mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
fc55e99ad7
This patch ensures that all ordinary help strings are wrapped at 80 columns. For the most part this consists of changing code like this (note the embedded \n and the trailing backslash without a newline): -Manage the space-separated list of debuginfod server URLs that GDB will query \ -when missing debuginfo, executables or source files.\nThe default value is \ -copied from the DEBUGINFOD_URLS environment variable."), ... to end each line with \n\, like: +Manage the space-separated list of debuginfod server URLs that GDB will\n\ +query when missing debuginfo, executables or source files.\n\ +The default value is copied from the DEBUGINFOD_URLS environment variable."), Approved-By: Eli Zaretskii <eliz@gnu.org>
4150 lines
116 KiB
C
4150 lines
116 KiB
C
/* DWARF 2 location expression support for GDB.
|
||
|
||
Copyright (C) 2003-2024 Free Software Foundation, Inc.
|
||
|
||
Contributed by Daniel Jacobowitz, MontaVista Software, 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 "event-top.h"
|
||
#include "exceptions.h"
|
||
#include "ui-out.h"
|
||
#include "value.h"
|
||
#include "frame.h"
|
||
#include "gdbcore.h"
|
||
#include "target.h"
|
||
#include "inferior.h"
|
||
#include "ax.h"
|
||
#include "ax-gdb.h"
|
||
#include "regcache.h"
|
||
#include "objfiles.h"
|
||
#include "block.h"
|
||
#include "cli/cli-cmds.h"
|
||
#include "complaints.h"
|
||
#include "dwarf2.h"
|
||
#include "dwarf2/expr.h"
|
||
#include "dwarf2/loc.h"
|
||
#include "dwarf2/read.h"
|
||
#include "dwarf2/frame.h"
|
||
#include "dwarf2/leb.h"
|
||
#include "compile/compile.h"
|
||
#include <algorithm>
|
||
#include <vector>
|
||
#include <unordered_set>
|
||
#include "gdbsupport/underlying.h"
|
||
#include "gdbsupport/byte-vector.h"
|
||
|
||
static struct value *dwarf2_evaluate_loc_desc_full
|
||
(struct type *type, const frame_info_ptr &frame, const gdb_byte *data,
|
||
size_t size, dwarf2_per_cu_data *per_cu, dwarf2_per_objfile *per_objfile,
|
||
struct type *subobj_type, LONGEST subobj_byte_offset, bool as_lval = true);
|
||
|
||
/* Until these have formal names, we define these here.
|
||
ref: http://gcc.gnu.org/wiki/DebugFission
|
||
Each entry in .debug_loc.dwo begins with a byte that describes the entry,
|
||
and is then followed by data specific to that entry. */
|
||
|
||
enum debug_loc_kind
|
||
{
|
||
/* Indicates the end of the list of entries. */
|
||
DEBUG_LOC_END_OF_LIST = 0,
|
||
|
||
/* This is followed by an unsigned LEB128 number that is an index into
|
||
.debug_addr and specifies the base address for all following entries. */
|
||
DEBUG_LOC_BASE_ADDRESS = 1,
|
||
|
||
/* This is followed by two unsigned LEB128 numbers that are indices into
|
||
.debug_addr and specify the beginning and ending addresses, and then
|
||
a normal location expression as in .debug_loc. */
|
||
DEBUG_LOC_START_END = 2,
|
||
|
||
/* This is followed by an unsigned LEB128 number that is an index into
|
||
.debug_addr and specifies the beginning address, and a 4 byte unsigned
|
||
number that specifies the length, and then a normal location expression
|
||
as in .debug_loc. */
|
||
DEBUG_LOC_START_LENGTH = 3,
|
||
|
||
/* This is followed by two unsigned LEB128 operands. The values of these
|
||
operands are the starting and ending offsets, respectively, relative to
|
||
the applicable base address. */
|
||
DEBUG_LOC_OFFSET_PAIR = 4,
|
||
|
||
/* An internal value indicating there is insufficient data. */
|
||
DEBUG_LOC_BUFFER_OVERFLOW = -1,
|
||
|
||
/* An internal value indicating an invalid kind of entry was found. */
|
||
DEBUG_LOC_INVALID_ENTRY = -2
|
||
};
|
||
|
||
/* Helper function which throws an error if a synthetic pointer is
|
||
invalid. */
|
||
|
||
void
|
||
invalid_synthetic_pointer (void)
|
||
{
|
||
error (_("access outside bounds of object "
|
||
"referenced via synthetic pointer"));
|
||
}
|
||
|
||
/* Decode the addresses in a non-dwo .debug_loc entry.
|
||
A pointer to the next byte to examine is returned in *NEW_PTR.
|
||
The encoded low,high addresses are return in *LOW,*HIGH.
|
||
The result indicates the kind of entry found. */
|
||
|
||
static enum debug_loc_kind
|
||
decode_debug_loc_addresses (const gdb_byte *loc_ptr, const gdb_byte *buf_end,
|
||
const gdb_byte **new_ptr,
|
||
unrelocated_addr *lowp, unrelocated_addr *highp,
|
||
enum bfd_endian byte_order,
|
||
unsigned int addr_size,
|
||
int signed_addr_p)
|
||
{
|
||
CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
|
||
|
||
if (buf_end - loc_ptr < 2 * addr_size)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
CORE_ADDR low, high;
|
||
if (signed_addr_p)
|
||
low = extract_signed_integer (loc_ptr, addr_size, byte_order);
|
||
else
|
||
low = extract_unsigned_integer (loc_ptr, addr_size, byte_order);
|
||
loc_ptr += addr_size;
|
||
|
||
if (signed_addr_p)
|
||
high = extract_signed_integer (loc_ptr, addr_size, byte_order);
|
||
else
|
||
high = extract_unsigned_integer (loc_ptr, addr_size, byte_order);
|
||
loc_ptr += addr_size;
|
||
|
||
*new_ptr = loc_ptr;
|
||
*lowp = (unrelocated_addr) low;
|
||
*highp = (unrelocated_addr) high;
|
||
|
||
/* A base-address-selection entry. */
|
||
if ((low & base_mask) == base_mask)
|
||
return DEBUG_LOC_BASE_ADDRESS;
|
||
|
||
/* An end-of-list entry. */
|
||
if (low == 0 && high == 0)
|
||
return DEBUG_LOC_END_OF_LIST;
|
||
|
||
/* We want the caller to apply the base address, so we must return
|
||
DEBUG_LOC_OFFSET_PAIR here. */
|
||
return DEBUG_LOC_OFFSET_PAIR;
|
||
}
|
||
|
||
/* Decode the addresses in .debug_loclists entry.
|
||
A pointer to the next byte to examine is returned in *NEW_PTR.
|
||
The encoded low,high addresses are return in *LOW,*HIGH.
|
||
The result indicates the kind of entry found. */
|
||
|
||
static enum debug_loc_kind
|
||
decode_debug_loclists_addresses (dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile,
|
||
const gdb_byte *loc_ptr,
|
||
const gdb_byte *buf_end,
|
||
const gdb_byte **new_ptr,
|
||
unrelocated_addr *low,
|
||
unrelocated_addr *high,
|
||
enum bfd_endian byte_order,
|
||
unsigned int addr_size,
|
||
int signed_addr_p)
|
||
{
|
||
uint64_t u64;
|
||
|
||
if (loc_ptr == buf_end)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
switch (*loc_ptr++)
|
||
{
|
||
case DW_LLE_base_addressx:
|
||
*low = {};
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &u64);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*high = dwarf2_read_addr_index (per_cu, per_objfile, u64);
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_BASE_ADDRESS;
|
||
|
||
case DW_LLE_startx_length:
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &u64);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*low = dwarf2_read_addr_index (per_cu, per_objfile, u64);
|
||
*high = *low;
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &u64);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*high = (unrelocated_addr) ((uint64_t) *high + u64);
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_START_LENGTH;
|
||
|
||
case DW_LLE_start_length:
|
||
if (buf_end - loc_ptr < addr_size)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
if (signed_addr_p)
|
||
*low = (unrelocated_addr) extract_signed_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
else
|
||
*low = (unrelocated_addr) extract_unsigned_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
|
||
loc_ptr += addr_size;
|
||
*high = *low;
|
||
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &u64);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*high = (unrelocated_addr) ((uint64_t) *high + u64);
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_START_LENGTH;
|
||
|
||
case DW_LLE_end_of_list:
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_END_OF_LIST;
|
||
|
||
case DW_LLE_base_address:
|
||
if (loc_ptr + addr_size > buf_end)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
if (signed_addr_p)
|
||
*high = (unrelocated_addr) extract_signed_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
else
|
||
*high = (unrelocated_addr) extract_unsigned_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
|
||
loc_ptr += addr_size;
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_BASE_ADDRESS;
|
||
|
||
case DW_LLE_offset_pair:
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &u64);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*low = (unrelocated_addr) u64;
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &u64);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*high = (unrelocated_addr) u64;
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_OFFSET_PAIR;
|
||
|
||
case DW_LLE_start_end:
|
||
if (loc_ptr + 2 * addr_size > buf_end)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
if (signed_addr_p)
|
||
*low = (unrelocated_addr) extract_signed_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
else
|
||
*low = (unrelocated_addr) extract_unsigned_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
|
||
loc_ptr += addr_size;
|
||
if (signed_addr_p)
|
||
*high = (unrelocated_addr) extract_signed_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
else
|
||
*high = (unrelocated_addr) extract_unsigned_integer (loc_ptr, addr_size,
|
||
byte_order);
|
||
|
||
loc_ptr += addr_size;
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_START_END;
|
||
|
||
/* Following cases are not supported yet. */
|
||
case DW_LLE_startx_endx:
|
||
case DW_LLE_default_location:
|
||
default:
|
||
return DEBUG_LOC_INVALID_ENTRY;
|
||
}
|
||
}
|
||
|
||
/* Decode the addresses in .debug_loc.dwo entry.
|
||
A pointer to the next byte to examine is returned in *NEW_PTR.
|
||
The encoded low,high addresses are return in *LOW,*HIGH.
|
||
The result indicates the kind of entry found. */
|
||
|
||
static enum debug_loc_kind
|
||
decode_debug_loc_dwo_addresses (dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile,
|
||
const gdb_byte *loc_ptr,
|
||
const gdb_byte *buf_end,
|
||
const gdb_byte **new_ptr,
|
||
unrelocated_addr *low,
|
||
unrelocated_addr *high,
|
||
enum bfd_endian byte_order)
|
||
{
|
||
uint64_t low_index, high_index;
|
||
|
||
if (loc_ptr == buf_end)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
switch (*loc_ptr++)
|
||
{
|
||
case DW_LLE_GNU_end_of_list_entry:
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_END_OF_LIST;
|
||
|
||
case DW_LLE_GNU_base_address_selection_entry:
|
||
*low = {};
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &high_index);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*high = dwarf2_read_addr_index (per_cu, per_objfile, high_index);
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_BASE_ADDRESS;
|
||
|
||
case DW_LLE_GNU_start_end_entry:
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &low_index);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*low = dwarf2_read_addr_index (per_cu, per_objfile, low_index);
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &high_index);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*high = dwarf2_read_addr_index (per_cu, per_objfile, high_index);
|
||
*new_ptr = loc_ptr;
|
||
return DEBUG_LOC_START_END;
|
||
|
||
case DW_LLE_GNU_start_length_entry:
|
||
loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &low_index);
|
||
if (loc_ptr == NULL)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*low = dwarf2_read_addr_index (per_cu, per_objfile, low_index);
|
||
if (loc_ptr + 4 > buf_end)
|
||
return DEBUG_LOC_BUFFER_OVERFLOW;
|
||
|
||
*high = *low;
|
||
*high = (unrelocated_addr) ((CORE_ADDR) *high
|
||
+ extract_unsigned_integer (loc_ptr, 4,
|
||
byte_order));
|
||
*new_ptr = loc_ptr + 4;
|
||
return DEBUG_LOC_START_LENGTH;
|
||
|
||
default:
|
||
return DEBUG_LOC_INVALID_ENTRY;
|
||
}
|
||
}
|
||
|
||
/* A function for dealing with location lists. Given a
|
||
symbol baton (BATON) and a pc value (PC), find the appropriate
|
||
location expression, set *LOCEXPR_LENGTH, and return a pointer
|
||
to the beginning of the expression. Returns NULL on failure.
|
||
|
||
For now, only return the first matching location expression; there
|
||
can be more than one in the list. */
|
||
|
||
const gdb_byte *
|
||
dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
|
||
size_t *locexpr_length, const CORE_ADDR pc,
|
||
bool at_entry)
|
||
{
|
||
dwarf2_per_objfile *per_objfile = baton->per_objfile;
|
||
struct objfile *objfile = per_objfile->objfile;
|
||
struct gdbarch *gdbarch = objfile->arch ();
|
||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||
unsigned int addr_size = baton->per_cu->addr_size ();
|
||
int signed_addr_p = bfd_get_sign_extend_vma (objfile->obfd.get ());
|
||
/* Adjustment for relocatable objects. */
|
||
CORE_ADDR text_offset = baton->per_objfile->objfile->text_section_offset ();
|
||
unrelocated_addr unrel_pc = (unrelocated_addr) (pc - text_offset);
|
||
unrelocated_addr base_address = baton->base_address;
|
||
const gdb_byte *loc_ptr, *buf_end;
|
||
|
||
loc_ptr = baton->data;
|
||
buf_end = baton->data + baton->size;
|
||
|
||
while (1)
|
||
{
|
||
unrelocated_addr low = {}, high = {}; /* init for gcc -Wall */
|
||
int length;
|
||
enum debug_loc_kind kind;
|
||
const gdb_byte *new_ptr = NULL; /* init for gcc -Wall */
|
||
|
||
if (baton->per_cu->version () < 5 && baton->from_dwo)
|
||
kind = decode_debug_loc_dwo_addresses (baton->per_cu,
|
||
baton->per_objfile,
|
||
loc_ptr, buf_end, &new_ptr,
|
||
&low, &high, byte_order);
|
||
else if (baton->per_cu->version () < 5)
|
||
kind = decode_debug_loc_addresses (loc_ptr, buf_end, &new_ptr,
|
||
&low, &high,
|
||
byte_order, addr_size,
|
||
signed_addr_p);
|
||
else
|
||
kind = decode_debug_loclists_addresses (baton->per_cu,
|
||
baton->per_objfile,
|
||
loc_ptr, buf_end, &new_ptr,
|
||
&low, &high, byte_order,
|
||
addr_size, signed_addr_p);
|
||
|
||
loc_ptr = new_ptr;
|
||
switch (kind)
|
||
{
|
||
case DEBUG_LOC_END_OF_LIST:
|
||
*locexpr_length = 0;
|
||
return NULL;
|
||
|
||
case DEBUG_LOC_BASE_ADDRESS:
|
||
base_address = high;
|
||
continue;
|
||
|
||
case DEBUG_LOC_START_END:
|
||
case DEBUG_LOC_START_LENGTH:
|
||
case DEBUG_LOC_OFFSET_PAIR:
|
||
break;
|
||
|
||
case DEBUG_LOC_BUFFER_OVERFLOW:
|
||
case DEBUG_LOC_INVALID_ENTRY:
|
||
error (_("dwarf2_find_location_expression: "
|
||
"Corrupted DWARF expression."));
|
||
|
||
default:
|
||
gdb_assert_not_reached ("bad debug_loc_kind");
|
||
}
|
||
|
||
/* Otherwise, a location expression entry.
|
||
If the entry is from a DWO, don't add base address: the entry is from
|
||
.debug_addr which already has the DWARF "base address". We still add
|
||
text offset in case we're debugging a PIE executable. However, if the
|
||
entry is DW_LLE_offset_pair from a DWO, add the base address as the
|
||
operands are offsets relative to the applicable base address.
|
||
If the entry is DW_LLE_start_end or DW_LLE_start_length, then
|
||
it already is an address, and we don't need to add the base. */
|
||
if (!baton->from_dwo && kind == DEBUG_LOC_OFFSET_PAIR)
|
||
{
|
||
low = (unrelocated_addr) ((CORE_ADDR) low + (CORE_ADDR) base_address);
|
||
high = (unrelocated_addr) ((CORE_ADDR) high + (CORE_ADDR) base_address);
|
||
}
|
||
|
||
if (baton->per_cu->version () < 5)
|
||
{
|
||
length = extract_unsigned_integer (loc_ptr, 2, byte_order);
|
||
loc_ptr += 2;
|
||
}
|
||
else
|
||
{
|
||
unsigned int bytes_read;
|
||
|
||
length = read_unsigned_leb128 (NULL, loc_ptr, &bytes_read);
|
||
loc_ptr += bytes_read;
|
||
}
|
||
|
||
if (low == high && unrel_pc == low && at_entry)
|
||
{
|
||
/* This is entry PC record present only at entry point
|
||
of a function. Verify it is really the function entry point. */
|
||
|
||
const struct block *pc_block = block_for_pc (pc);
|
||
struct symbol *pc_func = NULL;
|
||
|
||
if (pc_block)
|
||
pc_func = pc_block->linkage_function ();
|
||
|
||
if (pc_func && pc == pc_func->value_block ()->entry_pc ())
|
||
{
|
||
*locexpr_length = length;
|
||
return loc_ptr;
|
||
}
|
||
}
|
||
|
||
if (unrel_pc >= low && unrel_pc < high)
|
||
{
|
||
*locexpr_length = length;
|
||
return loc_ptr;
|
||
}
|
||
|
||
loc_ptr += length;
|
||
}
|
||
}
|
||
|
||
/* Implement find_frame_base_location method for LOC_BLOCK functions using
|
||
DWARF expression for its DW_AT_frame_base. */
|
||
|
||
static void
|
||
locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
|
||
const gdb_byte **start, size_t *length)
|
||
{
|
||
struct dwarf2_locexpr_baton *symbaton
|
||
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (framefunc);
|
||
|
||
*length = symbaton->size;
|
||
*start = symbaton->data;
|
||
}
|
||
|
||
/* Implement the struct symbol_block_ops::get_frame_base method for
|
||
LOC_BLOCK functions using a DWARF expression as its DW_AT_frame_base. */
|
||
|
||
static CORE_ADDR
|
||
locexpr_get_frame_base (struct symbol *framefunc, const frame_info_ptr &frame)
|
||
{
|
||
struct gdbarch *gdbarch;
|
||
struct type *type;
|
||
struct dwarf2_locexpr_baton *dlbaton;
|
||
const gdb_byte *start;
|
||
size_t length;
|
||
struct value *result;
|
||
|
||
/* If this method is called, then FRAMEFUNC is supposed to be a DWARF block.
|
||
Thus, it's supposed to provide the find_frame_base_location method as
|
||
well. */
|
||
gdb_assert (framefunc->block_ops ()->find_frame_base_location != nullptr);
|
||
|
||
gdbarch = get_frame_arch (frame);
|
||
type = builtin_type (gdbarch)->builtin_data_ptr;
|
||
dlbaton = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (framefunc);
|
||
|
||
framefunc->block_ops ()->find_frame_base_location (framefunc,
|
||
get_frame_pc (frame),
|
||
&start, &length);
|
||
result = dwarf2_evaluate_loc_desc (type, frame, start, length,
|
||
dlbaton->per_cu, dlbaton->per_objfile);
|
||
|
||
/* The DW_AT_frame_base attribute contains a location description which
|
||
computes the base address itself. However, the call to
|
||
dwarf2_evaluate_loc_desc returns a value representing a variable at
|
||
that address. The frame base address is thus this variable's
|
||
address. */
|
||
return result->address ();
|
||
}
|
||
|
||
/* Vector for inferior functions as represented by LOC_BLOCK, if the inferior
|
||
function uses DWARF expression for its DW_AT_frame_base. */
|
||
|
||
const struct symbol_block_ops dwarf2_block_frame_base_locexpr_funcs =
|
||
{
|
||
locexpr_find_frame_base_location,
|
||
locexpr_get_frame_base
|
||
};
|
||
|
||
/* Implement find_frame_base_location method for LOC_BLOCK functions using
|
||
DWARF location list for its DW_AT_frame_base. */
|
||
|
||
static void
|
||
loclist_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
|
||
const gdb_byte **start, size_t *length)
|
||
{
|
||
struct dwarf2_loclist_baton *symbaton
|
||
= (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (framefunc);
|
||
|
||
*start = dwarf2_find_location_expression (symbaton, length, pc);
|
||
}
|
||
|
||
/* Implement the struct symbol_block_ops::get_frame_base method for
|
||
LOC_BLOCK functions using a DWARF location list as its DW_AT_frame_base. */
|
||
|
||
static CORE_ADDR
|
||
loclist_get_frame_base (struct symbol *framefunc, const frame_info_ptr &frame)
|
||
{
|
||
struct gdbarch *gdbarch;
|
||
struct type *type;
|
||
struct dwarf2_loclist_baton *dlbaton;
|
||
const gdb_byte *start;
|
||
size_t length;
|
||
struct value *result;
|
||
|
||
/* If this method is called, then FRAMEFUNC is supposed to be a DWARF block.
|
||
Thus, it's supposed to provide the find_frame_base_location method as
|
||
well. */
|
||
gdb_assert (framefunc->block_ops ()->find_frame_base_location != nullptr);
|
||
|
||
gdbarch = get_frame_arch (frame);
|
||
type = builtin_type (gdbarch)->builtin_data_ptr;
|
||
dlbaton = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (framefunc);
|
||
|
||
framefunc->block_ops ()->find_frame_base_location (framefunc,
|
||
get_frame_pc (frame),
|
||
&start, &length);
|
||
result = dwarf2_evaluate_loc_desc (type, frame, start, length,
|
||
dlbaton->per_cu, dlbaton->per_objfile);
|
||
|
||
/* The DW_AT_frame_base attribute contains a location description which
|
||
computes the base address itself. However, the call to
|
||
dwarf2_evaluate_loc_desc returns a value representing a variable at
|
||
that address. The frame base address is thus this variable's
|
||
address. */
|
||
return result->address ();
|
||
}
|
||
|
||
/* Vector for inferior functions as represented by LOC_BLOCK, if the inferior
|
||
function uses DWARF location list for its DW_AT_frame_base. */
|
||
|
||
const struct symbol_block_ops dwarf2_block_frame_base_loclist_funcs =
|
||
{
|
||
loclist_find_frame_base_location,
|
||
loclist_get_frame_base
|
||
};
|
||
|
||
/* See dwarf2/loc.h. */
|
||
|
||
void
|
||
func_get_frame_base_dwarf_block (struct symbol *framefunc, CORE_ADDR pc,
|
||
const gdb_byte **start, size_t *length)
|
||
{
|
||
if (const symbol_block_ops *block_ops = framefunc->block_ops ();
|
||
block_ops != nullptr)
|
||
block_ops->find_frame_base_location (framefunc, pc, start, length);
|
||
else
|
||
*length = 0;
|
||
|
||
if (*length == 0)
|
||
error (_("Could not find the frame base for \"%s\"."),
|
||
framefunc->natural_name ());
|
||
}
|
||
|
||
/* See loc.h. */
|
||
|
||
value *
|
||
compute_var_value (const char *name)
|
||
{
|
||
struct block_symbol sym = lookup_symbol (name, nullptr, SEARCH_VAR_DOMAIN,
|
||
nullptr);
|
||
if (sym.symbol != nullptr)
|
||
return value_of_variable (sym.symbol, sym.block);
|
||
return nullptr;
|
||
}
|
||
|
||
/* See dwarf2/loc.h. */
|
||
|
||
unsigned int entry_values_debug = 0;
|
||
|
||
/* Helper to set entry_values_debug. */
|
||
|
||
static void
|
||
show_entry_values_debug (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
gdb_printf (file,
|
||
_("Entry values and tail call frames debugging is %s.\n"),
|
||
value);
|
||
}
|
||
|
||
/* See gdbtypes.h. */
|
||
|
||
void
|
||
call_site_target::iterate_over_addresses (gdbarch *call_site_gdbarch,
|
||
const call_site *call_site,
|
||
const frame_info_ptr &caller_frame,
|
||
iterate_ftype callback) const
|
||
{
|
||
switch (m_loc_kind)
|
||
{
|
||
case call_site_target::DWARF_BLOCK:
|
||
{
|
||
struct dwarf2_locexpr_baton *dwarf_block;
|
||
struct value *val;
|
||
struct type *caller_core_addr_type;
|
||
struct gdbarch *caller_arch;
|
||
|
||
dwarf_block = m_loc.dwarf_block;
|
||
if (dwarf_block == NULL)
|
||
{
|
||
bound_minimal_symbol msym
|
||
= lookup_minimal_symbol_by_pc (call_site->pc () - 1);
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("DW_AT_call_target is not specified at %s in %s"),
|
||
paddress (call_site_gdbarch, call_site->pc ()),
|
||
(msym.minsym == NULL ? "???"
|
||
: msym.minsym->print_name ()));
|
||
|
||
}
|
||
if (caller_frame == NULL)
|
||
{
|
||
bound_minimal_symbol msym
|
||
= lookup_minimal_symbol_by_pc (call_site->pc () - 1);
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("DW_AT_call_target DWARF block resolving "
|
||
"requires known frame which is currently not "
|
||
"available at %s in %s"),
|
||
paddress (call_site_gdbarch, call_site->pc ()),
|
||
(msym.minsym == NULL ? "???"
|
||
: msym.minsym->print_name ()));
|
||
|
||
}
|
||
caller_arch = get_frame_arch (caller_frame);
|
||
caller_core_addr_type = builtin_type (caller_arch)->builtin_func_ptr;
|
||
val = dwarf2_evaluate_loc_desc (caller_core_addr_type, caller_frame,
|
||
dwarf_block->data, dwarf_block->size,
|
||
dwarf_block->per_cu,
|
||
dwarf_block->per_objfile);
|
||
/* DW_AT_call_target is a DWARF expression, not a DWARF location. */
|
||
if (val->lval () == lval_memory)
|
||
callback (val->address ());
|
||
else
|
||
callback (value_as_address (val));
|
||
}
|
||
break;
|
||
|
||
case call_site_target::PHYSNAME:
|
||
{
|
||
const char *physname;
|
||
|
||
physname = m_loc.physname;
|
||
|
||
/* Handle both the mangled and demangled PHYSNAME. */
|
||
bound_minimal_symbol msym
|
||
= lookup_minimal_symbol (current_program_space, physname);
|
||
if (msym.minsym == NULL)
|
||
{
|
||
msym = lookup_minimal_symbol_by_pc (call_site->pc () - 1);
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("Cannot find function \"%s\" for a call site target "
|
||
"at %s in %s"),
|
||
physname, paddress (call_site_gdbarch, call_site->pc ()),
|
||
(msym.minsym == NULL ? "???"
|
||
: msym.minsym->print_name ()));
|
||
|
||
}
|
||
|
||
CORE_ADDR addr = (gdbarch_convert_from_func_ptr_addr
|
||
(call_site_gdbarch, msym.value_address (),
|
||
current_inferior ()->top_target ()));
|
||
callback (addr);
|
||
}
|
||
break;
|
||
|
||
case call_site_target::PHYSADDR:
|
||
{
|
||
dwarf2_per_objfile *per_objfile = call_site->per_objfile;
|
||
|
||
callback (per_objfile->relocate (m_loc.physaddr));
|
||
}
|
||
break;
|
||
|
||
case call_site_target::ADDRESSES:
|
||
{
|
||
dwarf2_per_objfile *per_objfile = call_site->per_objfile;
|
||
|
||
for (unsigned i = 0; i < m_loc.addresses.length; ++i)
|
||
callback (per_objfile->relocate (m_loc.addresses.values[i]));
|
||
}
|
||
break;
|
||
|
||
default:
|
||
internal_error (_("invalid call site target kind"));
|
||
}
|
||
}
|
||
|
||
/* Convert function entry point exact address ADDR to the function which is
|
||
compliant with TAIL_CALL_LIST_COMPLETE condition. Throw
|
||
NO_ENTRY_VALUE_ERROR otherwise. */
|
||
|
||
static struct symbol *
|
||
func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
|
||
{
|
||
struct symbol *sym = find_pc_function (addr);
|
||
struct type *type;
|
||
|
||
if (sym == NULL || sym->value_block ()->entry_pc () != addr)
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("DW_TAG_call_site resolving failed to find function "
|
||
"name for address %s"),
|
||
paddress (gdbarch, addr));
|
||
|
||
type = sym->type ();
|
||
gdb_assert (type->code () == TYPE_CODE_FUNC);
|
||
gdb_assert (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FUNC);
|
||
|
||
return sym;
|
||
}
|
||
|
||
/* Verify function with entry point exact address ADDR can never call itself
|
||
via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it
|
||
can call itself via tail calls.
|
||
|
||
If a function can tail call itself its entry value based parameters are
|
||
unreliable. There is no verification whether the value of some/all
|
||
parameters is unchanged through the self tail call, we expect if there is
|
||
a self tail call all the parameters can be modified. */
|
||
|
||
static void
|
||
func_verify_no_selftailcall (struct gdbarch *gdbarch, CORE_ADDR verify_addr)
|
||
{
|
||
CORE_ADDR addr;
|
||
|
||
/* The verification is completely unordered. Track here function addresses
|
||
which still need to be iterated. */
|
||
std::vector<CORE_ADDR> todo;
|
||
|
||
/* Track here CORE_ADDRs which were already visited. */
|
||
std::unordered_set<CORE_ADDR> addr_hash;
|
||
|
||
todo.push_back (verify_addr);
|
||
while (!todo.empty ())
|
||
{
|
||
struct symbol *func_sym;
|
||
struct call_site *call_site;
|
||
|
||
addr = todo.back ();
|
||
todo.pop_back ();
|
||
|
||
func_sym = func_addr_to_tail_call_list (gdbarch, addr);
|
||
|
||
for (call_site = TYPE_TAIL_CALL_LIST (func_sym->type ());
|
||
call_site; call_site = call_site->tail_call_next)
|
||
{
|
||
/* CALLER_FRAME with registers is not available for tail-call jumped
|
||
frames. */
|
||
call_site->iterate_over_addresses (gdbarch, nullptr,
|
||
[&] (CORE_ADDR target_addr)
|
||
{
|
||
if (target_addr == verify_addr)
|
||
{
|
||
bound_minimal_symbol msym
|
||
= lookup_minimal_symbol_by_pc (verify_addr);
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("DW_OP_entry_value resolving has found "
|
||
"function \"%s\" at %s can call itself via tail "
|
||
"calls"),
|
||
(msym.minsym == NULL ? "???"
|
||
: msym.minsym->print_name ()),
|
||
paddress (gdbarch, verify_addr));
|
||
}
|
||
|
||
if (addr_hash.insert (target_addr).second)
|
||
todo.push_back (target_addr);
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Print user readable form of CALL_SITE->PC to gdb_stdlog. Used only for
|
||
ENTRY_VALUES_DEBUG. */
|
||
|
||
static void
|
||
tailcall_dump (struct gdbarch *gdbarch, const struct call_site *call_site)
|
||
{
|
||
CORE_ADDR addr = call_site->pc ();
|
||
bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (addr - 1);
|
||
|
||
gdb_printf (gdb_stdlog, " %s(%s)", paddress (gdbarch, addr),
|
||
(msym.minsym == NULL ? "???"
|
||
: msym.minsym->print_name ()));
|
||
|
||
}
|
||
|
||
/* Intersect RESULTP with CHAIN to keep RESULTP unambiguous, keep in RESULTP
|
||
only top callers and bottom callees which are present in both. GDBARCH is
|
||
used only for ENTRY_VALUES_DEBUG. RESULTP is NULL after return if there are
|
||
no remaining possibilities to provide unambiguous non-trivial result.
|
||
RESULTP should point to NULL on the first (initialization) call. Caller is
|
||
responsible for xfree of any RESULTP data. */
|
||
|
||
static void
|
||
chain_candidate (struct gdbarch *gdbarch,
|
||
gdb::unique_xmalloc_ptr<struct call_site_chain> *resultp,
|
||
const std::vector<struct call_site *> &chain)
|
||
{
|
||
long length = chain.size ();
|
||
int callers, callees, idx;
|
||
|
||
if (*resultp == NULL)
|
||
{
|
||
/* Create the initial chain containing all the passed PCs. */
|
||
|
||
struct call_site_chain *result
|
||
= ((struct call_site_chain *)
|
||
xmalloc (sizeof (*result)
|
||
+ sizeof (*result->call_site) * (length - 1)));
|
||
result->length = length;
|
||
result->callers = result->callees = length;
|
||
if (!chain.empty ())
|
||
memcpy (result->call_site, chain.data (),
|
||
sizeof (*result->call_site) * length);
|
||
resultp->reset (result);
|
||
|
||
if (entry_values_debug)
|
||
{
|
||
gdb_printf (gdb_stdlog, "tailcall: initial:");
|
||
for (idx = 0; idx < length; idx++)
|
||
tailcall_dump (gdbarch, result->call_site[idx]);
|
||
gdb_putc ('\n', gdb_stdlog);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
if (entry_values_debug)
|
||
{
|
||
gdb_printf (gdb_stdlog, "tailcall: compare:");
|
||
for (idx = 0; idx < length; idx++)
|
||
tailcall_dump (gdbarch, chain[idx]);
|
||
gdb_putc ('\n', gdb_stdlog);
|
||
}
|
||
|
||
/* Intersect callers. */
|
||
|
||
callers = std::min ((long) (*resultp)->callers, length);
|
||
for (idx = 0; idx < callers; idx++)
|
||
if ((*resultp)->call_site[idx] != chain[idx])
|
||
{
|
||
(*resultp)->callers = idx;
|
||
break;
|
||
}
|
||
|
||
/* Intersect callees. */
|
||
|
||
callees = std::min ((long) (*resultp)->callees, length);
|
||
for (idx = 0; idx < callees; idx++)
|
||
if ((*resultp)->call_site[(*resultp)->length - 1 - idx]
|
||
!= chain[length - 1 - idx])
|
||
{
|
||
(*resultp)->callees = idx;
|
||
break;
|
||
}
|
||
|
||
if (entry_values_debug)
|
||
{
|
||
gdb_printf (gdb_stdlog, "tailcall: reduced:");
|
||
for (idx = 0; idx < (*resultp)->callers; idx++)
|
||
tailcall_dump (gdbarch, (*resultp)->call_site[idx]);
|
||
gdb_puts (" |", gdb_stdlog);
|
||
for (idx = 0; idx < (*resultp)->callees; idx++)
|
||
tailcall_dump (gdbarch,
|
||
(*resultp)->call_site[(*resultp)->length
|
||
- (*resultp)->callees + idx]);
|
||
gdb_putc ('\n', gdb_stdlog);
|
||
}
|
||
|
||
if ((*resultp)->callers == 0 && (*resultp)->callees == 0)
|
||
{
|
||
/* There are no common callers or callees. It could be also a direct
|
||
call (which has length 0) with ambiguous possibility of an indirect
|
||
call - CALLERS == CALLEES == 0 is valid during the first allocation
|
||
but any subsequence processing of such entry means ambiguity. */
|
||
resultp->reset (NULL);
|
||
return;
|
||
}
|
||
|
||
/* See call_site_find_chain_1 why there is no way to reach the bottom callee
|
||
PC again. In such case there must be two different code paths to reach
|
||
it. CALLERS + CALLEES equal to LENGTH in the case of self tail-call. */
|
||
gdb_assert ((*resultp)->callers + (*resultp)->callees <= (*resultp)->length);
|
||
}
|
||
|
||
/* Recursively try to construct the call chain. GDBARCH, RESULTP, and
|
||
CHAIN are passed to chain_candidate. ADDR_HASH tracks which
|
||
addresses have already been seen along the current chain.
|
||
CALL_SITE is the call site to visit, and CALLEE_PC is the PC we're
|
||
trying to "reach". Returns false if an error has already been
|
||
detected and so an early return can be done. If it makes sense to
|
||
keep trying (even if no answer has yet been found), returns
|
||
true. */
|
||
|
||
static bool
|
||
call_site_find_chain_2
|
||
(struct gdbarch *gdbarch,
|
||
gdb::unique_xmalloc_ptr<struct call_site_chain> *resultp,
|
||
std::vector<struct call_site *> &chain,
|
||
std::unordered_set<CORE_ADDR> &addr_hash,
|
||
struct call_site *call_site,
|
||
CORE_ADDR callee_pc)
|
||
{
|
||
std::vector<CORE_ADDR> addresses;
|
||
bool found_exact = false;
|
||
call_site->iterate_over_addresses (gdbarch, nullptr,
|
||
[&] (CORE_ADDR addr)
|
||
{
|
||
if (addr == callee_pc)
|
||
found_exact = true;
|
||
else
|
||
addresses.push_back (addr);
|
||
});
|
||
|
||
if (found_exact)
|
||
{
|
||
chain_candidate (gdbarch, resultp, chain);
|
||
/* If RESULTP was reset, then chain_candidate failed, and so we
|
||
can tell our callers to early-return. */
|
||
return *resultp != nullptr;
|
||
}
|
||
|
||
for (CORE_ADDR target_func_addr : addresses)
|
||
{
|
||
struct symbol *target_func
|
||
= func_addr_to_tail_call_list (gdbarch, target_func_addr);
|
||
for (struct call_site *target_call_site
|
||
= TYPE_TAIL_CALL_LIST (target_func->type ());
|
||
target_call_site != nullptr;
|
||
target_call_site = target_call_site->tail_call_next)
|
||
{
|
||
if (addr_hash.insert (target_call_site->pc ()).second)
|
||
{
|
||
/* Successfully entered TARGET_CALL_SITE. */
|
||
chain.push_back (target_call_site);
|
||
|
||
if (!call_site_find_chain_2 (gdbarch, resultp, chain,
|
||
addr_hash, target_call_site,
|
||
callee_pc))
|
||
return false;
|
||
|
||
size_t removed = addr_hash.erase (target_call_site->pc ());
|
||
gdb_assert (removed == 1);
|
||
chain.pop_back ();
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/* Create and return call_site_chain for CALLER_PC and CALLEE_PC. All
|
||
the assumed frames between them use GDBARCH. Any unreliability
|
||
results in thrown NO_ENTRY_VALUE_ERROR. */
|
||
|
||
static gdb::unique_xmalloc_ptr<call_site_chain>
|
||
call_site_find_chain_1 (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
|
||
CORE_ADDR callee_pc)
|
||
{
|
||
CORE_ADDR save_callee_pc = callee_pc;
|
||
gdb::unique_xmalloc_ptr<struct call_site_chain> retval;
|
||
struct call_site *call_site;
|
||
|
||
/* CHAIN contains only the intermediate CALL_SITEs. Neither CALLER_PC's
|
||
call_site nor any possible call_site at CALLEE_PC's function is there.
|
||
Any CALL_SITE in CHAIN will be iterated to its siblings - via
|
||
TAIL_CALL_NEXT. This is inappropriate for CALLER_PC's call_site. */
|
||
std::vector<struct call_site *> chain;
|
||
|
||
/* A given call site may have multiple associated addresses. This
|
||
can happen if, e.g., the caller is split by hot/cold
|
||
partitioning. This vector tracks the ones we haven't visited
|
||
yet. */
|
||
std::vector<std::vector<CORE_ADDR>> unvisited_addresses;
|
||
|
||
/* We are not interested in the specific PC inside the callee function. */
|
||
callee_pc = get_pc_function_start (callee_pc);
|
||
if (callee_pc == 0)
|
||
throw_error (NO_ENTRY_VALUE_ERROR, _("Unable to find function for PC %s"),
|
||
paddress (gdbarch, save_callee_pc));
|
||
|
||
/* Mark CALL_SITEs so we do not visit the same ones twice. */
|
||
std::unordered_set<CORE_ADDR> addr_hash;
|
||
|
||
/* Do not push CALL_SITE to CHAIN. Push there only the first tail call site
|
||
at the target's function. All the possible tail call sites in the
|
||
target's function will get iterated as already pushed into CHAIN via their
|
||
TAIL_CALL_NEXT. */
|
||
call_site = call_site_for_pc (gdbarch, caller_pc);
|
||
/* No need to check the return value here, because we no longer care
|
||
about possible early returns. */
|
||
call_site_find_chain_2 (gdbarch, &retval, chain, addr_hash, call_site,
|
||
callee_pc);
|
||
|
||
if (retval == NULL)
|
||
{
|
||
bound_minimal_symbol msym_caller
|
||
= lookup_minimal_symbol_by_pc (caller_pc);
|
||
bound_minimal_symbol msym_callee
|
||
= lookup_minimal_symbol_by_pc (callee_pc);
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("There are no unambiguously determinable intermediate "
|
||
"callers or callees between caller function \"%s\" at %s "
|
||
"and callee function \"%s\" at %s"),
|
||
(msym_caller.minsym == NULL
|
||
? "???" : msym_caller.minsym->print_name ()),
|
||
paddress (gdbarch, caller_pc),
|
||
(msym_callee.minsym == NULL
|
||
? "???" : msym_callee.minsym->print_name ()),
|
||
paddress (gdbarch, callee_pc));
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* Create and return call_site_chain for CALLER_PC and CALLEE_PC. All the
|
||
assumed frames between them use GDBARCH. If valid call_site_chain cannot be
|
||
constructed return NULL. */
|
||
|
||
gdb::unique_xmalloc_ptr<call_site_chain>
|
||
call_site_find_chain (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
|
||
CORE_ADDR callee_pc)
|
||
{
|
||
gdb::unique_xmalloc_ptr<call_site_chain> retval;
|
||
|
||
try
|
||
{
|
||
retval = call_site_find_chain_1 (gdbarch, caller_pc, callee_pc);
|
||
}
|
||
catch (const gdb_exception_error &e)
|
||
{
|
||
if (e.error == NO_ENTRY_VALUE_ERROR)
|
||
{
|
||
if (entry_values_debug)
|
||
exception_print (gdb_stdout, e);
|
||
|
||
return NULL;
|
||
}
|
||
else
|
||
throw;
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* Return 1 if KIND and KIND_U match PARAMETER. Return 0 otherwise. */
|
||
|
||
static int
|
||
call_site_parameter_matches (struct call_site_parameter *parameter,
|
||
enum call_site_parameter_kind kind,
|
||
union call_site_parameter_u kind_u)
|
||
{
|
||
if (kind == parameter->kind)
|
||
switch (kind)
|
||
{
|
||
case CALL_SITE_PARAMETER_DWARF_REG:
|
||
return kind_u.dwarf_reg == parameter->u.dwarf_reg;
|
||
|
||
case CALL_SITE_PARAMETER_FB_OFFSET:
|
||
return kind_u.fb_offset == parameter->u.fb_offset;
|
||
|
||
case CALL_SITE_PARAMETER_PARAM_OFFSET:
|
||
return kind_u.param_cu_off == parameter->u.param_cu_off;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* See loc.h. */
|
||
|
||
struct call_site_parameter *
|
||
dwarf_expr_reg_to_entry_parameter (const frame_info_ptr &initial_frame,
|
||
call_site_parameter_kind kind,
|
||
call_site_parameter_u kind_u,
|
||
dwarf2_per_cu_data **per_cu_return,
|
||
dwarf2_per_objfile **per_objfile_return)
|
||
{
|
||
CORE_ADDR func_addr, caller_pc;
|
||
struct gdbarch *gdbarch;
|
||
frame_info_ptr caller_frame;
|
||
struct call_site *call_site;
|
||
int iparams;
|
||
/* Initialize it just to avoid a GCC false warning. */
|
||
struct call_site_parameter *parameter = NULL;
|
||
CORE_ADDR target_addr;
|
||
frame_info_ptr frame = initial_frame;
|
||
|
||
while (get_frame_type (frame) == INLINE_FRAME)
|
||
{
|
||
frame = get_prev_frame_always (frame);
|
||
gdb_assert (frame != NULL);
|
||
}
|
||
|
||
func_addr = get_frame_func (frame);
|
||
gdbarch = get_frame_arch (frame);
|
||
caller_frame = get_prev_frame (frame);
|
||
if (gdbarch != frame_unwind_arch (frame))
|
||
{
|
||
bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (func_addr);
|
||
struct gdbarch *caller_gdbarch = frame_unwind_arch (frame);
|
||
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("DW_OP_entry_value resolving callee gdbarch %s "
|
||
"(of %s (%s)) does not match caller gdbarch %s"),
|
||
gdbarch_bfd_arch_info (gdbarch)->printable_name,
|
||
paddress (gdbarch, func_addr),
|
||
(msym.minsym == NULL ? "???"
|
||
: msym.minsym->print_name ()),
|
||
gdbarch_bfd_arch_info (caller_gdbarch)->printable_name);
|
||
}
|
||
|
||
if (caller_frame == NULL)
|
||
{
|
||
bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (func_addr);
|
||
|
||
throw_error (NO_ENTRY_VALUE_ERROR, _("DW_OP_entry_value resolving "
|
||
"requires caller of %s (%s)"),
|
||
paddress (gdbarch, func_addr),
|
||
(msym.minsym == NULL ? "???"
|
||
: msym.minsym->print_name ()));
|
||
}
|
||
caller_pc = get_frame_pc (caller_frame);
|
||
call_site = call_site_for_pc (gdbarch, caller_pc);
|
||
|
||
bool found = false;
|
||
unsigned count = 0;
|
||
call_site->iterate_over_addresses (gdbarch, caller_frame,
|
||
[&] (CORE_ADDR addr)
|
||
{
|
||
/* Preserve any address. */
|
||
target_addr = addr;
|
||
++count;
|
||
if (addr == func_addr)
|
||
found = true;
|
||
});
|
||
if (!found)
|
||
{
|
||
struct minimal_symbol *target_msym, *func_msym;
|
||
|
||
target_msym = lookup_minimal_symbol_by_pc (target_addr).minsym;
|
||
func_msym = lookup_minimal_symbol_by_pc (func_addr).minsym;
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("DW_OP_entry_value resolving expects callee %s at %s %s"
|
||
"but the called frame is for %s at %s"),
|
||
(target_msym == NULL ? "???"
|
||
: target_msym->print_name ()),
|
||
paddress (gdbarch, target_addr),
|
||
(count > 0
|
||
? _("(but note there are multiple addresses not listed)")
|
||
: ""),
|
||
func_msym == NULL ? "???" : func_msym->print_name (),
|
||
paddress (gdbarch, func_addr));
|
||
}
|
||
|
||
/* No entry value based parameters would be reliable if this function can
|
||
call itself via tail calls. */
|
||
func_verify_no_selftailcall (gdbarch, func_addr);
|
||
|
||
for (iparams = 0; iparams < call_site->parameter_count; iparams++)
|
||
{
|
||
parameter = &call_site->parameter[iparams];
|
||
if (call_site_parameter_matches (parameter, kind, kind_u))
|
||
break;
|
||
}
|
||
if (iparams == call_site->parameter_count)
|
||
{
|
||
struct minimal_symbol *msym
|
||
= lookup_minimal_symbol_by_pc (caller_pc).minsym;
|
||
|
||
/* DW_TAG_call_site_parameter will be missing just if GCC could not
|
||
determine its value. */
|
||
throw_error (NO_ENTRY_VALUE_ERROR, _("Cannot find matching parameter "
|
||
"at DW_TAG_call_site %s at %s"),
|
||
paddress (gdbarch, caller_pc),
|
||
msym == NULL ? "???" : msym->print_name ());
|
||
}
|
||
|
||
*per_cu_return = call_site->per_cu;
|
||
*per_objfile_return = call_site->per_objfile;
|
||
return parameter;
|
||
}
|
||
|
||
/* Return value for PARAMETER matching DEREF_SIZE. If DEREF_SIZE is -1, return
|
||
the normal DW_AT_call_value block. Otherwise return the
|
||
DW_AT_call_data_value (dereferenced) block.
|
||
|
||
TYPE and CALLER_FRAME specify how to evaluate the DWARF block into returned
|
||
struct value.
|
||
|
||
Function always returns non-NULL, non-optimized out value. It throws
|
||
NO_ENTRY_VALUE_ERROR if it cannot resolve the value for any reason. */
|
||
|
||
static struct value *
|
||
dwarf_entry_parameter_to_value (struct call_site_parameter *parameter,
|
||
CORE_ADDR deref_size, struct type *type,
|
||
const frame_info_ptr &caller_frame,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile)
|
||
{
|
||
const gdb_byte *data_src;
|
||
size_t size;
|
||
|
||
data_src = deref_size == -1 ? parameter->value : parameter->data_value;
|
||
size = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
|
||
|
||
/* DEREF_SIZE size is not verified here. */
|
||
if (data_src == NULL)
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("Cannot resolve DW_AT_call_data_value"));
|
||
|
||
return dwarf2_evaluate_loc_desc (type, caller_frame, data_src, size, per_cu,
|
||
per_objfile, false);
|
||
}
|
||
|
||
/* VALUE must be of type lval_computed with entry_data_value_funcs. Perform
|
||
the indirect method on it, that is use its stored target value, the sole
|
||
purpose of entry_data_value_funcs.. */
|
||
|
||
static struct value *
|
||
entry_data_value_coerce_ref (const struct value *value)
|
||
{
|
||
struct type *checked_type = check_typedef (value->type ());
|
||
struct value *target_val;
|
||
|
||
if (!TYPE_IS_REFERENCE (checked_type))
|
||
return NULL;
|
||
|
||
target_val = (struct value *) value->computed_closure ();
|
||
target_val->incref ();
|
||
return target_val;
|
||
}
|
||
|
||
/* Implement copy_closure. */
|
||
|
||
static void *
|
||
entry_data_value_copy_closure (const struct value *v)
|
||
{
|
||
struct value *target_val = (struct value *) v->computed_closure ();
|
||
|
||
target_val->incref ();
|
||
return target_val;
|
||
}
|
||
|
||
/* Implement free_closure. */
|
||
|
||
static void
|
||
entry_data_value_free_closure (struct value *v)
|
||
{
|
||
struct value *target_val = (struct value *) v->computed_closure ();
|
||
|
||
target_val->decref ();
|
||
}
|
||
|
||
/* Vector for methods for an entry value reference where the referenced value
|
||
is stored in the caller. On the first dereference use
|
||
DW_AT_call_data_value in the caller. */
|
||
|
||
static const struct lval_funcs entry_data_value_funcs =
|
||
{
|
||
NULL, /* read */
|
||
NULL, /* write */
|
||
nullptr,
|
||
NULL, /* indirect */
|
||
entry_data_value_coerce_ref,
|
||
NULL, /* check_synthetic_pointer */
|
||
entry_data_value_copy_closure,
|
||
entry_data_value_free_closure
|
||
};
|
||
|
||
/* See dwarf2/loc.h. */
|
||
struct value *
|
||
value_of_dwarf_reg_entry (struct type *type, const frame_info_ptr &frame,
|
||
enum call_site_parameter_kind kind,
|
||
union call_site_parameter_u kind_u)
|
||
{
|
||
struct type *checked_type = check_typedef (type);
|
||
struct type *target_type = checked_type->target_type ();
|
||
frame_info_ptr caller_frame = get_prev_frame (frame);
|
||
struct value *outer_val, *target_val, *val;
|
||
struct call_site_parameter *parameter;
|
||
dwarf2_per_cu_data *caller_per_cu;
|
||
dwarf2_per_objfile *caller_per_objfile;
|
||
|
||
parameter = dwarf_expr_reg_to_entry_parameter (frame, kind, kind_u,
|
||
&caller_per_cu,
|
||
&caller_per_objfile);
|
||
|
||
outer_val = dwarf_entry_parameter_to_value (parameter, -1 /* deref_size */,
|
||
type, caller_frame,
|
||
caller_per_cu,
|
||
caller_per_objfile);
|
||
|
||
/* Check if DW_AT_call_data_value cannot be used. If it should be
|
||
used and it is not available do not fall back to OUTER_VAL - dereferencing
|
||
TYPE_CODE_REF with non-entry data value would give current value - not the
|
||
entry value. */
|
||
|
||
if (!TYPE_IS_REFERENCE (checked_type)
|
||
|| checked_type->target_type () == NULL)
|
||
return outer_val;
|
||
|
||
target_val = dwarf_entry_parameter_to_value (parameter,
|
||
target_type->length (),
|
||
target_type, caller_frame,
|
||
caller_per_cu,
|
||
caller_per_objfile);
|
||
|
||
val = value::allocate_computed (type, &entry_data_value_funcs,
|
||
release_value (target_val).release ());
|
||
|
||
/* Copy the referencing pointer to the new computed value. */
|
||
memcpy (val->contents_raw ().data (),
|
||
outer_val->contents_raw ().data (),
|
||
checked_type->length ());
|
||
val->set_lazy (false);
|
||
|
||
return val;
|
||
}
|
||
|
||
/* Read parameter of TYPE at (callee) FRAME's function entry. DATA and
|
||
SIZE are DWARF block used to match DW_AT_location at the caller's
|
||
DW_TAG_call_site_parameter.
|
||
|
||
Function always returns non-NULL value. It throws NO_ENTRY_VALUE_ERROR if it
|
||
cannot resolve the parameter for any reason. */
|
||
|
||
static struct value *
|
||
value_of_dwarf_block_entry (struct type *type, const frame_info_ptr &frame,
|
||
const gdb_byte *block, size_t block_len)
|
||
{
|
||
union call_site_parameter_u kind_u;
|
||
|
||
kind_u.dwarf_reg = dwarf_block_to_dwarf_reg (block, block + block_len);
|
||
if (kind_u.dwarf_reg != -1)
|
||
return value_of_dwarf_reg_entry (type, frame, CALL_SITE_PARAMETER_DWARF_REG,
|
||
kind_u);
|
||
|
||
if (dwarf_block_to_fb_offset (block, block + block_len, &kind_u.fb_offset))
|
||
return value_of_dwarf_reg_entry (type, frame, CALL_SITE_PARAMETER_FB_OFFSET,
|
||
kind_u);
|
||
|
||
/* This can normally happen - throw NO_ENTRY_VALUE_ERROR to get the message
|
||
suppressed during normal operation. The expression can be arbitrary if
|
||
there is no caller-callee entry value binding expected. */
|
||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||
_("DWARF-2 expression error: DW_OP_entry_value is supported "
|
||
"only for single DW_OP_reg* or for DW_OP_fbreg(*)"));
|
||
}
|
||
|
||
/* Fetch a DW_AT_const_value through a synthetic pointer. */
|
||
|
||
static struct value *
|
||
fetch_const_value_from_synthetic_pointer (sect_offset die, LONGEST byte_offset,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile,
|
||
struct type *type)
|
||
{
|
||
struct value *result = NULL;
|
||
const gdb_byte *bytes;
|
||
LONGEST len;
|
||
|
||
auto_obstack temp_obstack;
|
||
bytes = dwarf2_fetch_constant_bytes (die, per_cu, per_objfile,
|
||
&temp_obstack, &len);
|
||
|
||
if (bytes != NULL)
|
||
{
|
||
if (byte_offset >= 0
|
||
&& byte_offset + type->target_type ()->length () <= len)
|
||
{
|
||
bytes += byte_offset;
|
||
result = value_from_contents (type->target_type (), bytes);
|
||
}
|
||
else
|
||
invalid_synthetic_pointer ();
|
||
}
|
||
else
|
||
result = value::allocate_optimized_out (type->target_type ());
|
||
|
||
return result;
|
||
}
|
||
|
||
/* See loc.h. */
|
||
|
||
struct value *
|
||
indirect_synthetic_pointer (sect_offset die, LONGEST byte_offset,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile,
|
||
const frame_info_ptr &frame, struct type *type,
|
||
bool resolve_abstract_p)
|
||
{
|
||
/* Fetch the location expression of the DIE we're pointing to. */
|
||
auto get_frame_address_in_block_wrapper = [frame] ()
|
||
{
|
||
return get_frame_address_in_block (frame);
|
||
};
|
||
struct dwarf2_locexpr_baton baton
|
||
= dwarf2_fetch_die_loc_sect_off (die, per_cu, per_objfile,
|
||
get_frame_address_in_block_wrapper,
|
||
resolve_abstract_p);
|
||
|
||
/* Get type of pointed-to DIE. */
|
||
struct type *orig_type = dwarf2_fetch_die_type_sect_off (die, per_cu,
|
||
per_objfile);
|
||
if (orig_type == NULL)
|
||
invalid_synthetic_pointer ();
|
||
|
||
/* If pointed-to DIE has a DW_AT_location, evaluate it and return the
|
||
resulting value. Otherwise, it may have a DW_AT_const_value instead,
|
||
or it may've been optimized out. */
|
||
if (baton.data != NULL)
|
||
return dwarf2_evaluate_loc_desc_full (orig_type, frame, baton.data,
|
||
baton.size, baton.per_cu,
|
||
baton.per_objfile,
|
||
type->target_type (),
|
||
byte_offset);
|
||
else
|
||
return fetch_const_value_from_synthetic_pointer (die, byte_offset, per_cu,
|
||
per_objfile, type);
|
||
}
|
||
|
||
/* Evaluate a location description, starting at DATA and with length
|
||
SIZE, to find the current location of variable of TYPE in the
|
||
context of FRAME. If SUBOBJ_TYPE is non-NULL, return instead the
|
||
location of the subobject of type SUBOBJ_TYPE at byte offset
|
||
SUBOBJ_BYTE_OFFSET within the variable of type TYPE. */
|
||
|
||
static struct value *
|
||
dwarf2_evaluate_loc_desc_full (struct type *type, const frame_info_ptr &frame,
|
||
const gdb_byte *data, size_t size,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile,
|
||
struct type *subobj_type,
|
||
LONGEST subobj_byte_offset,
|
||
bool as_lval)
|
||
{
|
||
if (subobj_type == NULL)
|
||
{
|
||
subobj_type = type;
|
||
subobj_byte_offset = 0;
|
||
}
|
||
else if (subobj_byte_offset < 0)
|
||
invalid_synthetic_pointer ();
|
||
|
||
if (size == 0)
|
||
return value::allocate_optimized_out (subobj_type);
|
||
|
||
dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
|
||
|
||
value *retval;
|
||
scoped_value_mark free_values;
|
||
|
||
try
|
||
{
|
||
retval = ctx.evaluate (data, size, as_lval, per_cu, frame, nullptr,
|
||
type, subobj_type, subobj_byte_offset);
|
||
}
|
||
catch (const gdb_exception_error &ex)
|
||
{
|
||
if (ex.error == NOT_AVAILABLE_ERROR)
|
||
{
|
||
free_values.free_to_mark ();
|
||
retval = value::allocate (subobj_type);
|
||
retval->mark_bytes_unavailable (0,
|
||
subobj_type->length ());
|
||
return retval;
|
||
}
|
||
else if (ex.error == NO_ENTRY_VALUE_ERROR)
|
||
{
|
||
if (entry_values_debug)
|
||
exception_print (gdb_stdout, ex);
|
||
free_values.free_to_mark ();
|
||
return value::allocate_optimized_out (subobj_type);
|
||
}
|
||
else
|
||
throw;
|
||
}
|
||
|
||
/* We need to clean up all the values that are not needed any more.
|
||
The problem with a value_ref_ptr class is that it disconnects the
|
||
RETVAL from the value garbage collection, so we need to make
|
||
a copy of that value on the stack to keep everything consistent.
|
||
The value_ref_ptr will clean up after itself at the end of this block. */
|
||
value_ref_ptr value_holder = value_ref_ptr::new_reference (retval);
|
||
free_values.free_to_mark ();
|
||
|
||
return retval->copy ();
|
||
}
|
||
|
||
/* The exported interface to dwarf2_evaluate_loc_desc_full; it always
|
||
passes 0 as the byte_offset. */
|
||
|
||
struct value *
|
||
dwarf2_evaluate_loc_desc (struct type *type, const frame_info_ptr &frame,
|
||
const gdb_byte *data, size_t size,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile, bool as_lval)
|
||
{
|
||
return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu,
|
||
per_objfile, NULL, 0, as_lval);
|
||
}
|
||
|
||
/* Evaluates a dwarf expression and stores the result in VAL,
|
||
expecting that the dwarf expression only produces a single
|
||
CORE_ADDR. FRAME is the frame in which the expression is
|
||
evaluated. ADDR_STACK is a context (location of a variable) and
|
||
might be needed to evaluate the location expression.
|
||
|
||
PUSH_VALUES is an array of values to be pushed to the expression stack
|
||
before evaluation starts. PUSH_VALUES[0] is pushed first, then
|
||
PUSH_VALUES[1], and so on.
|
||
|
||
Returns 1 on success, 0 otherwise. */
|
||
|
||
static int
|
||
dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
|
||
const frame_info_ptr &frame,
|
||
const struct property_addr_info *addr_stack,
|
||
CORE_ADDR *valp,
|
||
gdb::array_view<CORE_ADDR> push_values,
|
||
bool *is_reference)
|
||
{
|
||
if (dlbaton == NULL || dlbaton->size == 0)
|
||
return 0;
|
||
|
||
dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
|
||
dwarf2_per_cu_data *per_cu = dlbaton->per_cu;
|
||
dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
|
||
|
||
value *result;
|
||
scoped_value_mark free_values;
|
||
|
||
/* Place any initial values onto the expression stack. */
|
||
for (const auto &val : push_values)
|
||
ctx.push_address (val, false);
|
||
|
||
try
|
||
{
|
||
result = ctx.evaluate (dlbaton->data, dlbaton->size,
|
||
true, per_cu, frame, addr_stack);
|
||
}
|
||
catch (const gdb_exception_error &ex)
|
||
{
|
||
if (ex.error == NOT_AVAILABLE_ERROR)
|
||
{
|
||
return 0;
|
||
}
|
||
else if (ex.error == NO_ENTRY_VALUE_ERROR)
|
||
{
|
||
if (entry_values_debug)
|
||
exception_print (gdb_stdout, ex);
|
||
return 0;
|
||
}
|
||
else
|
||
throw;
|
||
}
|
||
|
||
if (result->optimized_out ())
|
||
return 0;
|
||
|
||
if (result->lval () == lval_memory)
|
||
*valp = result->address ();
|
||
else
|
||
{
|
||
if (result->lval () == not_lval)
|
||
*is_reference = false;
|
||
|
||
*valp = value_as_address (result);
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* See dwarf2/loc.h. */
|
||
|
||
bool
|
||
dwarf2_evaluate_property (const dynamic_prop *prop,
|
||
const frame_info_ptr &initial_frame,
|
||
const property_addr_info *addr_stack,
|
||
CORE_ADDR *value,
|
||
gdb::array_view<CORE_ADDR> push_values)
|
||
{
|
||
if (prop == NULL)
|
||
return false;
|
||
|
||
/* Evaluating a property should not change the current language.
|
||
Without this here this could happen if the code below selects a
|
||
frame. */
|
||
scoped_restore_current_language save_language;
|
||
frame_info_ptr frame = initial_frame;
|
||
|
||
if (frame == NULL && has_stack_frames ())
|
||
frame = get_selected_frame (NULL);
|
||
|
||
switch (prop->kind ())
|
||
{
|
||
case PROP_LOCEXPR:
|
||
{
|
||
const struct dwarf2_property_baton *baton = prop->baton ();
|
||
gdb_assert (baton->property_type != NULL);
|
||
|
||
bool is_reference = baton->locexpr.is_reference;
|
||
if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame, addr_stack,
|
||
value, push_values, &is_reference))
|
||
{
|
||
if (is_reference)
|
||
{
|
||
struct value *val = value_at (baton->property_type, *value);
|
||
*value = value_as_address (val);
|
||
}
|
||
else
|
||
{
|
||
gdb_assert (baton->property_type != NULL);
|
||
|
||
struct type *type = check_typedef (baton->property_type);
|
||
if (type->length () < sizeof (CORE_ADDR)
|
||
&& !type->is_unsigned ())
|
||
{
|
||
/* If we have a valid return candidate and it's value
|
||
is signed, we have to sign-extend the value because
|
||
CORE_ADDR on 64bit machine has 8 bytes but address
|
||
size of an 32bit application is bytes. */
|
||
const int addr_size
|
||
= (baton->locexpr.per_cu->addr_size ()
|
||
* TARGET_CHAR_BIT);
|
||
const CORE_ADDR neg_mask
|
||
= (~((CORE_ADDR) 0) << (addr_size - 1));
|
||
|
||
/* Check if signed bit is set and sign-extend values. */
|
||
if (*value & neg_mask)
|
||
*value |= neg_mask;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case PROP_LOCLIST:
|
||
{
|
||
const dwarf2_property_baton *baton = prop->baton ();
|
||
CORE_ADDR pc;
|
||
const gdb_byte *data;
|
||
struct value *val;
|
||
size_t size;
|
||
|
||
if (frame == NULL
|
||
|| !get_frame_address_in_block_if_available (frame, &pc))
|
||
return false;
|
||
|
||
data = dwarf2_find_location_expression (&baton->loclist, &size, pc);
|
||
if (data != NULL)
|
||
{
|
||
val = dwarf2_evaluate_loc_desc (baton->property_type, frame, data,
|
||
size, baton->loclist.per_cu,
|
||
baton->loclist.per_objfile);
|
||
if (!val->optimized_out ())
|
||
{
|
||
*value = value_as_address (val);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case PROP_CONST:
|
||
*value = prop->const_val ();
|
||
return true;
|
||
|
||
case PROP_ADDR_OFFSET:
|
||
{
|
||
const dwarf2_property_baton *baton = prop->baton ();
|
||
const struct property_addr_info *pinfo;
|
||
struct value *val;
|
||
|
||
for (pinfo = addr_stack; pinfo != NULL; pinfo = pinfo->next)
|
||
{
|
||
/* This approach lets us avoid checking the qualifiers. */
|
||
if (TYPE_MAIN_TYPE (pinfo->type)
|
||
== TYPE_MAIN_TYPE (baton->property_type))
|
||
break;
|
||
}
|
||
if (pinfo == NULL)
|
||
error (_("cannot find reference address for offset property"));
|
||
if (pinfo->valaddr.data () != NULL)
|
||
val = value_from_contents
|
||
(baton->offset_info.type,
|
||
pinfo->valaddr.data () + baton->offset_info.offset);
|
||
else
|
||
val = value_at (baton->offset_info.type,
|
||
pinfo->addr + baton->offset_info.offset);
|
||
*value = value_as_address (val);
|
||
return true;
|
||
}
|
||
|
||
case PROP_VARIABLE_NAME:
|
||
{
|
||
struct value *val = compute_var_value (prop->variable_name ());
|
||
if (val != nullptr)
|
||
{
|
||
*value = value_as_long (val);
|
||
return true;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/* See dwarf2/loc.h. */
|
||
|
||
void
|
||
dwarf2_compile_property_to_c (string_file *stream,
|
||
const char *result_name,
|
||
struct gdbarch *gdbarch,
|
||
std::vector<bool> ®isters_used,
|
||
const struct dynamic_prop *prop,
|
||
CORE_ADDR pc,
|
||
struct symbol *sym)
|
||
{
|
||
const dwarf2_property_baton *baton = prop->baton ();
|
||
const gdb_byte *data;
|
||
size_t size;
|
||
dwarf2_per_cu_data *per_cu;
|
||
dwarf2_per_objfile *per_objfile;
|
||
|
||
if (prop->kind () == PROP_LOCEXPR)
|
||
{
|
||
data = baton->locexpr.data;
|
||
size = baton->locexpr.size;
|
||
per_cu = baton->locexpr.per_cu;
|
||
per_objfile = baton->locexpr.per_objfile;
|
||
}
|
||
else
|
||
{
|
||
gdb_assert (prop->kind () == PROP_LOCLIST);
|
||
|
||
data = dwarf2_find_location_expression (&baton->loclist, &size, pc);
|
||
per_cu = baton->loclist.per_cu;
|
||
per_objfile = baton->loclist.per_objfile;
|
||
}
|
||
|
||
compile_dwarf_bounds_to_c (stream, result_name, prop, sym, pc,
|
||
gdbarch, registers_used,
|
||
per_cu->addr_size (),
|
||
data, data + size, per_cu, per_objfile);
|
||
}
|
||
|
||
/* Compute the correct symbol_needs_kind value for the location
|
||
expression in EXPR.
|
||
|
||
Implemented by traversing the logical control flow graph of the
|
||
expression. */
|
||
|
||
static enum symbol_needs_kind
|
||
dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile,
|
||
bfd_endian byte_order,
|
||
int addr_size,
|
||
int ref_addr_size,
|
||
int depth = 0)
|
||
{
|
||
enum symbol_needs_kind symbol_needs = SYMBOL_NEEDS_NONE;
|
||
|
||
/* If the expression is empty, we have nothing to do. */
|
||
if (expr.empty ())
|
||
return symbol_needs;
|
||
|
||
const gdb_byte *expr_end = expr.data () + expr.size ();
|
||
|
||
/* List of operations to visit. Operations in this list are not visited yet,
|
||
so are not in VISITED_OPS (and vice-versa). */
|
||
std::vector<const gdb_byte *> ops_to_visit;
|
||
|
||
/* Operations already visited. */
|
||
std::unordered_set<const gdb_byte *> visited_ops;
|
||
|
||
/* Insert OP in OPS_TO_VISIT if it is within the expression's range and
|
||
hasn't been visited yet. */
|
||
auto insert_in_ops_to_visit
|
||
= [expr_end, &visited_ops, &ops_to_visit] (const gdb_byte *op_ptr)
|
||
{
|
||
if (op_ptr >= expr_end)
|
||
return;
|
||
|
||
if (visited_ops.find (op_ptr) != visited_ops.end ())
|
||
return;
|
||
|
||
ops_to_visit.push_back (op_ptr);
|
||
};
|
||
|
||
/* Expressions can invoke other expressions with DW_OP_call*. Protect against
|
||
a loop of calls. */
|
||
const int max_depth = 256;
|
||
|
||
if (depth > max_depth)
|
||
error (_("DWARF-2 expression error: Loop detected."));
|
||
|
||
depth++;
|
||
|
||
/* Initialize the to-visit list with the first operation. */
|
||
insert_in_ops_to_visit (&expr[0]);
|
||
|
||
while (!ops_to_visit.empty ())
|
||
{
|
||
/* Pop one op to visit, mark it as visited. */
|
||
const gdb_byte *op_ptr = ops_to_visit.back ();
|
||
ops_to_visit.pop_back ();
|
||
gdb_assert (visited_ops.find (op_ptr) == visited_ops.end ());
|
||
visited_ops.insert (op_ptr);
|
||
|
||
dwarf_location_atom op = (dwarf_location_atom) *op_ptr;
|
||
|
||
/* Most operations have a single possible following operation
|
||
(they are not conditional branches). The code below updates
|
||
OP_PTR to point to that following operation, which is pushed
|
||
back to OPS_TO_VISIT, if needed, at the bottom. Here, leave
|
||
OP_PTR pointing just after the operand. */
|
||
op_ptr++;
|
||
|
||
/* The DWARF expression might have a bug causing an infinite
|
||
loop. In that case, quitting is the only way out. */
|
||
QUIT;
|
||
|
||
switch (op)
|
||
{
|
||
case DW_OP_lit0:
|
||
case DW_OP_lit1:
|
||
case DW_OP_lit2:
|
||
case DW_OP_lit3:
|
||
case DW_OP_lit4:
|
||
case DW_OP_lit5:
|
||
case DW_OP_lit6:
|
||
case DW_OP_lit7:
|
||
case DW_OP_lit8:
|
||
case DW_OP_lit9:
|
||
case DW_OP_lit10:
|
||
case DW_OP_lit11:
|
||
case DW_OP_lit12:
|
||
case DW_OP_lit13:
|
||
case DW_OP_lit14:
|
||
case DW_OP_lit15:
|
||
case DW_OP_lit16:
|
||
case DW_OP_lit17:
|
||
case DW_OP_lit18:
|
||
case DW_OP_lit19:
|
||
case DW_OP_lit20:
|
||
case DW_OP_lit21:
|
||
case DW_OP_lit22:
|
||
case DW_OP_lit23:
|
||
case DW_OP_lit24:
|
||
case DW_OP_lit25:
|
||
case DW_OP_lit26:
|
||
case DW_OP_lit27:
|
||
case DW_OP_lit28:
|
||
case DW_OP_lit29:
|
||
case DW_OP_lit30:
|
||
case DW_OP_lit31:
|
||
case DW_OP_stack_value:
|
||
case DW_OP_dup:
|
||
case DW_OP_drop:
|
||
case DW_OP_swap:
|
||
case DW_OP_over:
|
||
case DW_OP_rot:
|
||
case DW_OP_deref:
|
||
case DW_OP_abs:
|
||
case DW_OP_neg:
|
||
case DW_OP_not:
|
||
case DW_OP_and:
|
||
case DW_OP_div:
|
||
case DW_OP_minus:
|
||
case DW_OP_mod:
|
||
case DW_OP_mul:
|
||
case DW_OP_or:
|
||
case DW_OP_plus:
|
||
case DW_OP_shl:
|
||
case DW_OP_shr:
|
||
case DW_OP_shra:
|
||
case DW_OP_xor:
|
||
case DW_OP_le:
|
||
case DW_OP_ge:
|
||
case DW_OP_eq:
|
||
case DW_OP_lt:
|
||
case DW_OP_gt:
|
||
case DW_OP_ne:
|
||
case DW_OP_nop:
|
||
case DW_OP_GNU_uninit:
|
||
case DW_OP_push_object_address:
|
||
break;
|
||
|
||
case DW_OP_GNU_push_tls_address:
|
||
case DW_OP_form_tls_address:
|
||
if (symbol_needs <= SYMBOL_NEEDS_REGISTERS)
|
||
symbol_needs = SYMBOL_NEEDS_REGISTERS;
|
||
break;
|
||
|
||
case DW_OP_convert:
|
||
case DW_OP_GNU_convert:
|
||
case DW_OP_reinterpret:
|
||
case DW_OP_GNU_reinterpret:
|
||
case DW_OP_addrx:
|
||
case DW_OP_GNU_addr_index:
|
||
case DW_OP_constx:
|
||
case DW_OP_GNU_const_index:
|
||
case DW_OP_constu:
|
||
case DW_OP_plus_uconst:
|
||
case DW_OP_piece:
|
||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||
break;
|
||
|
||
case DW_OP_consts:
|
||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||
break;
|
||
|
||
case DW_OP_bit_piece:
|
||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||
break;
|
||
|
||
case DW_OP_deref_type:
|
||
case DW_OP_GNU_deref_type:
|
||
op_ptr++;
|
||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||
break;
|
||
|
||
case DW_OP_addr:
|
||
op_ptr += addr_size;
|
||
break;
|
||
|
||
case DW_OP_const1u:
|
||
case DW_OP_const1s:
|
||
op_ptr += 1;
|
||
break;
|
||
|
||
case DW_OP_const2u:
|
||
case DW_OP_const2s:
|
||
op_ptr += 2;
|
||
break;
|
||
|
||
case DW_OP_const4s:
|
||
case DW_OP_const4u:
|
||
op_ptr += 4;
|
||
break;
|
||
|
||
case DW_OP_const8s:
|
||
case DW_OP_const8u:
|
||
op_ptr += 8;
|
||
break;
|
||
|
||
case DW_OP_reg0:
|
||
case DW_OP_reg1:
|
||
case DW_OP_reg2:
|
||
case DW_OP_reg3:
|
||
case DW_OP_reg4:
|
||
case DW_OP_reg5:
|
||
case DW_OP_reg6:
|
||
case DW_OP_reg7:
|
||
case DW_OP_reg8:
|
||
case DW_OP_reg9:
|
||
case DW_OP_reg10:
|
||
case DW_OP_reg11:
|
||
case DW_OP_reg12:
|
||
case DW_OP_reg13:
|
||
case DW_OP_reg14:
|
||
case DW_OP_reg15:
|
||
case DW_OP_reg16:
|
||
case DW_OP_reg17:
|
||
case DW_OP_reg18:
|
||
case DW_OP_reg19:
|
||
case DW_OP_reg20:
|
||
case DW_OP_reg21:
|
||
case DW_OP_reg22:
|
||
case DW_OP_reg23:
|
||
case DW_OP_reg24:
|
||
case DW_OP_reg25:
|
||
case DW_OP_reg26:
|
||
case DW_OP_reg27:
|
||
case DW_OP_reg28:
|
||
case DW_OP_reg29:
|
||
case DW_OP_reg30:
|
||
case DW_OP_reg31:
|
||
case DW_OP_regx:
|
||
case DW_OP_breg0:
|
||
case DW_OP_breg1:
|
||
case DW_OP_breg2:
|
||
case DW_OP_breg3:
|
||
case DW_OP_breg4:
|
||
case DW_OP_breg5:
|
||
case DW_OP_breg6:
|
||
case DW_OP_breg7:
|
||
case DW_OP_breg8:
|
||
case DW_OP_breg9:
|
||
case DW_OP_breg10:
|
||
case DW_OP_breg11:
|
||
case DW_OP_breg12:
|
||
case DW_OP_breg13:
|
||
case DW_OP_breg14:
|
||
case DW_OP_breg15:
|
||
case DW_OP_breg16:
|
||
case DW_OP_breg17:
|
||
case DW_OP_breg18:
|
||
case DW_OP_breg19:
|
||
case DW_OP_breg20:
|
||
case DW_OP_breg21:
|
||
case DW_OP_breg22:
|
||
case DW_OP_breg23:
|
||
case DW_OP_breg24:
|
||
case DW_OP_breg25:
|
||
case DW_OP_breg26:
|
||
case DW_OP_breg27:
|
||
case DW_OP_breg28:
|
||
case DW_OP_breg29:
|
||
case DW_OP_breg30:
|
||
case DW_OP_breg31:
|
||
case DW_OP_bregx:
|
||
case DW_OP_fbreg:
|
||
case DW_OP_call_frame_cfa:
|
||
case DW_OP_entry_value:
|
||
case DW_OP_GNU_entry_value:
|
||
case DW_OP_GNU_parameter_ref:
|
||
case DW_OP_regval_type:
|
||
case DW_OP_GNU_regval_type:
|
||
symbol_needs = SYMBOL_NEEDS_FRAME;
|
||
break;
|
||
|
||
case DW_OP_implicit_value:
|
||
{
|
||
uint64_t uoffset;
|
||
op_ptr = safe_read_uleb128 (op_ptr, expr_end, &uoffset);
|
||
op_ptr += uoffset;
|
||
break;
|
||
}
|
||
|
||
case DW_OP_implicit_pointer:
|
||
case DW_OP_GNU_implicit_pointer:
|
||
op_ptr += ref_addr_size;
|
||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||
break;
|
||
|
||
case DW_OP_deref_size:
|
||
case DW_OP_pick:
|
||
op_ptr++;
|
||
break;
|
||
|
||
case DW_OP_skip:
|
||
{
|
||
int64_t offset = extract_signed_integer (op_ptr, 2, byte_order);
|
||
op_ptr += 2;
|
||
op_ptr += offset;
|
||
break;
|
||
}
|
||
|
||
case DW_OP_bra:
|
||
{
|
||
/* This is the only operation that pushes two operations in
|
||
the to-visit list, so handle it all here. */
|
||
LONGEST offset = extract_signed_integer (op_ptr, 2, byte_order);
|
||
op_ptr += 2;
|
||
|
||
insert_in_ops_to_visit (op_ptr + offset);
|
||
insert_in_ops_to_visit (op_ptr);
|
||
continue;
|
||
}
|
||
|
||
case DW_OP_call2:
|
||
case DW_OP_call4:
|
||
{
|
||
unsigned int len = op == DW_OP_call2 ? 2 : 4;
|
||
cu_offset cu_off
|
||
= (cu_offset) extract_unsigned_integer (op_ptr, len, byte_order);
|
||
op_ptr += len;
|
||
|
||
auto get_frame_pc = [&symbol_needs] ()
|
||
{
|
||
symbol_needs = SYMBOL_NEEDS_FRAME;
|
||
return 0;
|
||
};
|
||
|
||
struct dwarf2_locexpr_baton baton
|
||
= dwarf2_fetch_die_loc_cu_off (cu_off, per_cu,
|
||
per_objfile,
|
||
get_frame_pc);
|
||
|
||
/* If SYMBOL_NEEDS_FRAME is returned from the previous call,
|
||
we dont have to check the baton content. */
|
||
if (symbol_needs != SYMBOL_NEEDS_FRAME)
|
||
{
|
||
gdbarch *arch = baton.per_objfile->objfile->arch ();
|
||
gdb::array_view<const gdb_byte> sub_expr (baton.data,
|
||
baton.size);
|
||
symbol_needs
|
||
= dwarf2_get_symbol_read_needs (sub_expr,
|
||
baton.per_cu,
|
||
baton.per_objfile,
|
||
gdbarch_byte_order (arch),
|
||
baton.per_cu->addr_size (),
|
||
baton.per_cu->ref_addr_size (),
|
||
depth);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case DW_OP_GNU_variable_value:
|
||
{
|
||
sect_offset sect_off
|
||
= (sect_offset) extract_unsigned_integer (op_ptr,
|
||
ref_addr_size,
|
||
byte_order);
|
||
op_ptr += ref_addr_size;
|
||
|
||
struct type *die_type
|
||
= dwarf2_fetch_die_type_sect_off (sect_off, per_cu,
|
||
per_objfile);
|
||
|
||
if (die_type == NULL)
|
||
error (_("Bad DW_OP_GNU_variable_value DIE."));
|
||
|
||
/* Note: Things still work when the following test is
|
||
removed. This test and error is here to conform to the
|
||
proposed specification. */
|
||
if (die_type->code () != TYPE_CODE_INT
|
||
&& die_type->code () != TYPE_CODE_PTR)
|
||
error (_("Type of DW_OP_GNU_variable_value DIE must be "
|
||
"an integer or pointer."));
|
||
|
||
auto get_frame_pc = [&symbol_needs] ()
|
||
{
|
||
symbol_needs = SYMBOL_NEEDS_FRAME;
|
||
return 0;
|
||
};
|
||
|
||
struct dwarf2_locexpr_baton baton
|
||
= dwarf2_fetch_die_loc_sect_off (sect_off, per_cu,
|
||
per_objfile,
|
||
get_frame_pc, true);
|
||
|
||
/* If SYMBOL_NEEDS_FRAME is returned from the previous call,
|
||
we dont have to check the baton content. */
|
||
if (symbol_needs != SYMBOL_NEEDS_FRAME)
|
||
{
|
||
gdbarch *arch = baton.per_objfile->objfile->arch ();
|
||
gdb::array_view<const gdb_byte> sub_expr (baton.data,
|
||
baton.size);
|
||
symbol_needs
|
||
= dwarf2_get_symbol_read_needs (sub_expr,
|
||
baton.per_cu,
|
||
baton.per_objfile,
|
||
gdbarch_byte_order (arch),
|
||
baton.per_cu->addr_size (),
|
||
baton.per_cu->ref_addr_size (),
|
||
depth);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case DW_OP_const_type:
|
||
case DW_OP_GNU_const_type:
|
||
{
|
||
uint64_t uoffset;
|
||
op_ptr = safe_read_uleb128 (op_ptr, expr_end, &uoffset);
|
||
gdb_byte offset = *op_ptr++;
|
||
op_ptr += offset;
|
||
break;
|
||
}
|
||
|
||
default:
|
||
error (_("Unhandled DWARF expression opcode 0x%x"), op);
|
||
}
|
||
|
||
/* If it is known that a frame information is
|
||
needed we can stop parsing the expression. */
|
||
if (symbol_needs == SYMBOL_NEEDS_FRAME)
|
||
break;
|
||
|
||
insert_in_ops_to_visit (op_ptr);
|
||
}
|
||
|
||
return symbol_needs;
|
||
}
|
||
|
||
/* A helper function that throws an unimplemented error mentioning a
|
||
given DWARF operator. */
|
||
|
||
[[noreturn]] static void
|
||
unimplemented (unsigned int op)
|
||
{
|
||
const char *name = get_DW_OP_name (op);
|
||
|
||
if (name)
|
||
error (_("DWARF operator %s cannot be translated to an agent expression"),
|
||
name);
|
||
else
|
||
error (_("Unknown DWARF operator 0x%02x cannot be translated "
|
||
"to an agent expression"),
|
||
op);
|
||
}
|
||
|
||
/* See dwarf2/loc.h.
|
||
|
||
This is basically a wrapper on gdbarch_dwarf2_reg_to_regnum so that we
|
||
can issue a complaint, which is better than having every target's
|
||
implementation of dwarf2_reg_to_regnum do it. */
|
||
|
||
int
|
||
dwarf_reg_to_regnum (struct gdbarch *arch, int dwarf_reg)
|
||
{
|
||
int reg = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_reg);
|
||
|
||
if (reg == -1)
|
||
{
|
||
complaint (_("bad DWARF register number %d"), dwarf_reg);
|
||
}
|
||
return reg;
|
||
}
|
||
|
||
/* Subroutine of dwarf_reg_to_regnum_or_error to simplify it.
|
||
Throw an error because DWARF_REG is bad. */
|
||
|
||
static void
|
||
throw_bad_regnum_error (ULONGEST dwarf_reg)
|
||
{
|
||
/* Still want to print -1 as "-1".
|
||
We *could* have int and ULONGEST versions of dwarf2_reg_to_regnum_or_error
|
||
but that's overkill for now. */
|
||
if ((int) dwarf_reg == dwarf_reg)
|
||
error (_("Unable to access DWARF register number %d"), (int) dwarf_reg);
|
||
error (_("Unable to access DWARF register number %s"),
|
||
pulongest (dwarf_reg));
|
||
}
|
||
|
||
/* See dwarf2/loc.h. */
|
||
|
||
int
|
||
dwarf_reg_to_regnum_or_error (struct gdbarch *arch, ULONGEST dwarf_reg)
|
||
{
|
||
int reg;
|
||
|
||
if (dwarf_reg > INT_MAX)
|
||
throw_bad_regnum_error (dwarf_reg);
|
||
/* Yes, we will end up issuing a complaint and an error if DWARF_REG is
|
||
bad, but that's ok. */
|
||
reg = dwarf_reg_to_regnum (arch, (int) dwarf_reg);
|
||
if (reg == -1)
|
||
throw_bad_regnum_error (dwarf_reg);
|
||
return reg;
|
||
}
|
||
|
||
/* A helper function that emits an access to memory. ARCH is the
|
||
target architecture. EXPR is the expression which we are building.
|
||
NBITS is the number of bits we want to read. This emits the
|
||
opcodes needed to read the memory and then extract the desired
|
||
bits. */
|
||
|
||
static void
|
||
access_memory (struct gdbarch *arch, struct agent_expr *expr, ULONGEST nbits)
|
||
{
|
||
ULONGEST nbytes = (nbits + 7) / 8;
|
||
|
||
gdb_assert (nbytes > 0 && nbytes <= sizeof (LONGEST));
|
||
|
||
if (expr->tracing)
|
||
ax_trace_quick (expr, nbytes);
|
||
|
||
if (nbits <= 8)
|
||
ax_simple (expr, aop_ref8);
|
||
else if (nbits <= 16)
|
||
ax_simple (expr, aop_ref16);
|
||
else if (nbits <= 32)
|
||
ax_simple (expr, aop_ref32);
|
||
else
|
||
ax_simple (expr, aop_ref64);
|
||
|
||
/* If we read exactly the number of bytes we wanted, we're done. */
|
||
if (8 * nbytes == nbits)
|
||
return;
|
||
|
||
if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG)
|
||
{
|
||
/* On a bits-big-endian machine, we want the high-order
|
||
NBITS. */
|
||
ax_const_l (expr, 8 * nbytes - nbits);
|
||
ax_simple (expr, aop_rsh_unsigned);
|
||
}
|
||
else
|
||
{
|
||
/* On a bits-little-endian box, we want the low-order NBITS. */
|
||
ax_zero_ext (expr, nbits);
|
||
}
|
||
}
|
||
|
||
/* Compile a DWARF location expression to an agent expression.
|
||
|
||
EXPR is the agent expression we are building.
|
||
LOC is the agent value we modify.
|
||
ARCH is the architecture.
|
||
ADDR_SIZE is the size of addresses, in bytes.
|
||
OP_PTR is the start of the location expression.
|
||
OP_END is one past the last byte of the location expression.
|
||
|
||
This will throw an exception for various kinds of errors -- for
|
||
example, if the expression cannot be compiled, or if the expression
|
||
is invalid. */
|
||
|
||
static void
|
||
dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
|
||
unsigned int addr_size, const gdb_byte *op_ptr,
|
||
const gdb_byte *op_end,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile)
|
||
{
|
||
gdbarch *arch = expr->gdbarch;
|
||
std::vector<int> dw_labels, patches;
|
||
const gdb_byte * const base = op_ptr;
|
||
const gdb_byte *previous_piece = op_ptr;
|
||
enum bfd_endian byte_order = gdbarch_byte_order (arch);
|
||
ULONGEST bits_collected = 0;
|
||
unsigned int addr_size_bits = 8 * addr_size;
|
||
bool bits_big_endian = byte_order == BFD_ENDIAN_BIG;
|
||
|
||
std::vector<int> offsets (op_end - op_ptr, -1);
|
||
|
||
/* By default we are making an address. */
|
||
loc->kind = axs_lvalue_memory;
|
||
|
||
while (op_ptr < op_end)
|
||
{
|
||
enum dwarf_location_atom op = (enum dwarf_location_atom) *op_ptr;
|
||
uint64_t uoffset, reg;
|
||
int64_t offset;
|
||
int i;
|
||
|
||
offsets[op_ptr - base] = expr->buf.size ();
|
||
++op_ptr;
|
||
|
||
/* Our basic approach to code generation is to map DWARF
|
||
operations directly to AX operations. However, there are
|
||
some differences.
|
||
|
||
First, DWARF works on address-sized units, but AX always uses
|
||
LONGEST. For most operations we simply ignore this
|
||
difference; instead we generate sign extensions as needed
|
||
before division and comparison operations. It would be nice
|
||
to omit the sign extensions, but there is no way to determine
|
||
the size of the target's LONGEST. (This code uses the size
|
||
of the host LONGEST in some cases -- that is a bug but it is
|
||
difficult to fix.)
|
||
|
||
Second, some DWARF operations cannot be translated to AX.
|
||
For these we simply fail. See
|
||
http://sourceware.org/bugzilla/show_bug.cgi?id=11662. */
|
||
switch (op)
|
||
{
|
||
case DW_OP_lit0:
|
||
case DW_OP_lit1:
|
||
case DW_OP_lit2:
|
||
case DW_OP_lit3:
|
||
case DW_OP_lit4:
|
||
case DW_OP_lit5:
|
||
case DW_OP_lit6:
|
||
case DW_OP_lit7:
|
||
case DW_OP_lit8:
|
||
case DW_OP_lit9:
|
||
case DW_OP_lit10:
|
||
case DW_OP_lit11:
|
||
case DW_OP_lit12:
|
||
case DW_OP_lit13:
|
||
case DW_OP_lit14:
|
||
case DW_OP_lit15:
|
||
case DW_OP_lit16:
|
||
case DW_OP_lit17:
|
||
case DW_OP_lit18:
|
||
case DW_OP_lit19:
|
||
case DW_OP_lit20:
|
||
case DW_OP_lit21:
|
||
case DW_OP_lit22:
|
||
case DW_OP_lit23:
|
||
case DW_OP_lit24:
|
||
case DW_OP_lit25:
|
||
case DW_OP_lit26:
|
||
case DW_OP_lit27:
|
||
case DW_OP_lit28:
|
||
case DW_OP_lit29:
|
||
case DW_OP_lit30:
|
||
case DW_OP_lit31:
|
||
ax_const_l (expr, op - DW_OP_lit0);
|
||
break;
|
||
|
||
case DW_OP_addr:
|
||
uoffset = extract_unsigned_integer (op_ptr, addr_size, byte_order);
|
||
op_ptr += addr_size;
|
||
/* Some versions of GCC emit DW_OP_addr before
|
||
DW_OP_GNU_push_tls_address. In this case the value is an
|
||
index, not an address. We don't support things like
|
||
branching between the address and the TLS op. */
|
||
if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address)
|
||
uoffset += per_objfile->objfile->text_section_offset ();
|
||
ax_const_l (expr, uoffset);
|
||
break;
|
||
|
||
case DW_OP_const1u:
|
||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 1, byte_order));
|
||
op_ptr += 1;
|
||
break;
|
||
|
||
case DW_OP_const1s:
|
||
ax_const_l (expr, extract_signed_integer (op_ptr, 1, byte_order));
|
||
op_ptr += 1;
|
||
break;
|
||
|
||
case DW_OP_const2u:
|
||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 2, byte_order));
|
||
op_ptr += 2;
|
||
break;
|
||
|
||
case DW_OP_const2s:
|
||
ax_const_l (expr, extract_signed_integer (op_ptr, 2, byte_order));
|
||
op_ptr += 2;
|
||
break;
|
||
|
||
case DW_OP_const4u:
|
||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 4, byte_order));
|
||
op_ptr += 4;
|
||
break;
|
||
|
||
case DW_OP_const4s:
|
||
ax_const_l (expr, extract_signed_integer (op_ptr, 4, byte_order));
|
||
op_ptr += 4;
|
||
break;
|
||
|
||
case DW_OP_const8u:
|
||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 8, byte_order));
|
||
op_ptr += 8;
|
||
break;
|
||
|
||
case DW_OP_const8s:
|
||
ax_const_l (expr, extract_signed_integer (op_ptr, 8, byte_order));
|
||
op_ptr += 8;
|
||
break;
|
||
|
||
case DW_OP_constu:
|
||
op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
|
||
ax_const_l (expr, uoffset);
|
||
break;
|
||
|
||
case DW_OP_consts:
|
||
op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
|
||
ax_const_l (expr, offset);
|
||
break;
|
||
|
||
case DW_OP_reg0:
|
||
case DW_OP_reg1:
|
||
case DW_OP_reg2:
|
||
case DW_OP_reg3:
|
||
case DW_OP_reg4:
|
||
case DW_OP_reg5:
|
||
case DW_OP_reg6:
|
||
case DW_OP_reg7:
|
||
case DW_OP_reg8:
|
||
case DW_OP_reg9:
|
||
case DW_OP_reg10:
|
||
case DW_OP_reg11:
|
||
case DW_OP_reg12:
|
||
case DW_OP_reg13:
|
||
case DW_OP_reg14:
|
||
case DW_OP_reg15:
|
||
case DW_OP_reg16:
|
||
case DW_OP_reg17:
|
||
case DW_OP_reg18:
|
||
case DW_OP_reg19:
|
||
case DW_OP_reg20:
|
||
case DW_OP_reg21:
|
||
case DW_OP_reg22:
|
||
case DW_OP_reg23:
|
||
case DW_OP_reg24:
|
||
case DW_OP_reg25:
|
||
case DW_OP_reg26:
|
||
case DW_OP_reg27:
|
||
case DW_OP_reg28:
|
||
case DW_OP_reg29:
|
||
case DW_OP_reg30:
|
||
case DW_OP_reg31:
|
||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
|
||
loc->u.reg = dwarf_reg_to_regnum_or_error (arch, op - DW_OP_reg0);
|
||
loc->kind = axs_lvalue_register;
|
||
break;
|
||
|
||
case DW_OP_regx:
|
||
op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
|
||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
|
||
loc->u.reg = dwarf_reg_to_regnum_or_error (arch, reg);
|
||
loc->kind = axs_lvalue_register;
|
||
break;
|
||
|
||
case DW_OP_implicit_value:
|
||
{
|
||
uint64_t len;
|
||
|
||
op_ptr = safe_read_uleb128 (op_ptr, op_end, &len);
|
||
if (op_ptr + len > op_end)
|
||
error (_("DW_OP_implicit_value: too few bytes available."));
|
||
if (len > sizeof (ULONGEST))
|
||
error (_("Cannot translate DW_OP_implicit_value of %d bytes"),
|
||
(int) len);
|
||
|
||
ax_const_l (expr, extract_unsigned_integer (op_ptr, len,
|
||
byte_order));
|
||
op_ptr += len;
|
||
dwarf_expr_require_composition (op_ptr, op_end,
|
||
"DW_OP_implicit_value");
|
||
|
||
loc->kind = axs_rvalue;
|
||
}
|
||
break;
|
||
|
||
case DW_OP_stack_value:
|
||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_stack_value");
|
||
loc->kind = axs_rvalue;
|
||
break;
|
||
|
||
case DW_OP_breg0:
|
||
case DW_OP_breg1:
|
||
case DW_OP_breg2:
|
||
case DW_OP_breg3:
|
||
case DW_OP_breg4:
|
||
case DW_OP_breg5:
|
||
case DW_OP_breg6:
|
||
case DW_OP_breg7:
|
||
case DW_OP_breg8:
|
||
case DW_OP_breg9:
|
||
case DW_OP_breg10:
|
||
case DW_OP_breg11:
|
||
case DW_OP_breg12:
|
||
case DW_OP_breg13:
|
||
case DW_OP_breg14:
|
||
case DW_OP_breg15:
|
||
case DW_OP_breg16:
|
||
case DW_OP_breg17:
|
||
case DW_OP_breg18:
|
||
case DW_OP_breg19:
|
||
case DW_OP_breg20:
|
||
case DW_OP_breg21:
|
||
case DW_OP_breg22:
|
||
case DW_OP_breg23:
|
||
case DW_OP_breg24:
|
||
case DW_OP_breg25:
|
||
case DW_OP_breg26:
|
||
case DW_OP_breg27:
|
||
case DW_OP_breg28:
|
||
case DW_OP_breg29:
|
||
case DW_OP_breg30:
|
||
case DW_OP_breg31:
|
||
op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
|
||
i = dwarf_reg_to_regnum_or_error (arch, op - DW_OP_breg0);
|
||
ax_reg (expr, i);
|
||
if (offset != 0)
|
||
{
|
||
ax_const_l (expr, offset);
|
||
ax_simple (expr, aop_add);
|
||
}
|
||
break;
|
||
|
||
case DW_OP_bregx:
|
||
{
|
||
op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
|
||
op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
|
||
i = dwarf_reg_to_regnum_or_error (arch, reg);
|
||
ax_reg (expr, i);
|
||
if (offset != 0)
|
||
{
|
||
ax_const_l (expr, offset);
|
||
ax_simple (expr, aop_add);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case DW_OP_fbreg:
|
||
{
|
||
const gdb_byte *datastart;
|
||
size_t datalen;
|
||
const struct block *b;
|
||
struct symbol *framefunc;
|
||
|
||
b = block_for_pc (expr->scope);
|
||
|
||
if (!b)
|
||
error (_("No block found for address"));
|
||
|
||
framefunc = b->linkage_function ();
|
||
|
||
if (!framefunc)
|
||
error (_("No function found for block"));
|
||
|
||
func_get_frame_base_dwarf_block (framefunc, expr->scope,
|
||
&datastart, &datalen);
|
||
|
||
op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
|
||
dwarf2_compile_expr_to_ax (expr, loc, addr_size, datastart,
|
||
datastart + datalen, per_cu,
|
||
per_objfile);
|
||
if (loc->kind == axs_lvalue_register)
|
||
require_rvalue (expr, loc);
|
||
|
||
if (offset != 0)
|
||
{
|
||
ax_const_l (expr, offset);
|
||
ax_simple (expr, aop_add);
|
||
}
|
||
|
||
loc->kind = axs_lvalue_memory;
|
||
}
|
||
break;
|
||
|
||
case DW_OP_dup:
|
||
ax_simple (expr, aop_dup);
|
||
break;
|
||
|
||
case DW_OP_drop:
|
||
ax_simple (expr, aop_pop);
|
||
break;
|
||
|
||
case DW_OP_pick:
|
||
offset = *op_ptr++;
|
||
ax_pick (expr, offset);
|
||
break;
|
||
|
||
case DW_OP_swap:
|
||
ax_simple (expr, aop_swap);
|
||
break;
|
||
|
||
case DW_OP_over:
|
||
ax_pick (expr, 1);
|
||
break;
|
||
|
||
case DW_OP_rot:
|
||
ax_simple (expr, aop_rot);
|
||
break;
|
||
|
||
case DW_OP_deref:
|
||
case DW_OP_deref_size:
|
||
{
|
||
int size;
|
||
|
||
if (op == DW_OP_deref_size)
|
||
size = *op_ptr++;
|
||
else
|
||
size = addr_size;
|
||
|
||
if (size != 1 && size != 2 && size != 4 && size != 8)
|
||
error (_("Unsupported size %d in %s"),
|
||
size, get_DW_OP_name (op));
|
||
access_memory (arch, expr, size * TARGET_CHAR_BIT);
|
||
}
|
||
break;
|
||
|
||
case DW_OP_abs:
|
||
/* Sign extend the operand. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_dup);
|
||
ax_const_l (expr, 0);
|
||
ax_simple (expr, aop_less_signed);
|
||
ax_simple (expr, aop_log_not);
|
||
i = ax_goto (expr, aop_if_goto);
|
||
/* We have to emit 0 - X. */
|
||
ax_const_l (expr, 0);
|
||
ax_simple (expr, aop_swap);
|
||
ax_simple (expr, aop_sub);
|
||
ax_label (expr, i, expr->buf.size ());
|
||
break;
|
||
|
||
case DW_OP_neg:
|
||
/* No need to sign extend here. */
|
||
ax_const_l (expr, 0);
|
||
ax_simple (expr, aop_swap);
|
||
ax_simple (expr, aop_sub);
|
||
break;
|
||
|
||
case DW_OP_not:
|
||
/* Sign extend the operand. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_bit_not);
|
||
break;
|
||
|
||
case DW_OP_plus_uconst:
|
||
op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
|
||
/* It would be really weird to emit `DW_OP_plus_uconst 0',
|
||
but we micro-optimize anyhow. */
|
||
if (reg != 0)
|
||
{
|
||
ax_const_l (expr, reg);
|
||
ax_simple (expr, aop_add);
|
||
}
|
||
break;
|
||
|
||
case DW_OP_and:
|
||
ax_simple (expr, aop_bit_and);
|
||
break;
|
||
|
||
case DW_OP_div:
|
||
/* Sign extend the operands. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_simple (expr, aop_div_signed);
|
||
break;
|
||
|
||
case DW_OP_minus:
|
||
ax_simple (expr, aop_sub);
|
||
break;
|
||
|
||
case DW_OP_mod:
|
||
ax_simple (expr, aop_rem_unsigned);
|
||
break;
|
||
|
||
case DW_OP_mul:
|
||
ax_simple (expr, aop_mul);
|
||
break;
|
||
|
||
case DW_OP_or:
|
||
ax_simple (expr, aop_bit_or);
|
||
break;
|
||
|
||
case DW_OP_plus:
|
||
ax_simple (expr, aop_add);
|
||
break;
|
||
|
||
case DW_OP_shl:
|
||
ax_simple (expr, aop_lsh);
|
||
break;
|
||
|
||
case DW_OP_shr:
|
||
ax_simple (expr, aop_rsh_unsigned);
|
||
break;
|
||
|
||
case DW_OP_shra:
|
||
ax_simple (expr, aop_rsh_signed);
|
||
break;
|
||
|
||
case DW_OP_xor:
|
||
ax_simple (expr, aop_bit_xor);
|
||
break;
|
||
|
||
case DW_OP_le:
|
||
/* Sign extend the operands. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_ext (expr, addr_size_bits);
|
||
/* Note no swap here: A <= B is !(B < A). */
|
||
ax_simple (expr, aop_less_signed);
|
||
ax_simple (expr, aop_log_not);
|
||
break;
|
||
|
||
case DW_OP_ge:
|
||
/* Sign extend the operands. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
/* A >= B is !(A < B). */
|
||
ax_simple (expr, aop_less_signed);
|
||
ax_simple (expr, aop_log_not);
|
||
break;
|
||
|
||
case DW_OP_eq:
|
||
/* Sign extend the operands. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_ext (expr, addr_size_bits);
|
||
/* No need for a second swap here. */
|
||
ax_simple (expr, aop_equal);
|
||
break;
|
||
|
||
case DW_OP_lt:
|
||
/* Sign extend the operands. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_simple (expr, aop_less_signed);
|
||
break;
|
||
|
||
case DW_OP_gt:
|
||
/* Sign extend the operands. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_ext (expr, addr_size_bits);
|
||
/* Note no swap here: A > B is B < A. */
|
||
ax_simple (expr, aop_less_signed);
|
||
break;
|
||
|
||
case DW_OP_ne:
|
||
/* Sign extend the operands. */
|
||
ax_ext (expr, addr_size_bits);
|
||
ax_simple (expr, aop_swap);
|
||
ax_ext (expr, addr_size_bits);
|
||
/* No need for a swap here. */
|
||
ax_simple (expr, aop_equal);
|
||
ax_simple (expr, aop_log_not);
|
||
break;
|
||
|
||
case DW_OP_call_frame_cfa:
|
||
{
|
||
int regnum;
|
||
CORE_ADDR text_offset;
|
||
LONGEST off;
|
||
const gdb_byte *cfa_start, *cfa_end;
|
||
|
||
if (dwarf2_fetch_cfa_info (arch, expr->scope, per_cu,
|
||
®num, &off,
|
||
&text_offset, &cfa_start, &cfa_end))
|
||
{
|
||
/* Register. */
|
||
ax_reg (expr, regnum);
|
||
if (off != 0)
|
||
{
|
||
ax_const_l (expr, off);
|
||
ax_simple (expr, aop_add);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Another expression. */
|
||
ax_const_l (expr, text_offset);
|
||
dwarf2_compile_expr_to_ax (expr, loc, addr_size, cfa_start,
|
||
cfa_end, per_cu, per_objfile);
|
||
}
|
||
|
||
loc->kind = axs_lvalue_memory;
|
||
}
|
||
break;
|
||
|
||
case DW_OP_GNU_push_tls_address:
|
||
case DW_OP_form_tls_address:
|
||
unimplemented (op);
|
||
break;
|
||
|
||
case DW_OP_push_object_address:
|
||
unimplemented (op);
|
||
break;
|
||
|
||
case DW_OP_skip:
|
||
offset = extract_signed_integer (op_ptr, 2, byte_order);
|
||
op_ptr += 2;
|
||
i = ax_goto (expr, aop_goto);
|
||
dw_labels.push_back (op_ptr + offset - base);
|
||
patches.push_back (i);
|
||
break;
|
||
|
||
case DW_OP_bra:
|
||
offset = extract_signed_integer (op_ptr, 2, byte_order);
|
||
op_ptr += 2;
|
||
/* Zero extend the operand. */
|
||
ax_zero_ext (expr, addr_size_bits);
|
||
i = ax_goto (expr, aop_if_goto);
|
||
dw_labels.push_back (op_ptr + offset - base);
|
||
patches.push_back (i);
|
||
break;
|
||
|
||
case DW_OP_nop:
|
||
break;
|
||
|
||
case DW_OP_piece:
|
||
case DW_OP_bit_piece:
|
||
{
|
||
uint64_t size;
|
||
|
||
if (op_ptr - 1 == previous_piece)
|
||
error (_("Cannot translate empty pieces to agent expressions"));
|
||
previous_piece = op_ptr - 1;
|
||
|
||
op_ptr = safe_read_uleb128 (op_ptr, op_end, &size);
|
||
if (op == DW_OP_piece)
|
||
{
|
||
size *= 8;
|
||
uoffset = 0;
|
||
}
|
||
else
|
||
op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
|
||
|
||
if (bits_collected + size > 8 * sizeof (LONGEST))
|
||
error (_("Expression pieces exceed word size"));
|
||
|
||
/* Access the bits. */
|
||
switch (loc->kind)
|
||
{
|
||
case axs_lvalue_register:
|
||
ax_reg (expr, loc->u.reg);
|
||
break;
|
||
|
||
case axs_lvalue_memory:
|
||
/* Offset the pointer, if needed. */
|
||
if (uoffset > 8)
|
||
{
|
||
ax_const_l (expr, uoffset / 8);
|
||
ax_simple (expr, aop_add);
|
||
uoffset %= 8;
|
||
}
|
||
access_memory (arch, expr, size);
|
||
break;
|
||
}
|
||
|
||
/* For a bits-big-endian target, shift up what we already
|
||
have. For a bits-little-endian target, shift up the
|
||
new data. Note that there is a potential bug here if
|
||
the DWARF expression leaves multiple values on the
|
||
stack. */
|
||
if (bits_collected > 0)
|
||
{
|
||
if (bits_big_endian)
|
||
{
|
||
ax_simple (expr, aop_swap);
|
||
ax_const_l (expr, size);
|
||
ax_simple (expr, aop_lsh);
|
||
/* We don't need a second swap here, because
|
||
aop_bit_or is symmetric. */
|
||
}
|
||
else
|
||
{
|
||
ax_const_l (expr, size);
|
||
ax_simple (expr, aop_lsh);
|
||
}
|
||
ax_simple (expr, aop_bit_or);
|
||
}
|
||
|
||
bits_collected += size;
|
||
loc->kind = axs_rvalue;
|
||
}
|
||
break;
|
||
|
||
case DW_OP_GNU_uninit:
|
||
unimplemented (op);
|
||
|
||
case DW_OP_call2:
|
||
case DW_OP_call4:
|
||
{
|
||
struct dwarf2_locexpr_baton block;
|
||
int size = (op == DW_OP_call2 ? 2 : 4);
|
||
|
||
uoffset = extract_unsigned_integer (op_ptr, size, byte_order);
|
||
op_ptr += size;
|
||
|
||
auto get_frame_pc_from_expr = [expr] ()
|
||
{
|
||
return expr->scope;
|
||
};
|
||
cu_offset cuoffset = (cu_offset) uoffset;
|
||
block = dwarf2_fetch_die_loc_cu_off (cuoffset, per_cu, per_objfile,
|
||
get_frame_pc_from_expr);
|
||
|
||
/* DW_OP_call_ref is currently not supported. */
|
||
gdb_assert (block.per_cu == per_cu);
|
||
|
||
dwarf2_compile_expr_to_ax (expr, loc, addr_size, block.data,
|
||
block.data + block.size, per_cu,
|
||
per_objfile);
|
||
}
|
||
break;
|
||
|
||
case DW_OP_call_ref:
|
||
unimplemented (op);
|
||
|
||
case DW_OP_GNU_variable_value:
|
||
unimplemented (op);
|
||
|
||
default:
|
||
unimplemented (op);
|
||
}
|
||
}
|
||
|
||
/* Patch all the branches we emitted. */
|
||
for (int i = 0; i < patches.size (); ++i)
|
||
{
|
||
int targ = offsets[dw_labels[i]];
|
||
if (targ == -1)
|
||
internal_error (_("invalid label"));
|
||
ax_label (expr, patches[i], targ);
|
||
}
|
||
}
|
||
|
||
|
||
/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
|
||
evaluator to calculate the location. */
|
||
static struct value *
|
||
locexpr_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
|
||
{
|
||
struct dwarf2_locexpr_baton *dlbaton
|
||
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
struct value *val;
|
||
|
||
val = dwarf2_evaluate_loc_desc (symbol->type (), frame, dlbaton->data,
|
||
dlbaton->size, dlbaton->per_cu,
|
||
dlbaton->per_objfile);
|
||
|
||
return val;
|
||
}
|
||
|
||
/* Return the value of SYMBOL in FRAME at (callee) FRAME's function
|
||
entry. SYMBOL should be a function parameter, otherwise NO_ENTRY_VALUE_ERROR
|
||
will be thrown. */
|
||
|
||
static struct value *
|
||
locexpr_read_variable_at_entry (struct symbol *symbol, const frame_info_ptr &frame)
|
||
{
|
||
struct dwarf2_locexpr_baton *dlbaton
|
||
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
|
||
return value_of_dwarf_block_entry (symbol->type (), frame, dlbaton->data,
|
||
dlbaton->size);
|
||
}
|
||
|
||
/* Implementation of get_symbol_read_needs from
|
||
symbol_computed_ops. */
|
||
|
||
static enum symbol_needs_kind
|
||
locexpr_get_symbol_read_needs (struct symbol *symbol)
|
||
{
|
||
struct dwarf2_locexpr_baton *dlbaton
|
||
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
|
||
gdbarch *arch = dlbaton->per_objfile->objfile->arch ();
|
||
gdb::array_view<const gdb_byte> expr (dlbaton->data, dlbaton->size);
|
||
|
||
return dwarf2_get_symbol_read_needs (expr,
|
||
dlbaton->per_cu,
|
||
dlbaton->per_objfile,
|
||
gdbarch_byte_order (arch),
|
||
dlbaton->per_cu->addr_size (),
|
||
dlbaton->per_cu->ref_addr_size ());
|
||
}
|
||
|
||
/* Return true if DATA points to the end of a piece. END is one past
|
||
the last byte in the expression. */
|
||
|
||
static int
|
||
piece_end_p (const gdb_byte *data, const gdb_byte *end)
|
||
{
|
||
return data == end || data[0] == DW_OP_piece || data[0] == DW_OP_bit_piece;
|
||
}
|
||
|
||
/* Helper for locexpr_describe_location_piece that finds the name of a
|
||
DWARF register. */
|
||
|
||
static const char *
|
||
locexpr_regname (struct gdbarch *gdbarch, int dwarf_regnum)
|
||
{
|
||
int regnum;
|
||
|
||
/* This doesn't use dwarf_reg_to_regnum_or_error on purpose.
|
||
We'd rather print *something* here than throw an error. */
|
||
regnum = dwarf_reg_to_regnum (gdbarch, dwarf_regnum);
|
||
/* gdbarch_register_name may just return "", return something more
|
||
descriptive for bad register numbers. */
|
||
if (regnum == -1)
|
||
{
|
||
/* The text is output as "$bad_register_number".
|
||
That is why we use the underscores. */
|
||
return _("bad_register_number");
|
||
}
|
||
return gdbarch_register_name (gdbarch, regnum);
|
||
}
|
||
|
||
/* Nicely describe a single piece of a location, returning an updated
|
||
position in the bytecode sequence. This function cannot recognize
|
||
all locations; if a location is not recognized, it simply returns
|
||
DATA. If there is an error during reading, e.g. we run off the end
|
||
of the buffer, an error is thrown. */
|
||
|
||
static const gdb_byte *
|
||
locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
|
||
CORE_ADDR addr, dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile,
|
||
const gdb_byte *data, const gdb_byte *end,
|
||
unsigned int addr_size)
|
||
{
|
||
objfile *objfile = per_objfile->objfile;
|
||
struct gdbarch *gdbarch = objfile->arch ();
|
||
size_t leb128_size;
|
||
|
||
if (data[0] >= DW_OP_reg0 && data[0] <= DW_OP_reg31)
|
||
{
|
||
gdb_printf (stream, _("a variable in $%s"),
|
||
locexpr_regname (gdbarch, data[0] - DW_OP_reg0));
|
||
data += 1;
|
||
}
|
||
else if (data[0] == DW_OP_regx)
|
||
{
|
||
uint64_t reg;
|
||
|
||
data = safe_read_uleb128 (data + 1, end, ®);
|
||
gdb_printf (stream, _("a variable in $%s"),
|
||
locexpr_regname (gdbarch, reg));
|
||
}
|
||
else if (data[0] == DW_OP_fbreg)
|
||
{
|
||
const struct block *b;
|
||
struct symbol *framefunc;
|
||
int frame_reg = 0;
|
||
int64_t frame_offset;
|
||
const gdb_byte *base_data, *new_data, *save_data = data;
|
||
size_t base_size;
|
||
int64_t base_offset = 0;
|
||
|
||
new_data = safe_read_sleb128 (data + 1, end, &frame_offset);
|
||
if (!piece_end_p (new_data, end))
|
||
return data;
|
||
data = new_data;
|
||
|
||
b = block_for_pc (addr);
|
||
|
||
if (!b)
|
||
error (_("No block found for address for symbol \"%s\"."),
|
||
symbol->print_name ());
|
||
|
||
framefunc = b->linkage_function ();
|
||
|
||
if (!framefunc)
|
||
error (_("No function found for block for symbol \"%s\"."),
|
||
symbol->print_name ());
|
||
|
||
func_get_frame_base_dwarf_block (framefunc, addr, &base_data, &base_size);
|
||
|
||
if (base_data[0] >= DW_OP_breg0 && base_data[0] <= DW_OP_breg31)
|
||
{
|
||
const gdb_byte *buf_end;
|
||
|
||
frame_reg = base_data[0] - DW_OP_breg0;
|
||
buf_end = safe_read_sleb128 (base_data + 1, base_data + base_size,
|
||
&base_offset);
|
||
if (buf_end != base_data + base_size)
|
||
error (_("Unexpected opcode after "
|
||
"DW_OP_breg%u for symbol \"%s\"."),
|
||
frame_reg, symbol->print_name ());
|
||
}
|
||
else if (base_data[0] >= DW_OP_reg0 && base_data[0] <= DW_OP_reg31)
|
||
{
|
||
/* The frame base is just the register, with no offset. */
|
||
frame_reg = base_data[0] - DW_OP_reg0;
|
||
base_offset = 0;
|
||
}
|
||
else
|
||
{
|
||
/* We don't know what to do with the frame base expression,
|
||
so we can't trace this variable; give up. */
|
||
return save_data;
|
||
}
|
||
|
||
gdb_printf (stream,
|
||
_("a variable at frame base reg $%s offset %s+%s"),
|
||
locexpr_regname (gdbarch, frame_reg),
|
||
plongest (base_offset), plongest (frame_offset));
|
||
}
|
||
else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31
|
||
&& piece_end_p (data, end))
|
||
{
|
||
int64_t offset;
|
||
|
||
data = safe_read_sleb128 (data + 1, end, &offset);
|
||
|
||
gdb_printf (stream,
|
||
_("a variable at offset %s from base reg $%s"),
|
||
plongest (offset),
|
||
locexpr_regname (gdbarch, data[0] - DW_OP_breg0));
|
||
}
|
||
|
||
/* The location expression for a TLS variable looks like this (on a
|
||
64-bit LE machine):
|
||
|
||
DW_AT_location : 10 byte block: 3 4 0 0 0 0 0 0 0 e0
|
||
(DW_OP_addr: 4; DW_OP_GNU_push_tls_address)
|
||
|
||
0x3 is the encoding for DW_OP_addr, which has an operand as long
|
||
as the size of an address on the target machine (here is 8
|
||
bytes). Note that more recent version of GCC emit DW_OP_const4u
|
||
or DW_OP_const8u, depending on address size, rather than
|
||
DW_OP_addr. 0xe0 is the encoding for DW_OP_GNU_push_tls_address.
|
||
The operand represents the offset at which the variable is within
|
||
the thread local storage. */
|
||
|
||
else if (data + 1 + addr_size < end
|
||
&& (data[0] == DW_OP_addr
|
||
|| (addr_size == 4 && data[0] == DW_OP_const4u)
|
||
|| (addr_size == 8 && data[0] == DW_OP_const8u))
|
||
&& (data[1 + addr_size] == DW_OP_GNU_push_tls_address
|
||
|| data[1 + addr_size] == DW_OP_form_tls_address)
|
||
&& piece_end_p (data + 2 + addr_size, end))
|
||
{
|
||
ULONGEST offset;
|
||
offset = extract_unsigned_integer (data + 1, addr_size,
|
||
gdbarch_byte_order (gdbarch));
|
||
|
||
gdb_printf (stream,
|
||
_("a thread-local variable at offset 0x%s "
|
||
"in the thread-local storage for `%s'"),
|
||
phex_nz (offset, addr_size), objfile_name (objfile));
|
||
|
||
data += 1 + addr_size + 1;
|
||
}
|
||
|
||
/* With -gsplit-dwarf a TLS variable can also look like this:
|
||
DW_AT_location : 3 byte block: fc 4 e0
|
||
(DW_OP_GNU_const_index: 4;
|
||
DW_OP_GNU_push_tls_address) |
|
||
3 byte block a2 4 e0
|
||
(DW_OP_constx: 4;
|
||
DW_OP_form_tls_address) */
|
||
else if (data + 3 <= end
|
||
&& data + 1 + (leb128_size = skip_leb128 (data + 1, end)) < end
|
||
&& (data[0] == DW_OP_constx || data[0] == DW_OP_GNU_const_index)
|
||
&& leb128_size > 0
|
||
&& (data[1 + leb128_size] == DW_OP_GNU_push_tls_address
|
||
|| data[1 + leb128_size] == DW_OP_form_tls_address)
|
||
&& piece_end_p (data + 2 + leb128_size, end))
|
||
{
|
||
uint64_t offset;
|
||
|
||
data = safe_read_uleb128 (data + 1, end, &offset);
|
||
offset = (uint64_t) dwarf2_read_addr_index (per_cu, per_objfile, offset);
|
||
gdb_printf (stream,
|
||
_("a thread-local variable at offset 0x%s "
|
||
"in the thread-local storage for `%s'"),
|
||
phex_nz (offset, addr_size), objfile_name (objfile));
|
||
++data;
|
||
}
|
||
|
||
else if (data[0] >= DW_OP_lit0
|
||
&& data[0] <= DW_OP_lit31
|
||
&& data + 1 < end
|
||
&& data[1] == DW_OP_stack_value)
|
||
{
|
||
gdb_printf (stream, _("the constant %d"), data[0] - DW_OP_lit0);
|
||
data += 2;
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
/* Disassemble an expression, stopping at the end of a piece or at the
|
||
end of the expression. Returns a pointer to the next unread byte
|
||
in the input expression. If ALL is nonzero, then this function
|
||
will keep going until it reaches the end of the expression.
|
||
If there is an error during reading, e.g. we run off the end
|
||
of the buffer, an error is thrown. */
|
||
|
||
static const gdb_byte *
|
||
disassemble_dwarf_expression (struct ui_file *stream,
|
||
struct gdbarch *arch, unsigned int addr_size,
|
||
int offset_size, const gdb_byte *start,
|
||
const gdb_byte *data, const gdb_byte *end,
|
||
int indent, int all,
|
||
dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile)
|
||
{
|
||
while (data < end
|
||
&& (all
|
||
|| (data[0] != DW_OP_piece && data[0] != DW_OP_bit_piece)))
|
||
{
|
||
enum dwarf_location_atom op = (enum dwarf_location_atom) *data++;
|
||
uint64_t ul;
|
||
int64_t l;
|
||
const char *name;
|
||
|
||
name = get_DW_OP_name (op);
|
||
|
||
if (!name)
|
||
error (_("Unrecognized DWARF opcode 0x%02x at %ld"),
|
||
op, (long) (data - 1 - start));
|
||
gdb_printf (stream, " %*ld: %s", indent + 4,
|
||
(long) (data - 1 - start), name);
|
||
|
||
switch (op)
|
||
{
|
||
case DW_OP_addr:
|
||
ul = extract_unsigned_integer (data, addr_size,
|
||
gdbarch_byte_order (arch));
|
||
data += addr_size;
|
||
gdb_printf (stream, " 0x%s", phex_nz (ul, addr_size));
|
||
break;
|
||
|
||
case DW_OP_const1u:
|
||
ul = extract_unsigned_integer (data, 1, gdbarch_byte_order (arch));
|
||
data += 1;
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_const1s:
|
||
l = extract_signed_integer (data, 1, gdbarch_byte_order (arch));
|
||
data += 1;
|
||
gdb_printf (stream, " %s", plongest (l));
|
||
break;
|
||
|
||
case DW_OP_const2u:
|
||
ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
|
||
data += 2;
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_const2s:
|
||
l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
|
||
data += 2;
|
||
gdb_printf (stream, " %s", plongest (l));
|
||
break;
|
||
|
||
case DW_OP_const4u:
|
||
ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
|
||
data += 4;
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_const4s:
|
||
l = extract_signed_integer (data, 4, gdbarch_byte_order (arch));
|
||
data += 4;
|
||
gdb_printf (stream, " %s", plongest (l));
|
||
break;
|
||
|
||
case DW_OP_const8u:
|
||
ul = extract_unsigned_integer (data, 8, gdbarch_byte_order (arch));
|
||
data += 8;
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_const8s:
|
||
l = extract_signed_integer (data, 8, gdbarch_byte_order (arch));
|
||
data += 8;
|
||
gdb_printf (stream, " %s", plongest (l));
|
||
break;
|
||
|
||
case DW_OP_constu:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_consts:
|
||
data = safe_read_sleb128 (data, end, &l);
|
||
gdb_printf (stream, " %s", plongest (l));
|
||
break;
|
||
|
||
case DW_OP_reg0:
|
||
case DW_OP_reg1:
|
||
case DW_OP_reg2:
|
||
case DW_OP_reg3:
|
||
case DW_OP_reg4:
|
||
case DW_OP_reg5:
|
||
case DW_OP_reg6:
|
||
case DW_OP_reg7:
|
||
case DW_OP_reg8:
|
||
case DW_OP_reg9:
|
||
case DW_OP_reg10:
|
||
case DW_OP_reg11:
|
||
case DW_OP_reg12:
|
||
case DW_OP_reg13:
|
||
case DW_OP_reg14:
|
||
case DW_OP_reg15:
|
||
case DW_OP_reg16:
|
||
case DW_OP_reg17:
|
||
case DW_OP_reg18:
|
||
case DW_OP_reg19:
|
||
case DW_OP_reg20:
|
||
case DW_OP_reg21:
|
||
case DW_OP_reg22:
|
||
case DW_OP_reg23:
|
||
case DW_OP_reg24:
|
||
case DW_OP_reg25:
|
||
case DW_OP_reg26:
|
||
case DW_OP_reg27:
|
||
case DW_OP_reg28:
|
||
case DW_OP_reg29:
|
||
case DW_OP_reg30:
|
||
case DW_OP_reg31:
|
||
gdb_printf (stream, " [$%s]",
|
||
locexpr_regname (arch, op - DW_OP_reg0));
|
||
break;
|
||
|
||
case DW_OP_regx:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
gdb_printf (stream, " %s [$%s]", pulongest (ul),
|
||
locexpr_regname (arch, (int) ul));
|
||
break;
|
||
|
||
case DW_OP_implicit_value:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
data += ul;
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_breg0:
|
||
case DW_OP_breg1:
|
||
case DW_OP_breg2:
|
||
case DW_OP_breg3:
|
||
case DW_OP_breg4:
|
||
case DW_OP_breg5:
|
||
case DW_OP_breg6:
|
||
case DW_OP_breg7:
|
||
case DW_OP_breg8:
|
||
case DW_OP_breg9:
|
||
case DW_OP_breg10:
|
||
case DW_OP_breg11:
|
||
case DW_OP_breg12:
|
||
case DW_OP_breg13:
|
||
case DW_OP_breg14:
|
||
case DW_OP_breg15:
|
||
case DW_OP_breg16:
|
||
case DW_OP_breg17:
|
||
case DW_OP_breg18:
|
||
case DW_OP_breg19:
|
||
case DW_OP_breg20:
|
||
case DW_OP_breg21:
|
||
case DW_OP_breg22:
|
||
case DW_OP_breg23:
|
||
case DW_OP_breg24:
|
||
case DW_OP_breg25:
|
||
case DW_OP_breg26:
|
||
case DW_OP_breg27:
|
||
case DW_OP_breg28:
|
||
case DW_OP_breg29:
|
||
case DW_OP_breg30:
|
||
case DW_OP_breg31:
|
||
data = safe_read_sleb128 (data, end, &l);
|
||
gdb_printf (stream, " %s [$%s]", plongest (l),
|
||
locexpr_regname (arch, op - DW_OP_breg0));
|
||
break;
|
||
|
||
case DW_OP_bregx:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
data = safe_read_sleb128 (data, end, &l);
|
||
gdb_printf (stream, " register %s [$%s] offset %s",
|
||
pulongest (ul),
|
||
locexpr_regname (arch, (int) ul),
|
||
plongest (l));
|
||
break;
|
||
|
||
case DW_OP_fbreg:
|
||
data = safe_read_sleb128 (data, end, &l);
|
||
gdb_printf (stream, " %s", plongest (l));
|
||
break;
|
||
|
||
case DW_OP_xderef_size:
|
||
case DW_OP_deref_size:
|
||
case DW_OP_pick:
|
||
gdb_printf (stream, " %d", *data);
|
||
++data;
|
||
break;
|
||
|
||
case DW_OP_plus_uconst:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_skip:
|
||
l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
|
||
data += 2;
|
||
gdb_printf (stream, " to %ld",
|
||
(long) (data + l - start));
|
||
break;
|
||
|
||
case DW_OP_bra:
|
||
l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
|
||
data += 2;
|
||
gdb_printf (stream, " %ld",
|
||
(long) (data + l - start));
|
||
break;
|
||
|
||
case DW_OP_call2:
|
||
ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
|
||
data += 2;
|
||
gdb_printf (stream, " offset %s", phex_nz (ul, 2));
|
||
break;
|
||
|
||
case DW_OP_call4:
|
||
ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
|
||
data += 4;
|
||
gdb_printf (stream, " offset %s", phex_nz (ul, 4));
|
||
break;
|
||
|
||
case DW_OP_call_ref:
|
||
ul = extract_unsigned_integer (data, offset_size,
|
||
gdbarch_byte_order (arch));
|
||
data += offset_size;
|
||
gdb_printf (stream, " offset %s", phex_nz (ul, offset_size));
|
||
break;
|
||
|
||
case DW_OP_piece:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
gdb_printf (stream, " %s (bytes)", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_bit_piece:
|
||
{
|
||
uint64_t offset;
|
||
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
data = safe_read_uleb128 (data, end, &offset);
|
||
gdb_printf (stream, " size %s offset %s (bits)",
|
||
pulongest (ul), pulongest (offset));
|
||
}
|
||
break;
|
||
|
||
case DW_OP_implicit_pointer:
|
||
case DW_OP_GNU_implicit_pointer:
|
||
{
|
||
ul = extract_unsigned_integer (data, offset_size,
|
||
gdbarch_byte_order (arch));
|
||
data += offset_size;
|
||
|
||
data = safe_read_sleb128 (data, end, &l);
|
||
|
||
gdb_printf (stream, " DIE %s offset %s",
|
||
phex_nz (ul, offset_size),
|
||
plongest (l));
|
||
}
|
||
break;
|
||
|
||
case DW_OP_deref_type:
|
||
case DW_OP_GNU_deref_type:
|
||
{
|
||
int deref_addr_size = *data++;
|
||
struct type *type;
|
||
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
cu_offset offset = (cu_offset) ul;
|
||
type = dwarf2_get_die_type (offset, per_cu, per_objfile);
|
||
gdb_printf (stream, "<");
|
||
type_print (type, "", stream, -1);
|
||
gdb_printf (stream, " [0x%s]> %d",
|
||
phex_nz (to_underlying (offset), 0),
|
||
deref_addr_size);
|
||
}
|
||
break;
|
||
|
||
case DW_OP_const_type:
|
||
case DW_OP_GNU_const_type:
|
||
{
|
||
struct type *type;
|
||
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
cu_offset type_die = (cu_offset) ul;
|
||
type = dwarf2_get_die_type (type_die, per_cu, per_objfile);
|
||
gdb_printf (stream, "<");
|
||
type_print (type, "", stream, -1);
|
||
gdb_printf (stream, " [0x%s]>",
|
||
phex_nz (to_underlying (type_die), 0));
|
||
|
||
int n = *data++;
|
||
gdb_printf (stream, " %d byte block:", n);
|
||
for (int i = 0; i < n; ++i)
|
||
gdb_printf (stream, " %02x", data[i]);
|
||
data += n;
|
||
}
|
||
break;
|
||
|
||
case DW_OP_regval_type:
|
||
case DW_OP_GNU_regval_type:
|
||
{
|
||
uint64_t reg;
|
||
struct type *type;
|
||
|
||
data = safe_read_uleb128 (data, end, ®);
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
cu_offset type_die = (cu_offset) ul;
|
||
|
||
type = dwarf2_get_die_type (type_die, per_cu, per_objfile);
|
||
gdb_printf (stream, "<");
|
||
type_print (type, "", stream, -1);
|
||
gdb_printf (stream, " [0x%s]> [$%s]",
|
||
phex_nz (to_underlying (type_die), 0),
|
||
locexpr_regname (arch, reg));
|
||
}
|
||
break;
|
||
|
||
case DW_OP_convert:
|
||
case DW_OP_GNU_convert:
|
||
case DW_OP_reinterpret:
|
||
case DW_OP_GNU_reinterpret:
|
||
{
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
cu_offset type_die = (cu_offset) ul;
|
||
|
||
if (to_underlying (type_die) == 0)
|
||
gdb_printf (stream, "<0>");
|
||
else
|
||
{
|
||
struct type *type;
|
||
|
||
type = dwarf2_get_die_type (type_die, per_cu, per_objfile);
|
||
gdb_printf (stream, "<");
|
||
type_print (type, "", stream, -1);
|
||
gdb_printf (stream, " [0x%s]>",
|
||
phex_nz (to_underlying (type_die), 0));
|
||
}
|
||
}
|
||
break;
|
||
|
||
case DW_OP_entry_value:
|
||
case DW_OP_GNU_entry_value:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
gdb_putc ('\n', stream);
|
||
disassemble_dwarf_expression (stream, arch, addr_size, offset_size,
|
||
start, data, data + ul, indent + 2,
|
||
all, per_cu, per_objfile);
|
||
data += ul;
|
||
continue;
|
||
|
||
case DW_OP_GNU_parameter_ref:
|
||
ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
|
||
data += 4;
|
||
gdb_printf (stream, " offset %s", phex_nz (ul, 4));
|
||
break;
|
||
|
||
case DW_OP_addrx:
|
||
case DW_OP_GNU_addr_index:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
ul = (uint64_t) dwarf2_read_addr_index (per_cu, per_objfile, ul);
|
||
gdb_printf (stream, " 0x%s", phex_nz (ul, addr_size));
|
||
break;
|
||
|
||
case DW_OP_constx:
|
||
case DW_OP_GNU_const_index:
|
||
data = safe_read_uleb128 (data, end, &ul);
|
||
ul = (uint64_t) dwarf2_read_addr_index (per_cu, per_objfile, ul);
|
||
gdb_printf (stream, " %s", pulongest (ul));
|
||
break;
|
||
|
||
case DW_OP_GNU_variable_value:
|
||
ul = extract_unsigned_integer (data, offset_size,
|
||
gdbarch_byte_order (arch));
|
||
data += offset_size;
|
||
gdb_printf (stream, " offset %s", phex_nz (ul, offset_size));
|
||
break;
|
||
}
|
||
|
||
gdb_printf (stream, "\n");
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
static bool dwarf_always_disassemble;
|
||
|
||
static void
|
||
show_dwarf_always_disassemble (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
gdb_printf (file,
|
||
_("Whether to always disassemble "
|
||
"DWARF expressions is %s.\n"),
|
||
value);
|
||
}
|
||
|
||
/* Describe a single location, which may in turn consist of multiple
|
||
pieces. */
|
||
|
||
static void
|
||
locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr,
|
||
struct ui_file *stream,
|
||
const gdb_byte *data, size_t size,
|
||
unsigned int addr_size,
|
||
int offset_size, dwarf2_per_cu_data *per_cu,
|
||
dwarf2_per_objfile *per_objfile)
|
||
{
|
||
const gdb_byte *end = data + size;
|
||
int first_piece = 1, bad = 0;
|
||
objfile *objfile = per_objfile->objfile;
|
||
|
||
while (data < end)
|
||
{
|
||
const gdb_byte *here = data;
|
||
int disassemble = 1;
|
||
|
||
if (first_piece)
|
||
first_piece = 0;
|
||
else
|
||
gdb_printf (stream, _(", and "));
|
||
|
||
if (!dwarf_always_disassemble)
|
||
{
|
||
data = locexpr_describe_location_piece (symbol, stream,
|
||
addr, per_cu, per_objfile,
|
||
data, end, addr_size);
|
||
/* If we printed anything, or if we have an empty piece,
|
||
then don't disassemble. */
|
||
if (data != here
|
||
|| data[0] == DW_OP_piece
|
||
|| data[0] == DW_OP_bit_piece)
|
||
disassemble = 0;
|
||
}
|
||
if (disassemble)
|
||
{
|
||
gdb_printf (stream, _("a complex DWARF expression:\n"));
|
||
data = disassemble_dwarf_expression (stream,
|
||
objfile->arch (),
|
||
addr_size, offset_size, data,
|
||
data, end, 0,
|
||
dwarf_always_disassemble,
|
||
per_cu, per_objfile);
|
||
}
|
||
|
||
if (data < end)
|
||
{
|
||
int empty = data == here;
|
||
|
||
if (disassemble)
|
||
gdb_printf (stream, " ");
|
||
if (data[0] == DW_OP_piece)
|
||
{
|
||
uint64_t bytes;
|
||
|
||
data = safe_read_uleb128 (data + 1, end, &bytes);
|
||
|
||
if (empty)
|
||
gdb_printf (stream, _("an empty %s-byte piece"),
|
||
pulongest (bytes));
|
||
else
|
||
gdb_printf (stream, _(" [%s-byte piece]"),
|
||
pulongest (bytes));
|
||
}
|
||
else if (data[0] == DW_OP_bit_piece)
|
||
{
|
||
uint64_t bits, offset;
|
||
|
||
data = safe_read_uleb128 (data + 1, end, &bits);
|
||
data = safe_read_uleb128 (data, end, &offset);
|
||
|
||
if (empty)
|
||
gdb_printf (stream,
|
||
_("an empty %s-bit piece"),
|
||
pulongest (bits));
|
||
else
|
||
gdb_printf (stream,
|
||
_(" [%s-bit piece, offset %s bits]"),
|
||
pulongest (bits), pulongest (offset));
|
||
}
|
||
else
|
||
{
|
||
bad = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bad || data > end)
|
||
error (_("Corrupted DWARF2 expression for \"%s\"."),
|
||
symbol->print_name ());
|
||
}
|
||
|
||
/* Print a natural-language description of SYMBOL to STREAM. This
|
||
version is for a symbol with a single location. */
|
||
|
||
static void
|
||
locexpr_describe_location (struct symbol *symbol, CORE_ADDR addr,
|
||
struct ui_file *stream)
|
||
{
|
||
struct dwarf2_locexpr_baton *dlbaton
|
||
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
unsigned int addr_size = dlbaton->per_cu->addr_size ();
|
||
int offset_size = dlbaton->per_cu->offset_size ();
|
||
|
||
locexpr_describe_location_1 (symbol, addr, stream,
|
||
dlbaton->data, dlbaton->size,
|
||
addr_size, offset_size,
|
||
dlbaton->per_cu, dlbaton->per_objfile);
|
||
}
|
||
|
||
/* Describe the location of SYMBOL as an agent value in VALUE, generating
|
||
any necessary bytecode in AX. */
|
||
|
||
static void
|
||
locexpr_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
|
||
struct axs_value *value)
|
||
{
|
||
struct dwarf2_locexpr_baton *dlbaton
|
||
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
unsigned int addr_size = dlbaton->per_cu->addr_size ();
|
||
|
||
if (dlbaton->size == 0)
|
||
value->optimized_out = 1;
|
||
else
|
||
dwarf2_compile_expr_to_ax (ax, value, addr_size, dlbaton->data,
|
||
dlbaton->data + dlbaton->size, dlbaton->per_cu,
|
||
dlbaton->per_objfile);
|
||
}
|
||
|
||
/* symbol_computed_ops 'generate_c_location' method. */
|
||
|
||
static void
|
||
locexpr_generate_c_location (struct symbol *sym, string_file *stream,
|
||
struct gdbarch *gdbarch,
|
||
std::vector<bool> ®isters_used,
|
||
CORE_ADDR pc, const char *result_name)
|
||
{
|
||
struct dwarf2_locexpr_baton *dlbaton
|
||
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (sym);
|
||
unsigned int addr_size = dlbaton->per_cu->addr_size ();
|
||
|
||
if (dlbaton->size == 0)
|
||
error (_("symbol \"%s\" is optimized out"), sym->natural_name ());
|
||
|
||
compile_dwarf_expr_to_c (stream, result_name,
|
||
sym, pc, gdbarch, registers_used, addr_size,
|
||
dlbaton->data, dlbaton->data + dlbaton->size,
|
||
dlbaton->per_cu, dlbaton->per_objfile);
|
||
}
|
||
|
||
/* The set of location functions used with the DWARF-2 expression
|
||
evaluator. */
|
||
const struct symbol_computed_ops dwarf2_locexpr_funcs = {
|
||
locexpr_read_variable,
|
||
locexpr_read_variable_at_entry,
|
||
locexpr_get_symbol_read_needs,
|
||
locexpr_describe_location,
|
||
0, /* location_has_loclist */
|
||
locexpr_tracepoint_var_ref,
|
||
locexpr_generate_c_location
|
||
};
|
||
|
||
|
||
/* Wrapper functions for location lists. These generally find
|
||
the appropriate location expression and call something above. */
|
||
|
||
/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
|
||
evaluator to calculate the location. */
|
||
static struct value *
|
||
loclist_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
|
||
{
|
||
struct dwarf2_loclist_baton *dlbaton
|
||
= (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
struct value *val;
|
||
const gdb_byte *data;
|
||
size_t size;
|
||
CORE_ADDR pc = frame ? get_frame_address_in_block (frame) : 0;
|
||
|
||
data = dwarf2_find_location_expression (dlbaton, &size, pc);
|
||
val = dwarf2_evaluate_loc_desc (symbol->type (), frame, data, size,
|
||
dlbaton->per_cu, dlbaton->per_objfile);
|
||
|
||
return val;
|
||
}
|
||
|
||
/* Read variable SYMBOL like loclist_read_variable at (callee) FRAME's function
|
||
entry. SYMBOL should be a function parameter, otherwise NO_ENTRY_VALUE_ERROR
|
||
will be thrown.
|
||
|
||
Function always returns non-NULL value, it may be marked optimized out if
|
||
inferior frame information is not available. It throws NO_ENTRY_VALUE_ERROR
|
||
if it cannot resolve the parameter for any reason. */
|
||
|
||
static struct value *
|
||
loclist_read_variable_at_entry (struct symbol *symbol, const frame_info_ptr &frame)
|
||
{
|
||
struct dwarf2_loclist_baton *dlbaton
|
||
= (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
const gdb_byte *data;
|
||
size_t size;
|
||
CORE_ADDR pc;
|
||
|
||
if (frame == NULL || !get_frame_func_if_available (frame, &pc))
|
||
return value::allocate_optimized_out (symbol->type ());
|
||
|
||
data = dwarf2_find_location_expression (dlbaton, &size, pc, true);
|
||
if (data == NULL)
|
||
return value::allocate_optimized_out (symbol->type ());
|
||
|
||
return value_of_dwarf_block_entry (symbol->type (), frame, data, size);
|
||
}
|
||
|
||
/* Implementation of get_symbol_read_needs from
|
||
symbol_computed_ops. */
|
||
|
||
static enum symbol_needs_kind
|
||
loclist_symbol_needs (struct symbol *symbol)
|
||
{
|
||
/* If there's a location list, then assume we need to have a frame
|
||
to choose the appropriate location expression. With tracking of
|
||
global variables this is not necessarily true, but such tracking
|
||
is disabled in GCC at the moment until we figure out how to
|
||
represent it. */
|
||
|
||
return SYMBOL_NEEDS_FRAME;
|
||
}
|
||
|
||
/* Print a natural-language description of SYMBOL to STREAM. This
|
||
version applies when there is a list of different locations, each
|
||
with a specified address range. */
|
||
|
||
static void
|
||
loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
|
||
struct ui_file *stream)
|
||
{
|
||
struct dwarf2_loclist_baton *dlbaton
|
||
= (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
const gdb_byte *loc_ptr, *buf_end;
|
||
dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
|
||
struct objfile *objfile = per_objfile->objfile;
|
||
struct gdbarch *gdbarch = objfile->arch ();
|
||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||
unsigned int addr_size = dlbaton->per_cu->addr_size ();
|
||
int offset_size = dlbaton->per_cu->offset_size ();
|
||
int signed_addr_p = bfd_get_sign_extend_vma (objfile->obfd.get ());
|
||
unrelocated_addr base_address = dlbaton->base_address;
|
||
int done = 0;
|
||
|
||
loc_ptr = dlbaton->data;
|
||
buf_end = dlbaton->data + dlbaton->size;
|
||
|
||
gdb_printf (stream, _("multi-location:\n"));
|
||
|
||
/* Iterate through locations until we run out. */
|
||
while (!done)
|
||
{
|
||
unrelocated_addr low = {}, high = {}; /* init for gcc -Wall */
|
||
int length;
|
||
enum debug_loc_kind kind;
|
||
const gdb_byte *new_ptr = NULL; /* init for gcc -Wall */
|
||
|
||
if (dlbaton->per_cu->version () < 5 && dlbaton->from_dwo)
|
||
kind = decode_debug_loc_dwo_addresses (dlbaton->per_cu,
|
||
per_objfile,
|
||
loc_ptr, buf_end, &new_ptr,
|
||
&low, &high, byte_order);
|
||
else if (dlbaton->per_cu->version () < 5)
|
||
kind = decode_debug_loc_addresses (loc_ptr, buf_end, &new_ptr,
|
||
&low, &high,
|
||
byte_order, addr_size,
|
||
signed_addr_p);
|
||
else
|
||
kind = decode_debug_loclists_addresses (dlbaton->per_cu,
|
||
per_objfile,
|
||
loc_ptr, buf_end, &new_ptr,
|
||
&low, &high, byte_order,
|
||
addr_size, signed_addr_p);
|
||
loc_ptr = new_ptr;
|
||
switch (kind)
|
||
{
|
||
case DEBUG_LOC_END_OF_LIST:
|
||
done = 1;
|
||
continue;
|
||
|
||
case DEBUG_LOC_BASE_ADDRESS:
|
||
base_address = high;
|
||
gdb_printf (stream, _(" Base address %s"),
|
||
paddress (gdbarch, (CORE_ADDR) base_address));
|
||
continue;
|
||
|
||
case DEBUG_LOC_START_END:
|
||
case DEBUG_LOC_START_LENGTH:
|
||
case DEBUG_LOC_OFFSET_PAIR:
|
||
break;
|
||
|
||
case DEBUG_LOC_BUFFER_OVERFLOW:
|
||
case DEBUG_LOC_INVALID_ENTRY:
|
||
error (_("Corrupted DWARF expression for symbol \"%s\"."),
|
||
symbol->print_name ());
|
||
|
||
default:
|
||
gdb_assert_not_reached ("bad debug_loc_kind");
|
||
}
|
||
|
||
/* Otherwise, a location expression entry. */
|
||
if (!dlbaton->from_dwo && kind == DEBUG_LOC_OFFSET_PAIR)
|
||
{
|
||
low = (unrelocated_addr) ((CORE_ADDR) low
|
||
+ (CORE_ADDR) base_address);
|
||
high = (unrelocated_addr) ((CORE_ADDR) high
|
||
+ (CORE_ADDR) base_address);
|
||
}
|
||
|
||
CORE_ADDR low_reloc = per_objfile->relocate (low);
|
||
CORE_ADDR high_reloc = per_objfile->relocate (high);
|
||
|
||
if (dlbaton->per_cu->version () < 5)
|
||
{
|
||
length = extract_unsigned_integer (loc_ptr, 2, byte_order);
|
||
loc_ptr += 2;
|
||
}
|
||
else
|
||
{
|
||
unsigned int bytes_read;
|
||
length = read_unsigned_leb128 (NULL, loc_ptr, &bytes_read);
|
||
loc_ptr += bytes_read;
|
||
}
|
||
|
||
/* (It would improve readability to print only the minimum
|
||
necessary digits of the second number of the range.) */
|
||
gdb_printf (stream, _(" Range %s-%s: "),
|
||
paddress (gdbarch, low_reloc),
|
||
paddress (gdbarch, high_reloc));
|
||
|
||
/* Now describe this particular location. */
|
||
locexpr_describe_location_1 (symbol, low_reloc, stream, loc_ptr, length,
|
||
addr_size, offset_size,
|
||
dlbaton->per_cu, per_objfile);
|
||
|
||
gdb_printf (stream, "\n");
|
||
|
||
loc_ptr += length;
|
||
}
|
||
}
|
||
|
||
/* Describe the location of SYMBOL as an agent value in VALUE, generating
|
||
any necessary bytecode in AX. */
|
||
static void
|
||
loclist_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
|
||
struct axs_value *value)
|
||
{
|
||
struct dwarf2_loclist_baton *dlbaton
|
||
= (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
|
||
const gdb_byte *data;
|
||
size_t size;
|
||
unsigned int addr_size = dlbaton->per_cu->addr_size ();
|
||
|
||
data = dwarf2_find_location_expression (dlbaton, &size, ax->scope);
|
||
if (size == 0)
|
||
value->optimized_out = 1;
|
||
else
|
||
dwarf2_compile_expr_to_ax (ax, value, addr_size, data, data + size,
|
||
dlbaton->per_cu, dlbaton->per_objfile);
|
||
}
|
||
|
||
/* symbol_computed_ops 'generate_c_location' method. */
|
||
|
||
static void
|
||
loclist_generate_c_location (struct symbol *sym, string_file *stream,
|
||
struct gdbarch *gdbarch,
|
||
std::vector<bool> ®isters_used,
|
||
CORE_ADDR pc, const char *result_name)
|
||
{
|
||
struct dwarf2_loclist_baton *dlbaton
|
||
= (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (sym);
|
||
unsigned int addr_size = dlbaton->per_cu->addr_size ();
|
||
const gdb_byte *data;
|
||
size_t size;
|
||
|
||
data = dwarf2_find_location_expression (dlbaton, &size, pc);
|
||
if (size == 0)
|
||
error (_("symbol \"%s\" is optimized out"), sym->natural_name ());
|
||
|
||
compile_dwarf_expr_to_c (stream, result_name,
|
||
sym, pc, gdbarch, registers_used, addr_size,
|
||
data, data + size,
|
||
dlbaton->per_cu,
|
||
dlbaton->per_objfile);
|
||
}
|
||
|
||
/* The set of location functions used with the DWARF-2 expression
|
||
evaluator and location lists. */
|
||
const struct symbol_computed_ops dwarf2_loclist_funcs = {
|
||
loclist_read_variable,
|
||
loclist_read_variable_at_entry,
|
||
loclist_symbol_needs,
|
||
loclist_describe_location,
|
||
1, /* location_has_loclist */
|
||
loclist_tracepoint_var_ref,
|
||
loclist_generate_c_location
|
||
};
|
||
|
||
void _initialize_dwarf2loc ();
|
||
void
|
||
_initialize_dwarf2loc ()
|
||
{
|
||
add_setshow_zuinteger_cmd ("entry-values", class_maintenance,
|
||
&entry_values_debug,
|
||
_("\
|
||
Set entry values and tail call frames debugging."),
|
||
_("\
|
||
Show entry values and tail call frames debugging."),
|
||
_("\
|
||
When non-zero, the process of determining parameter values from\n\
|
||
function entry point and tail call frames will be printed."),
|
||
NULL,
|
||
show_entry_values_debug,
|
||
&setdebuglist, &showdebuglist);
|
||
|
||
add_setshow_boolean_cmd ("always-disassemble", class_obscure,
|
||
&dwarf_always_disassemble, _("\
|
||
Set whether `info address' always disassembles DWARF expressions."), _("\
|
||
Show whether `info address' always disassembles DWARF expressions."), _("\
|
||
When enabled, DWARF expressions are always printed in an assembly-like\n\
|
||
syntax. When disabled, expressions will be printed in a more\n\
|
||
conversational style, when possible."),
|
||
NULL,
|
||
show_dwarf_always_disassemble,
|
||
&set_dwarf_cmdlist,
|
||
&show_dwarf_cmdlist);
|
||
}
|