mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 01:33:06 +00:00
libdrgn: dwarf_info_cache: handle variables DW_AT_const_value
Compile-time constants have DW_AT_const_value instead of DW_AT_location. We can translate those to a value object. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
213c148ce6
commit
6d4af7e17e
@ -10,6 +10,7 @@
|
||||
#include "dwarf_index.h"
|
||||
#include "dwarf_info_cache.h"
|
||||
#include "hash_table.h"
|
||||
#include "object.h"
|
||||
#include "object_index.h"
|
||||
#include "type_index.h"
|
||||
#include "vector.h"
|
||||
@ -1528,6 +1529,55 @@ drgn_object_from_dwarf_subprogram(struct drgn_dwarf_info_cache *dicache,
|
||||
0, byte_order);
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
drgn_object_from_dwarf_constant(struct drgn_dwarf_info_cache *dicache,
|
||||
Dwarf_Die *die,
|
||||
struct drgn_qualified_type qualified_type,
|
||||
Dwarf_Attribute *attr, struct drgn_object *ret)
|
||||
{
|
||||
struct drgn_object_type type;
|
||||
enum drgn_object_kind kind;
|
||||
uint64_t bit_size;
|
||||
struct drgn_error *err = drgn_object_set_common(qualified_type, 0,
|
||||
&type, &kind,
|
||||
&bit_size);
|
||||
if (err)
|
||||
return err;
|
||||
Dwarf_Block block;
|
||||
if (dwarf_formblock(attr, &block) == 0) {
|
||||
bool little_endian;
|
||||
err = dwarf_die_is_little_endian(die, true, &little_endian);
|
||||
if (err)
|
||||
return err;
|
||||
if (block.length < drgn_value_size(bit_size, 0)) {
|
||||
return drgn_error_create(DRGN_ERROR_OTHER,
|
||||
"DW_AT_const_value block is too small");
|
||||
}
|
||||
return drgn_object_set_buffer_internal(ret, &type, kind,
|
||||
bit_size, block.data, 0,
|
||||
little_endian);
|
||||
} else if (kind == DRGN_OBJECT_SIGNED) {
|
||||
Dwarf_Sword svalue;
|
||||
if (dwarf_formsdata(attr, &svalue)) {
|
||||
return drgn_error_create(DRGN_ERROR_OTHER,
|
||||
"invalid DW_AT_const_value");
|
||||
}
|
||||
return drgn_object_set_signed_internal(ret, &type, bit_size,
|
||||
svalue);
|
||||
} else if (kind == DRGN_OBJECT_UNSIGNED) {
|
||||
Dwarf_Word uvalue;
|
||||
if (dwarf_formudata(attr, &uvalue)) {
|
||||
return drgn_error_create(DRGN_ERROR_OTHER,
|
||||
"invalid DW_AT_const_value");
|
||||
}
|
||||
return drgn_object_set_unsigned_internal(ret, &type, bit_size,
|
||||
uvalue);
|
||||
} else {
|
||||
return drgn_error_create(DRGN_ERROR_OTHER,
|
||||
"unknown DW_AT_const_value form");
|
||||
}
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
drgn_object_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache,
|
||||
Dwarf_Die *die, uint64_t bias, const char *name,
|
||||
@ -1541,26 +1591,32 @@ drgn_object_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache,
|
||||
if (err)
|
||||
return err;
|
||||
Dwarf_Attribute attr_mem, *attr;
|
||||
if (!(attr = dwarf_attr_integrate(die, DW_AT_location, &attr_mem))) {
|
||||
if ((attr = dwarf_attr_integrate(die, DW_AT_location, &attr_mem))) {
|
||||
Dwarf_Op *loc;
|
||||
size_t nloc;
|
||||
if (dwarf_getlocation(attr, &loc, &nloc))
|
||||
return drgn_error_libdw();
|
||||
if (nloc != 1 || loc[0].atom != DW_OP_addr) {
|
||||
return drgn_error_create(DRGN_ERROR_OTHER,
|
||||
"DW_AT_location has unimplemented operation");
|
||||
}
|
||||
enum drgn_byte_order byte_order;
|
||||
err = dwarf_die_byte_order(die, true, &byte_order);
|
||||
if (err)
|
||||
return err;
|
||||
return drgn_object_set_reference(ret, qualified_type,
|
||||
loc[0].number + bias, 0, 0,
|
||||
byte_order);
|
||||
} else if ((attr = dwarf_attr_integrate(die, DW_AT_const_value,
|
||||
&attr_mem))) {
|
||||
return drgn_object_from_dwarf_constant(dicache, die,
|
||||
qualified_type, attr,
|
||||
ret);
|
||||
} else {
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find address of '%s'",
|
||||
"could not find address or value of '%s'",
|
||||
name);
|
||||
}
|
||||
Dwarf_Op *loc;
|
||||
size_t nloc;
|
||||
if (dwarf_getlocation(attr, &loc, &nloc))
|
||||
return drgn_error_libdw();
|
||||
if (nloc != 1 || loc[0].atom != DW_OP_addr) {
|
||||
return drgn_error_create(DRGN_ERROR_OTHER,
|
||||
"DW_AT_location has unimplemented operation");
|
||||
}
|
||||
enum drgn_byte_order byte_order;
|
||||
err = dwarf_die_byte_order(die, true, &byte_order);
|
||||
if (err)
|
||||
return err;
|
||||
return drgn_object_set_reference(ret, qualified_type,
|
||||
loc[0].number + bias, 0, 0,
|
||||
byte_order);
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
|
@ -104,7 +104,7 @@ drgn_object_set_common(struct drgn_qualified_type qualified_type,
|
||||
return drgn_object_type_kind_and_size(type_ret, kind_ret, bit_size_ret);
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
struct drgn_error *
|
||||
drgn_object_set_signed_internal(struct drgn_object *res,
|
||||
const struct drgn_object_type *type,
|
||||
uint64_t bit_size, int64_t svalue)
|
||||
@ -140,7 +140,7 @@ drgn_object_set_signed(struct drgn_object *res,
|
||||
return drgn_object_set_signed_internal(res, &type, bit_size, svalue);
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
struct drgn_error *
|
||||
drgn_object_set_unsigned_internal(struct drgn_object *res,
|
||||
const struct drgn_object_type *type,
|
||||
uint64_t bit_size, uint64_t uvalue)
|
||||
@ -296,7 +296,7 @@ drgn_byte_order_to_little_endian(struct drgn_program *prog,
|
||||
}
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
struct drgn_error *
|
||||
drgn_object_set_buffer_internal(struct drgn_object *res,
|
||||
const struct drgn_object_type *type,
|
||||
enum drgn_object_kind kind, uint64_t bit_size,
|
||||
|
@ -129,6 +129,35 @@ struct drgn_error *sanity_check_object(enum drgn_object_kind kind,
|
||||
uint64_t bit_field_size,
|
||||
uint64_t bit_size);
|
||||
|
||||
/**
|
||||
* Like @ref drgn_object_set_signed() but @ref drgn_object_set_common() was
|
||||
* already called.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_object_set_signed_internal(struct drgn_object *res,
|
||||
const struct drgn_object_type *type,
|
||||
uint64_t bit_size, int64_t svalue);
|
||||
|
||||
/**
|
||||
* Like @ref drgn_object_set_unsigned() but @ref drgn_object_set_common() was
|
||||
* already called.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_object_set_unsigned_internal(struct drgn_object *res,
|
||||
const struct drgn_object_type *type,
|
||||
uint64_t bit_size, uint64_t uvalue);
|
||||
|
||||
/**
|
||||
* Like @ref drgn_object_set_buffer() but @ref drgn_object_set_common() was
|
||||
* already called.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_object_set_buffer_internal(struct drgn_object *res,
|
||||
const struct drgn_object_type *type,
|
||||
enum drgn_object_kind kind, uint64_t bit_size,
|
||||
const void *buf, uint8_t bit_offset,
|
||||
bool little_endian);
|
||||
|
||||
/** Convert a @ref drgn_byte_order to a boolean. */
|
||||
struct drgn_error *
|
||||
drgn_byte_order_to_little_endian(struct drgn_program *prog,
|
||||
|
@ -90,10 +90,19 @@ def _compile_debug_info(cu_die, little_endian, bits):
|
||||
buf.extend(value.to_bytes(bits // 8, byteorder))
|
||||
elif attrib.form == DW_FORM.data1:
|
||||
buf.append(value)
|
||||
elif attrib.form == DW_FORM.data2:
|
||||
buf.extend(value.to_bytes(2, byteorder))
|
||||
elif attrib.form == DW_FORM.data4:
|
||||
buf.extend(value.to_bytes(4, byteorder))
|
||||
elif attrib.form == DW_FORM.data8:
|
||||
buf.extend(value.to_bytes(8, byteorder))
|
||||
elif attrib.form == DW_FORM.udata:
|
||||
_append_uleb128(buf, value)
|
||||
elif attrib.form == DW_FORM.sdata:
|
||||
_append_sleb128(buf, value)
|
||||
elif attrib.form == DW_FORM.block1:
|
||||
buf.append(len(value))
|
||||
buf.extend(value)
|
||||
elif attrib.form == DW_FORM.string:
|
||||
buf.extend(value.encode())
|
||||
buf.append(0)
|
||||
|
@ -2033,12 +2033,114 @@ class TestObjects(ObjectTestCase):
|
||||
|
||||
del dies[1].attribs[2]
|
||||
prog = dwarf_program(dies)
|
||||
self.assertRaisesRegex(LookupError, "could not find address", prog.object, "x")
|
||||
self.assertRaisesRegex(
|
||||
LookupError, "could not find address or value", prog.object, "x"
|
||||
)
|
||||
|
||||
dies[1].attribs.insert(2, DwarfAttrib(DW_AT.location, DW_FORM.exprloc, b"\xe0"))
|
||||
prog = dwarf_program(dies)
|
||||
self.assertRaisesRegex(Exception, "unimplemented operation", prog.object, "x")
|
||||
|
||||
def test_const_signed(self):
|
||||
for form in (
|
||||
DW_FORM.data1,
|
||||
DW_FORM.data2,
|
||||
DW_FORM.data4,
|
||||
DW_FORM.data8,
|
||||
DW_FORM.sdata,
|
||||
):
|
||||
dies = [
|
||||
int_die,
|
||||
DwarfDie(
|
||||
DW_TAG.variable,
|
||||
[
|
||||
DwarfAttrib(DW_AT.name, DW_FORM.string, "x"),
|
||||
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 0),
|
||||
DwarfAttrib(DW_AT.const_value, form, 1,),
|
||||
],
|
||||
),
|
||||
]
|
||||
prog = dwarf_program(dies)
|
||||
self.assertEqual(
|
||||
prog["x"], Object(prog, int_type("int", 4, True), 1),
|
||||
)
|
||||
|
||||
def test_const_unsigned(self):
|
||||
for form in (
|
||||
DW_FORM.data1,
|
||||
DW_FORM.data2,
|
||||
DW_FORM.data4,
|
||||
DW_FORM.data8,
|
||||
DW_FORM.udata,
|
||||
):
|
||||
dies = [
|
||||
unsigned_int_die,
|
||||
DwarfDie(
|
||||
DW_TAG.variable,
|
||||
[
|
||||
DwarfAttrib(DW_AT.name, DW_FORM.string, "x"),
|
||||
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 0),
|
||||
DwarfAttrib(DW_AT.const_value, form, 1),
|
||||
],
|
||||
),
|
||||
]
|
||||
prog = dwarf_program(dies)
|
||||
self.assertEqual(
|
||||
prog["x"], Object(prog, int_type("unsigned int", 4, False), 1),
|
||||
)
|
||||
|
||||
def test_const_block(self):
|
||||
dies = [
|
||||
int_die,
|
||||
DwarfDie(
|
||||
DW_TAG.structure_type,
|
||||
[
|
||||
DwarfAttrib(DW_AT.name, DW_FORM.string, "point"),
|
||||
DwarfAttrib(DW_AT.byte_size, DW_FORM.data1, 8),
|
||||
],
|
||||
[
|
||||
DwarfDie(
|
||||
DW_TAG.member,
|
||||
[
|
||||
DwarfAttrib(DW_AT.name, DW_FORM.string, "x"),
|
||||
DwarfAttrib(DW_AT.data_member_location, DW_FORM.data1, 0),
|
||||
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 0),
|
||||
],
|
||||
),
|
||||
DwarfDie(
|
||||
DW_TAG.member,
|
||||
[
|
||||
DwarfAttrib(DW_AT.name, DW_FORM.string, "y"),
|
||||
DwarfAttrib(DW_AT.data_member_location, DW_FORM.data1, 4),
|
||||
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 0),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
DwarfDie(
|
||||
DW_TAG.variable,
|
||||
[
|
||||
DwarfAttrib(DW_AT.name, DW_FORM.string, "p"),
|
||||
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 1),
|
||||
DwarfAttrib(
|
||||
DW_AT.const_value,
|
||||
DW_FORM.block1,
|
||||
b"\x01\x00\x00\x00\x02\x00\x00\x00",
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
prog = dwarf_program(dies)
|
||||
self.assertEqual(
|
||||
prog["p"], Object(prog, point_type, {"x": 1, "y": 2}),
|
||||
)
|
||||
|
||||
dies[2].attribs[2] = DwarfAttrib(
|
||||
DW_AT.const_value, DW_FORM.block1, b"\x01\x00\x00\x00\x02\x00\x00",
|
||||
)
|
||||
prog = dwarf_program(dies)
|
||||
self.assertRaisesRegex(Exception, "too small", prog.variable, "p")
|
||||
|
||||
def test_not_found(self):
|
||||
prog = dwarf_program([int_die])
|
||||
self.assertRaisesRegex(LookupError, "could not find", prog.object, "y")
|
||||
|
Loading…
Reference in New Issue
Block a user