mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-21 04:42:53 +08:00
42a4f53d2b
This commit applies all changes made after running the gdb/copyright.py script. Note that one file was flagged by the script, due to an invalid copyright header (gdb/unittests/basic_string_view/element_access/char/empty.cc). As the file was copied from GCC's libstdc++-v3 testsuite, this commit leaves this file untouched for the time being; a patch to fix the header was sent to gcc-patches first. gdb/ChangeLog: Update copyright year range in all GDB files.
200 lines
5.5 KiB
C
200 lines
5.5 KiB
C
/* Copyright (C) 2009-2019 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include JIT_READER_H /* Please see jit-reader.exp for an explanation. */
|
|
#include "jithost.h"
|
|
|
|
GDB_DECLARE_GPL_COMPATIBLE_READER;
|
|
|
|
enum register_mapping
|
|
{
|
|
AMD64_RA = 16,
|
|
AMD64_RBP = 6,
|
|
AMD64_RSP = 7,
|
|
};
|
|
|
|
struct reader_state
|
|
{
|
|
uintptr_t code_begin;
|
|
uintptr_t code_end;
|
|
};
|
|
|
|
static enum gdb_status
|
|
read_debug_info (struct gdb_reader_funcs *self,
|
|
struct gdb_symbol_callbacks *cbs,
|
|
void *memory, long memory_sz)
|
|
{
|
|
struct jithost_abi *symfile = memory;
|
|
struct gdb_object *object = cbs->object_open (cbs);
|
|
struct gdb_symtab *symtab = cbs->symtab_open (cbs, object, "");
|
|
GDB_CORE_ADDR begin = (GDB_CORE_ADDR) symfile->begin;
|
|
GDB_CORE_ADDR end = (GDB_CORE_ADDR) symfile->end;
|
|
struct reader_state *state = (struct reader_state *) self->priv_data;
|
|
|
|
/* Record the function's range, for the unwinder. */
|
|
state->code_begin = begin;
|
|
state->code_end = end;
|
|
|
|
cbs->block_open (cbs, symtab, NULL, begin, end, "jit_function_00");
|
|
|
|
cbs->symtab_close (cbs, symtab);
|
|
cbs->object_close (cbs, object);
|
|
return GDB_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
free_reg_value (struct gdb_reg_value *value)
|
|
{
|
|
free (value);
|
|
}
|
|
|
|
static void
|
|
write_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
|
|
uintptr_t value)
|
|
{
|
|
const int size = sizeof (uintptr_t);
|
|
struct gdb_reg_value *reg_val =
|
|
malloc (sizeof (struct gdb_reg_value) + size - 1);
|
|
reg_val->defined = 1;
|
|
reg_val->free = free_reg_value;
|
|
|
|
memcpy (reg_val->value, &value, size);
|
|
callbacks->reg_set (callbacks, dw_reg, reg_val);
|
|
}
|
|
|
|
static int
|
|
read_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
|
|
uintptr_t *value)
|
|
{
|
|
const int size = sizeof (uintptr_t);
|
|
struct gdb_reg_value *reg_val = callbacks->reg_get (callbacks, dw_reg);
|
|
if (reg_val->size != size || !reg_val->defined)
|
|
{
|
|
reg_val->free (reg_val);
|
|
return 0;
|
|
}
|
|
memcpy (value, reg_val->value, size);
|
|
reg_val->free (reg_val);
|
|
return 1;
|
|
}
|
|
|
|
/* Read the stack pointer into *VALUE. IP is the address the inferior
|
|
is currently stopped at. Takes care of demangling the stack
|
|
pointer if necessary. */
|
|
|
|
static int
|
|
read_sp (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs,
|
|
uintptr_t ip, uintptr_t *value)
|
|
{
|
|
struct reader_state *state = (struct reader_state *) self->priv_data;
|
|
uintptr_t sp;
|
|
|
|
if (!read_register (cbs, AMD64_RSP, &sp))
|
|
return GDB_FAIL;
|
|
|
|
/* If stopped at the instruction after the "xor $-1, %rsp", demangle
|
|
the stack pointer back. */
|
|
if (ip == state->code_begin + 5)
|
|
sp ^= (uintptr_t) -1;
|
|
|
|
*value = sp;
|
|
return GDB_SUCCESS;
|
|
}
|
|
|
|
static enum gdb_status
|
|
unwind_frame (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
|
|
{
|
|
const int word_size = sizeof (uintptr_t);
|
|
uintptr_t prev_sp, this_sp;
|
|
uintptr_t prev_ip, this_ip;
|
|
uintptr_t prev_bp, this_bp;
|
|
struct reader_state *state = (struct reader_state *) self->priv_data;
|
|
|
|
if (!read_register (cbs, AMD64_RA, &this_ip))
|
|
return GDB_FAIL;
|
|
|
|
if (this_ip >= state->code_end || this_ip < state->code_begin)
|
|
return GDB_FAIL;
|
|
|
|
/* Unwind RBP in order to make the unwinder that tries to unwind
|
|
from the just-unwound frame happy. */
|
|
if (!read_register (cbs, AMD64_RBP, &this_bp))
|
|
return GDB_FAIL;
|
|
/* RBP is unmodified. */
|
|
prev_bp = this_bp;
|
|
|
|
/* Fetch the demangled stack pointer. */
|
|
if (!read_sp (self, cbs, this_ip, &this_sp))
|
|
return GDB_FAIL;
|
|
|
|
/* The return address is saved on the stack. */
|
|
if (cbs->target_read (this_sp, &prev_ip, word_size) == GDB_FAIL)
|
|
return GDB_FAIL;
|
|
prev_sp = this_sp + word_size;
|
|
|
|
write_register (cbs, AMD64_RA, prev_ip);
|
|
write_register (cbs, AMD64_RSP, prev_sp);
|
|
write_register (cbs, AMD64_RBP, prev_bp);
|
|
return GDB_SUCCESS;
|
|
}
|
|
|
|
static struct gdb_frame_id
|
|
get_frame_id (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
|
|
{
|
|
struct reader_state *state = (struct reader_state *) self->priv_data;
|
|
struct gdb_frame_id frame_id;
|
|
uintptr_t ip;
|
|
uintptr_t sp;
|
|
|
|
read_register (cbs, AMD64_RA, &ip);
|
|
read_sp (self, cbs, ip, &sp);
|
|
|
|
frame_id.code_address = (GDB_CORE_ADDR) state->code_begin;
|
|
frame_id.stack_address = (GDB_CORE_ADDR) sp;
|
|
|
|
return frame_id;
|
|
}
|
|
|
|
static void
|
|
destroy_reader (struct gdb_reader_funcs *self)
|
|
{
|
|
free (self->priv_data);
|
|
free (self);
|
|
}
|
|
|
|
struct gdb_reader_funcs *
|
|
gdb_init_reader (void)
|
|
{
|
|
struct reader_state *state = calloc (1, sizeof (struct reader_state));
|
|
struct gdb_reader_funcs *reader_funcs =
|
|
malloc (sizeof (struct gdb_reader_funcs));
|
|
|
|
reader_funcs->reader_version = GDB_READER_INTERFACE_VERSION;
|
|
reader_funcs->priv_data = state;
|
|
reader_funcs->read = read_debug_info;
|
|
reader_funcs->unwind = unwind_frame;
|
|
reader_funcs->get_frame_id = get_frame_id;
|
|
reader_funcs->destroy = destroy_reader;
|
|
|
|
return reader_funcs;
|
|
}
|