Skip to content

Commit

Permalink
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
Delphix Engineering committed Sep 17, 2024
2 parents bdd482e + a8e2e17 commit 5ec2aff
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 18 deletions.
36 changes: 27 additions & 9 deletions libdrgn/dwarf_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,14 @@ enum drgn_dwarf_index_abbrev_insn {
* The byte after INSN_END contains the DIE flags, which are a bitmask
* of flags combined with the drgn_dwarf_index_tag.
*/
INSN_DIE_FLAG_TAG_MASK = 0x3f,
INSN_DIE_FLAG_TAG_MASK = 0x1f,
/*
* DIE has a DW_AT_inline attribute (which may be DW_INL_not_inlined or
* DW_INL_declared_not_inlined). We use this to decide whether to look
* for a concrete out-of-line instance of an abstract instance root, so
* false positives are okay.
*/
INSN_DIE_FLAG_MAYBE_INLINED = 0x20,
/* DIE is a declaration. */
INSN_DIE_FLAG_DECLARATION = 0x40,
/* DIE has children. */
Expand Down Expand Up @@ -899,7 +906,7 @@ dw_at_specification_to_insn(struct drgn_dwarf_index_cu *cu,
return NULL;
default:
return binary_buffer_error(bb,
"unknown attribute form %#" PRIx64 " for DW_AT_specification",
"unknown attribute form %#" PRIx64 " for DW_AT_specification or DW_AT_abstract_origin",
form);
}
}
Expand Down Expand Up @@ -964,10 +971,15 @@ read_abbrev_decl(struct drgn_elf_file_section_buffer *buffer,
} else if (name == DW_AT_declaration && should_index) {
err = dw_at_declaration_to_insn(&buffer->bb, form,
&insn, &die_flags);
} else if (name == DW_AT_specification && should_index) {
} else if (should_index
&& (name == DW_AT_specification
|| (tag == DW_TAG_subprogram
&& name == DW_AT_abstract_origin))) {
err = dw_at_specification_to_insn(cu, &buffer->bb, form,
&insn);
} else {
if (tag == DW_TAG_subprogram && name == DW_AT_inline)
die_flags |= INSN_DIE_FLAG_MAYBE_INLINED;
err = dw_form_to_insn(cu, &buffer->bb, form, &insn);
}
if (err)
Expand Down Expand Up @@ -1096,8 +1108,8 @@ static struct drgn_error *read_indirect_insn(struct drgn_dwarf_index_cu *cu,
}

/*
* First pass: index DIEs with DW_AT_specification. This recurses into
* namespaces.
* First pass: index DIEs with DW_AT_specification and DW_AT_abstract_origin.
* This recurses into namespaces.
*/
static struct drgn_error *
index_cu_first_pass(struct drgn_dwarf_specification_map *specifications,
Expand Down Expand Up @@ -1333,12 +1345,13 @@ indirect_insn:;
}

/**
* Find a definition corresponding to a declaration DIE.
* Find the address of a top-level DIE with a @c DW_AT_specification or @c
* DW_AT_abstract_origin attribute that refers to the given DIE address.
*
* This finds the address of a DIE with a @c DW_AT_specification attribute that
* refers to the given address.
* This can be used to find the definition of a declaration or the concrete
* out-of-line instance of an abstract instance root.
*
* @param[in] die_addr The address of the declaration DIE.
* @param[in] die_addr Address of a DIE.
* @param[out] ret Returned address of the definition DIE.
* @return @c true if a definition DIE was found, @c false if not (in which case
* `*ret` is not modified).
Expand Down Expand Up @@ -1651,6 +1664,11 @@ indirect_insn:;
goto next;
}

if (insn & INSN_DIE_FLAG_MAYBE_INLINED) {
drgn_dwarf_find_definition(dbinfo, die_addr,
&die_addr);
}

if (!index_die(map, base_types, name, tag, die_addr))
return &drgn_enomem;
}
Expand Down
7 changes: 3 additions & 4 deletions libdrgn/dwarf_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,9 @@ struct drgn_dwarf_info {
*/
struct drgn_dwarf_base_type_map base_types;
/**
* Map from the address of a (usually non-defining) DIE to the address
* of a DIE with a DW_AT_specification attribute that references it.
* This is used to resolve DIEs with DW_AT_declaration to their
* definition.
* Map from the address of a DIE to the address of a top-level DIE with
* a `DW_AT_specification` or `DW_AT_abstract_origin` attribute that
* refers to it.
*/
struct drgn_dwarf_specification_map specifications;
/** Indexed compilation units. */
Expand Down
2 changes: 1 addition & 1 deletion libdrgn/python/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ static DrgnObject *DrgnObject_new(PyTypeObject *subtype, PyObject *args,
return NULL;
} else if (ret) {
PyErr_Format(PyExc_TypeError,
"cannot create %s literal",
"literal must be int, float, or bool, not '%s'",
Py_TYPE(value_obj)->tp_name);
return NULL;
}
Expand Down
80 changes: 77 additions & 3 deletions tests/test_dwarf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,17 @@
identical,
)
import tests.assembler as assembler
from tests.dwarf import DW_AT, DW_ATE, DW_END, DW_FORM, DW_LANG, DW_OP, DW_TAG, DW_UT
from tests.dwarf import (
DW_AT,
DW_ATE,
DW_END,
DW_FORM,
DW_INL,
DW_LANG,
DW_OP,
DW_TAG,
DW_UT,
)
from tests.dwarfwriter import (
DwarfAttrib,
DwarfDie,
Expand Down Expand Up @@ -4455,7 +4465,10 @@ def test_function(self):
(
DwarfDie(
DW_TAG.formal_parameter,
(DwarfAttrib(DW_AT.type, DW_FORM.ref4, "int_die"),),
(
DwarfAttrib(DW_AT.name, DW_FORM.string, "x"),
DwarfAttrib(DW_AT.type, DW_FORM.ref4, "int_die"),
),
),
),
),
Expand All @@ -4467,7 +4480,7 @@ def test_function(self):
prog,
prog.function_type(
prog.int_type("int", 4, True),
(TypeParameter(prog.int_type("int", 4, True)),),
(TypeParameter(prog.int_type("int", 4, True), "x"),),
False,
),
address=0x7FC3EB9B1C30,
Expand Down Expand Up @@ -4495,6 +4508,67 @@ def test_function_no_address(self):
prog.object("abort"), Object(prog, prog.function_type(prog.void_type(), ()))
)

def test_function_concrete_out_of_line_instance(self):
prog = dwarf_program(
wrap_test_type_dies(
*labeled_int_die,
DwarfLabel("abstract_instance_root"),
DwarfDie(
DW_TAG.subprogram,
(
DwarfAttrib(DW_AT.name, DW_FORM.string, "abs"),
DwarfAttrib(DW_AT.type, DW_FORM.ref4, "int_die"),
DwarfAttrib(DW_AT.inline, DW_FORM.data1, DW_INL.inlined),
),
(
DwarfLabel("abstract_instance_parameter"),
DwarfDie(
DW_TAG.formal_parameter,
(
DwarfAttrib(DW_AT.name, DW_FORM.string, "x"),
DwarfAttrib(DW_AT.type, DW_FORM.ref4, "int_die"),
),
),
),
),
DwarfDie(
DW_TAG.subprogram,
(
DwarfAttrib(
DW_AT.abstract_origin,
DW_FORM.ref4,
"abstract_instance_root",
),
DwarfAttrib(DW_AT.low_pc, DW_FORM.addr, 0x7FC3EB9B1C30),
),
(
DwarfDie(
DW_TAG.formal_parameter,
(
DwarfAttrib(
DW_AT.abstract_origin,
DW_FORM.ref4,
"abstract_instance_parameter",
),
),
),
),
),
)
)
self.assertIdentical(
prog["abs"],
Object(
prog,
prog.function_type(
prog.int_type("int", 4, True),
(TypeParameter(prog.int_type("int", 4, True), "x"),),
False,
),
address=0x7FC3EB9B1C30,
),
)

def test_variable(self):
prog = dwarf_program(
wrap_test_type_dies(
Expand Down
6 changes: 5 additions & 1 deletion tests/test_language_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,11 @@ class Foo:
pass

self.assertRaisesRegex(
TypeError, "cannot create Foo literal", Object, self.prog, value=Foo()
TypeError,
"literal must be int, float, or bool, not 'Foo'",
Object,
self.prog,
value=Foo(),
)


Expand Down

0 comments on commit 5ec2aff

Please sign in to comment.