mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
1628e02267
Approved-By: Tom Tromey <tom@tromey.com>
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 funtion 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 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);
|
||
}
|