Compare commits
10 Commits
main
...
jr/more-th
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3ebd42802 | ||
|
|
d8b9f45a24 | ||
|
|
35e555ae39 | ||
|
|
4c5d4a5ee4 | ||
|
|
530954e69f | ||
|
|
89a7afaded | ||
|
|
91a719e534 | ||
|
|
e80a11d730 | ||
|
|
f135232933 | ||
|
|
f0bedd4104 |
@ -120,13 +120,13 @@ namespace libdwarf {
|
|||||||
int
|
int
|
||||||
>::type = 0
|
>::type = 0
|
||||||
>
|
>
|
||||||
int wrap(int (*f)(Args...), Args2&&... args) const {
|
Result<int, internal_error> wrap(int (*f)(Args...), Args2&&... args) const {
|
||||||
Dwarf_Error error = nullptr;
|
Dwarf_Error error = nullptr;
|
||||||
int ret = f(std::forward<Args2>(args)..., &error);
|
int ret = f(std::forward<Args2>(args)..., &error);
|
||||||
if(ret == DW_DLV_ERROR) {
|
if(ret == DW_DLV_ERROR) {
|
||||||
handle_dwarf_error(dbg, error);
|
return handle_dwarf_error(dbg, error);
|
||||||
}
|
}
|
||||||
return ret;
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -178,14 +178,17 @@ namespace libdwarf {
|
|||||||
nullptr,
|
nullptr,
|
||||||
&dbg
|
&dbg
|
||||||
);
|
);
|
||||||
if(ret == DW_DLV_OK) {
|
if(!ret) {
|
||||||
|
ret.drop_error();
|
||||||
|
ok = false;
|
||||||
|
} else if(ret.unwrap_value() == DW_DLV_OK) {
|
||||||
ok = true;
|
ok = true;
|
||||||
} else if(ret == DW_DLV_NO_ENTRY) {
|
} else if(ret.unwrap_value() == DW_DLV_NO_ENTRY) {
|
||||||
// fail, no debug info
|
// fail, no debug info
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
ok = false;
|
ok = false;
|
||||||
PANIC("Unknown return code from dwarf_init_path");
|
ASSERT(false, "Unknown return code from dwarf_init_path");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
@ -256,7 +259,7 @@ namespace libdwarf {
|
|||||||
Dwarf_Unsigned next_cu_header;
|
Dwarf_Unsigned next_cu_header;
|
||||||
Dwarf_Half header_cu_type;
|
Dwarf_Half header_cu_type;
|
||||||
while(true) {
|
while(true) {
|
||||||
int ret = wrap(
|
auto ret = wrap(
|
||||||
dwarf_next_cu_header_d,
|
dwarf_next_cu_header_d,
|
||||||
dbg,
|
dbg,
|
||||||
true,
|
true,
|
||||||
@ -271,20 +274,29 @@ namespace libdwarf {
|
|||||||
&next_cu_header,
|
&next_cu_header,
|
||||||
&header_cu_type
|
&header_cu_type
|
||||||
);
|
);
|
||||||
if(ret == DW_DLV_NO_ENTRY) {
|
if(!ret) {
|
||||||
|
ret.drop_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(ret.unwrap_value() == DW_DLV_NO_ENTRY) {
|
||||||
if(dump_dwarf) {
|
if(dump_dwarf) {
|
||||||
std::fprintf(stderr, "End walk_dbg\n");
|
std::fprintf(stderr, "End walk_dbg\n");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(ret != DW_DLV_OK) {
|
if(ret.unwrap_value() != DW_DLV_OK) {
|
||||||
PANIC("Unexpected return code from dwarf_next_cu_header_d");
|
ASSERT(false, "Unexpected return code from dwarf_next_cu_header_d");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 0 passed as the die to the first call of dwarf_siblingof_b immediately after dwarf_next_cu_header_d
|
// 0 passed as the die to the first call of dwarf_siblingof_b immediately after dwarf_next_cu_header_d
|
||||||
// to fetch the cu die
|
// to fetch the cu die
|
||||||
die_object cu_die(dbg, nullptr);
|
die_object cu_die(dbg, nullptr);
|
||||||
cu_die = cu_die.get_sibling();
|
auto sibling = cu_die.get_sibling();
|
||||||
|
if(sibling.is_error()) {
|
||||||
|
sibling.drop_error();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cu_die = std::move(sibling).unwrap_value();
|
||||||
if(!cu_die) {
|
if(!cu_die) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -304,8 +316,17 @@ namespace libdwarf {
|
|||||||
Dwarf_Half dwversion = 0;
|
Dwarf_Half dwversion = 0;
|
||||||
dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size);
|
dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size);
|
||||||
auto ranges_vec = cu_die.get_rangelist_entries(dwversion);
|
auto ranges_vec = cu_die.get_rangelist_entries(dwversion);
|
||||||
for(auto range : ranges_vec) {
|
if(!ranges_vec) {
|
||||||
cu_cache.push_back({ cu_die.clone(), dwversion, range.first, range.second });
|
ranges_vec.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for(auto range : ranges_vec.unwrap_value()) {
|
||||||
|
auto cu = cu_die.clone();
|
||||||
|
if(!cu) {
|
||||||
|
ranges_vec.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cu_cache.push_back({std::move(cu).unwrap_value(), dwversion, range.low, range.high});
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -316,52 +337,75 @@ namespace libdwarf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string subprogram_symbol(
|
Result<std::string, internal_error> subprogram_symbol(
|
||||||
const die_object& die,
|
const die_object& die,
|
||||||
Dwarf_Half dwversion
|
Dwarf_Half dwversion
|
||||||
) {
|
) {
|
||||||
ASSERT(die.get_tag() == DW_TAG_subprogram || die.get_tag() == DW_TAG_inlined_subroutine);
|
auto tag = die.get_tag();
|
||||||
|
ASSERT(tag && (tag.unwrap_value() == DW_TAG_subprogram || tag.unwrap_value() == DW_TAG_inlined_subroutine));
|
||||||
optional<std::string> name;
|
optional<std::string> name;
|
||||||
if(auto linkage_name = die.get_string_attribute(DW_AT_linkage_name)) {
|
auto linkage_name = die.get_string_attribute(DW_AT_linkage_name);
|
||||||
name = std::move(linkage_name);
|
if(!linkage_name) {
|
||||||
} else if(auto linkage_name = die.get_string_attribute(DW_AT_MIPS_linkage_name)) {
|
linkage_name.drop_error();
|
||||||
name = std::move(linkage_name);
|
}
|
||||||
} else if(auto linkage_name = die.get_string_attribute(DW_AT_name)) {
|
if(linkage_name.has_value() && linkage_name.unwrap_value()) {
|
||||||
name = std::move(linkage_name);
|
name = std::move(linkage_name).unwrap_value();
|
||||||
|
} {
|
||||||
|
auto linkage_name = die.get_string_attribute(DW_AT_MIPS_linkage_name);
|
||||||
|
if(!linkage_name) {
|
||||||
|
linkage_name.drop_error();
|
||||||
|
}
|
||||||
|
if(linkage_name.has_value() && linkage_name.unwrap_value()) {
|
||||||
|
name = std::move(linkage_name).unwrap_value();
|
||||||
|
} else {
|
||||||
|
auto linkage_name = die.get_string_attribute(DW_AT_name);
|
||||||
|
if(!linkage_name) {
|
||||||
|
linkage_name.drop_error();
|
||||||
|
}
|
||||||
|
if(linkage_name.has_value() && linkage_name.unwrap_value()) {
|
||||||
|
name = std::move(linkage_name).unwrap_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(name.has_value()) {
|
if(name.has_value()) {
|
||||||
return std::move(name).unwrap();
|
return std::move(name).unwrap();
|
||||||
} else {
|
} else {
|
||||||
if(die.has_attr(DW_AT_specification)) {
|
if(die.has_attr(DW_AT_specification)) {
|
||||||
die_object spec = die.resolve_reference_attribute(DW_AT_specification);
|
auto spec = die.resolve_reference_attribute(DW_AT_specification);
|
||||||
return subprogram_symbol(spec, dwversion);
|
if(!spec) {
|
||||||
|
return std::move(spec).unwrap_error();
|
||||||
|
}
|
||||||
|
return subprogram_symbol(std::move(spec).unwrap_value(), dwversion);
|
||||||
} else if(die.has_attr(DW_AT_abstract_origin)) {
|
} else if(die.has_attr(DW_AT_abstract_origin)) {
|
||||||
die_object spec = die.resolve_reference_attribute(DW_AT_abstract_origin);
|
auto spec = die.resolve_reference_attribute(DW_AT_abstract_origin);
|
||||||
return subprogram_symbol(spec, dwversion);
|
if(!spec) {
|
||||||
|
return std::move(spec).unwrap_error();
|
||||||
|
}
|
||||||
|
return subprogram_symbol(std::move(spec).unwrap_value(), dwversion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return Ok("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// despite (some) dwarf using 1-indexing, file_i should be the 0-based index
|
// despite (some) dwarf using 1-indexing, file_i should be the 0-based index
|
||||||
std::string resolve_filename(const die_object& cu_die, Dwarf_Unsigned file_i) {
|
Result<std::string, internal_error> resolve_filename(const die_object& cu_die, Dwarf_Unsigned file_i) {
|
||||||
std::string filename;
|
std::string filename;
|
||||||
if(get_cache_mode() == cache_mode::prioritize_memory) {
|
if(get_cache_mode() == cache_mode::prioritize_memory) {
|
||||||
char** dw_srcfiles;
|
char** dw_srcfiles;
|
||||||
Dwarf_Signed dw_filecount;
|
Dwarf_Signed dw_filecount;
|
||||||
VERIFY(wrap(dwarf_srcfiles, cu_die.get(), &dw_srcfiles, &dw_filecount) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_srcfiles, cu_die.get(), &dw_srcfiles, &dw_filecount));
|
||||||
if(Dwarf_Signed(file_i) < dw_filecount) {
|
if(Dwarf_Signed(file_i) < dw_filecount) {
|
||||||
// dwarf is using 1-indexing
|
// dwarf is using 1-indexing
|
||||||
filename = dw_srcfiles[file_i];
|
filename = dw_srcfiles[file_i];
|
||||||
}
|
}
|
||||||
dwarf_dealloc(cu_die.dbg, dw_srcfiles, DW_DLA_LIST);
|
dwarf_dealloc(cu_die.dbg, dw_srcfiles, DW_DLA_LIST);
|
||||||
} else {
|
} else {
|
||||||
auto off = cu_die.get_global_offset();
|
PROP_ASSIGN(off, cu_die.get_global_offset());
|
||||||
auto it = srcfiles_cache.find(off);
|
auto it = srcfiles_cache.find(off);
|
||||||
if(it == srcfiles_cache.end()) {
|
if(it == srcfiles_cache.end()) {
|
||||||
char** dw_srcfiles;
|
char** dw_srcfiles;
|
||||||
Dwarf_Signed dw_filecount;
|
Dwarf_Signed dw_filecount;
|
||||||
VERIFY(wrap(dwarf_srcfiles, cu_die.get(), &dw_srcfiles, &dw_filecount) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_srcfiles, cu_die.get(), &dw_srcfiles, &dw_filecount));
|
||||||
it = srcfiles_cache.insert(it, {off, {dw_srcfiles, dw_filecount}});
|
it = srcfiles_cache.insert(it, {off, {dw_srcfiles, dw_filecount}});
|
||||||
}
|
}
|
||||||
char** dw_srcfiles = it->second.first;
|
char** dw_srcfiles = it->second.first;
|
||||||
@ -381,7 +425,8 @@ namespace libdwarf {
|
|||||||
Dwarf_Half dwversion,
|
Dwarf_Half dwversion,
|
||||||
std::vector<stacktrace_frame>& inlines
|
std::vector<stacktrace_frame>& inlines
|
||||||
) {
|
) {
|
||||||
ASSERT(die.get_tag() == DW_TAG_subprogram || die.get_tag() == DW_TAG_inlined_subroutine);
|
auto tag = die.get_tag();
|
||||||
|
ASSERT(tag && (tag.unwrap_value() == DW_TAG_subprogram || tag.unwrap_value() == DW_TAG_inlined_subroutine));
|
||||||
// get_inlines_info is recursive and recurses into dies with pc ranges matching the pc we're looking for,
|
// get_inlines_info is recursive and recurses into dies with pc ranges matching the pc we're looking for,
|
||||||
// however, because I wouldn't want anything stack overflowing I'm breaking the recursion out into a loop
|
// however, because I wouldn't want anything stack overflowing I'm breaking the recursion out into a loop
|
||||||
// while looping when we find the target die we need to be able to store a die somewhere that doesn't die
|
// while looping when we find the target die we need to be able to store a die somewhere that doesn't die
|
||||||
@ -390,47 +435,70 @@ namespace libdwarf {
|
|||||||
optional<std::reference_wrapper<const die_object>> current_die = die;
|
optional<std::reference_wrapper<const die_object>> current_die = die;
|
||||||
while(current_die.has_value()) {
|
while(current_die.has_value()) {
|
||||||
auto child = current_die.unwrap().get().get_child();
|
auto child = current_die.unwrap().get().get_child();
|
||||||
if(!child) {
|
if(!child.has_value() || !child.unwrap_value()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
optional<std::reference_wrapper<const die_object>> target_die;
|
optional<std::reference_wrapper<const die_object>> target_die;
|
||||||
walk_die_list(
|
walk_die_list(
|
||||||
child,
|
child.unwrap_value(),
|
||||||
[this, &cu_die, pc, dwversion, &inlines, &target_die, ¤t_obj_holder] (const die_object& die) {
|
[this, &cu_die, pc, dwversion, &inlines, &target_die, ¤t_obj_holder] (const die_object& die) {
|
||||||
if(die.get_tag() == DW_TAG_inlined_subroutine && die.pc_in_die(dwversion, pc)) {
|
auto tag = die.get_tag();
|
||||||
|
if(!tag) {
|
||||||
|
tag.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(tag.unwrap_value() == DW_TAG_inlined_subroutine && die.pc_in_die(dwversion, pc)) {
|
||||||
const auto name = subprogram_symbol(die, dwversion);
|
const auto name = subprogram_symbol(die, dwversion);
|
||||||
auto file_i = die.get_unsigned_attribute(DW_AT_call_file);
|
auto file_i_r = die.get_unsigned_attribute(DW_AT_call_file);
|
||||||
|
if(!file_i_r) {
|
||||||
|
file_i_r.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto file_i = std::move(file_i_r).unwrap_value();
|
||||||
if(file_i) {
|
if(file_i) {
|
||||||
// for dwarf 2, 3, 4, and experimental line table version 0xfe06 1-indexing is used
|
// for dwarf 2, 3, 4, and experimental line table version 0xfe06 1-indexing is used
|
||||||
// for dwarf 5 0-indexing is used
|
// for dwarf 5 0-indexing is used
|
||||||
auto line_table_opt = get_line_table(cu_die);
|
auto line_table_opt = get_line_table(cu_die);
|
||||||
if(line_table_opt) {
|
if(!line_table_opt) {
|
||||||
auto& line_table = line_table_opt.unwrap().get();
|
line_table_opt.drop_error();
|
||||||
if(line_table.version != 5) {
|
return true;
|
||||||
if(file_i.unwrap() == 0) {
|
}
|
||||||
file_i.reset(); // 0 means no name to be found
|
auto& line_table = line_table_opt.unwrap_value().get();
|
||||||
} else {
|
if(line_table.version != 5) {
|
||||||
// decrement to 0-based index
|
if(file_i.unwrap() == 0) {
|
||||||
file_i.unwrap()--;
|
file_i.reset(); // 0 means no name to be found
|
||||||
}
|
} else {
|
||||||
|
// decrement to 0-based index
|
||||||
|
file_i.unwrap()--;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// silently continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string file = file_i ? resolve_filename(cu_die, file_i.unwrap()) : "";
|
std::string file = file_i ? resolve_filename(cu_die, file_i.unwrap()).value_or("") : "";
|
||||||
const auto line = die.get_unsigned_attribute(DW_AT_call_line);
|
const auto line = die.get_unsigned_attribute(DW_AT_call_line);
|
||||||
|
if(!line) {
|
||||||
|
line.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const auto col = die.get_unsigned_attribute(DW_AT_call_column);
|
const auto col = die.get_unsigned_attribute(DW_AT_call_column);
|
||||||
|
if(!col) {
|
||||||
|
col.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
inlines.push_back(stacktrace_frame{
|
inlines.push_back(stacktrace_frame{
|
||||||
0,
|
0,
|
||||||
0, // TODO: Could put an object address here...
|
0, // TODO: Could put an object address here...
|
||||||
{static_cast<std::uint32_t>(line.value_or(0))},
|
{static_cast<std::uint32_t>(line.unwrap_value().value_or(0))},
|
||||||
{static_cast<std::uint32_t>(col.value_or(0))},
|
{static_cast<std::uint32_t>(col.unwrap_value().value_or(0))},
|
||||||
file,
|
file,
|
||||||
name,
|
name.value_or(""),
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
current_obj_holder = die.clone();
|
auto d = die.clone();
|
||||||
|
if(!d) {
|
||||||
|
d.drop_error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
current_obj_holder = std::move(d).unwrap_value();
|
||||||
target_die = current_obj_holder;
|
target_die = current_obj_holder;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@ -443,15 +511,16 @@ namespace libdwarf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string retrieve_symbol_for_subprogram(
|
Result<std::string, internal_error> retrieve_symbol_for_subprogram(
|
||||||
const die_object& cu_die,
|
const die_object& cu_die,
|
||||||
const die_object& die,
|
const die_object& die,
|
||||||
Dwarf_Addr pc,
|
Dwarf_Addr pc,
|
||||||
Dwarf_Half dwversion,
|
Dwarf_Half dwversion,
|
||||||
std::vector<stacktrace_frame>& inlines
|
std::vector<stacktrace_frame>& inlines
|
||||||
) {
|
) {
|
||||||
ASSERT(die.get_tag() == DW_TAG_subprogram);
|
auto tag = die.get_tag();
|
||||||
const auto name = subprogram_symbol(die, dwversion);
|
ASSERT(tag && tag.unwrap_value() == DW_TAG_subprogram);
|
||||||
|
auto name = subprogram_symbol(die, dwversion);
|
||||||
if(detail::should_resolve_inlined_calls()) {
|
if(detail::should_resolve_inlined_calls()) {
|
||||||
get_inlines_info(cu_die, die, pc, dwversion, inlines);
|
get_inlines_info(cu_die, die, pc, dwversion, inlines);
|
||||||
}
|
}
|
||||||
@ -473,42 +542,52 @@ namespace libdwarf {
|
|||||||
die,
|
die,
|
||||||
[this, &cu_die, pc, dwversion, &frame, &inlines, &found] (const die_object& die) {
|
[this, &cu_die, pc, dwversion, &frame, &inlines, &found] (const die_object& die) {
|
||||||
if(dump_dwarf) {
|
if(dump_dwarf) {
|
||||||
std::fprintf(
|
microfmt::print(
|
||||||
stderr,
|
std::cerr,
|
||||||
"-------------> %08llx %s %s\n",
|
"-------------> {8:0h} {} {}\n",
|
||||||
to_ull(die.get_global_offset()),
|
die.get_global_offset().value_or(0),
|
||||||
die.get_tag_name(),
|
die.get_tag_name(),
|
||||||
die.get_name().c_str()
|
die.get_name().value_or("<error>")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(!(die.get_tag() == DW_TAG_namespace || die.pc_in_die(dwversion, pc))) {
|
auto tag = die.get_tag();
|
||||||
|
if(!tag) {
|
||||||
|
tag.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(!(tag.unwrap_value() == DW_TAG_namespace || die.pc_in_die(dwversion, pc))) {
|
||||||
if(dump_dwarf) {
|
if(dump_dwarf) {
|
||||||
std::fprintf(stderr, "pc not in die\n");
|
microfmt::print(std::cerr, "pc not in die\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(trace_dwarf) {
|
if(trace_dwarf) {
|
||||||
std::fprintf(
|
microfmt::print(
|
||||||
stderr,
|
std::cerr,
|
||||||
"%s %08llx %s\n",
|
"{} {8:0h} {}\n",
|
||||||
die.get_tag() == DW_TAG_namespace ? "pc maybe in die (namespace)" : "pc in die",
|
tag.unwrap_value() == DW_TAG_namespace ? "pc maybe in die (namespace)" : "pc in die",
|
||||||
to_ull(die.get_global_offset()),
|
die.get_global_offset().value_or(0),
|
||||||
die.get_tag_name()
|
die.get_tag_name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(die.get_tag() == DW_TAG_subprogram) {
|
if(tag.unwrap_value() == DW_TAG_subprogram) {
|
||||||
frame.symbol = retrieve_symbol_for_subprogram(cu_die, die, pc, dwversion, inlines);
|
frame.symbol = retrieve_symbol_for_subprogram(cu_die, die, pc, dwversion, inlines)
|
||||||
|
.value_or("");
|
||||||
found = true;
|
found = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto child = die.get_child();
|
auto child = die.get_child();
|
||||||
if(child) {
|
if(!child) {
|
||||||
if(retrieve_symbol_walk(cu_die, child, pc, dwversion, frame, inlines)) {
|
child.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(child.unwrap_value()) {
|
||||||
|
if(retrieve_symbol_walk(cu_die, child.unwrap_value(), pc, dwversion, frame, inlines)) {
|
||||||
found = true;
|
found = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(dump_dwarf) {
|
if(dump_dwarf) {
|
||||||
std::fprintf(stderr, "(no child)\n");
|
microfmt::print(std::cerr, "(no child)\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -516,7 +595,7 @@ namespace libdwarf {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(dump_dwarf) {
|
if(dump_dwarf) {
|
||||||
std::fprintf(stderr, "End walk_die_list\n");
|
microfmt::print(std::cerr, "End walk_die_list\n");
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
@ -530,20 +609,38 @@ namespace libdwarf {
|
|||||||
walk_die_list(
|
walk_die_list(
|
||||||
die,
|
die,
|
||||||
[this, dwversion, &vec] (const die_object& die) {
|
[this, dwversion, &vec] (const die_object& die) {
|
||||||
switch(die.get_tag()) {
|
auto tag = die.get_tag();
|
||||||
|
if(!tag) {
|
||||||
|
tag.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
switch(tag.unwrap_value()) {
|
||||||
case DW_TAG_subprogram:
|
case DW_TAG_subprogram:
|
||||||
{
|
{
|
||||||
auto ranges_vec = die.get_rangelist_entries(dwversion);
|
auto ranges_vec = die.get_rangelist_entries(dwversion);
|
||||||
|
if(!ranges_vec) {
|
||||||
|
ranges_vec.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// TODO: Feels super inefficient and some day should maybe use an interval tree.
|
// TODO: Feels super inefficient and some day should maybe use an interval tree.
|
||||||
for(auto range : ranges_vec) {
|
for(auto range : ranges_vec.unwrap_value()) {
|
||||||
vec.push_back({ die.clone(), range.first, range.second });
|
auto d = die.clone();
|
||||||
|
if(!d) {
|
||||||
|
d.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
vec.push_back({ std::move(d).unwrap_value(), range.low, range.high });
|
||||||
}
|
}
|
||||||
// Walk children to get things like lambdas
|
// Walk children to get things like lambdas
|
||||||
// TODO: Somehow find a way to get better names here? For gcc it's just "operator()"
|
// TODO: Somehow find a way to get better names here? For gcc it's just "operator()"
|
||||||
// On clang it's better
|
// On clang it's better
|
||||||
auto child = die.get_child();
|
auto child = die.get_child();
|
||||||
if(child) {
|
if(!child) {
|
||||||
preprocess_subprograms(child, dwversion, vec);
|
child.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(child.unwrap_value()) {
|
||||||
|
preprocess_subprograms(child.unwrap_value(), dwversion, vec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -555,8 +652,12 @@ namespace libdwarf {
|
|||||||
case DW_TAG_compile_unit:
|
case DW_TAG_compile_unit:
|
||||||
{
|
{
|
||||||
auto child = die.get_child();
|
auto child = die.get_child();
|
||||||
if(child) {
|
if(!child) {
|
||||||
preprocess_subprograms(child, dwversion, vec);
|
child.drop_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(child.unwrap_value()) {
|
||||||
|
preprocess_subprograms(child.unwrap_value(), dwversion, vec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -583,7 +684,10 @@ namespace libdwarf {
|
|||||||
retrieve_symbol_walk(cu_die, cu_die, pc, dwversion, frame, inlines);
|
retrieve_symbol_walk(cu_die, cu_die, pc, dwversion, frame, inlines);
|
||||||
} else {
|
} else {
|
||||||
auto off = cu_die.get_global_offset();
|
auto off = cu_die.get_global_offset();
|
||||||
auto it = subprograms_cache.find(off);
|
if(!off) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto it = subprograms_cache.find(off.unwrap_value());
|
||||||
if(it == subprograms_cache.end()) {
|
if(it == subprograms_cache.end()) {
|
||||||
// TODO: Refactor. Do the sort in the preprocess function and return the vec directly.
|
// TODO: Refactor. Do the sort in the preprocess function and return the vec directly.
|
||||||
std::vector<subprogram_entry> vec;
|
std::vector<subprogram_entry> vec;
|
||||||
@ -591,8 +695,8 @@ namespace libdwarf {
|
|||||||
std::sort(vec.begin(), vec.end(), [] (const subprogram_entry& a, const subprogram_entry& b) {
|
std::sort(vec.begin(), vec.end(), [] (const subprogram_entry& a, const subprogram_entry& b) {
|
||||||
return a.low < b.low;
|
return a.low < b.low;
|
||||||
});
|
});
|
||||||
subprograms_cache.emplace(off, std::move(vec));
|
subprograms_cache.emplace(off.unwrap_value(), std::move(vec));
|
||||||
it = subprograms_cache.find(off);
|
it = subprograms_cache.find(off.unwrap_value());
|
||||||
}
|
}
|
||||||
auto& vec = it->second;
|
auto& vec = it->second;
|
||||||
auto vec_it = first_less_than_or_equal(
|
auto vec_it = first_less_than_or_equal(
|
||||||
@ -607,7 +711,8 @@ namespace libdwarf {
|
|||||||
if(vec_it != vec.end()) {
|
if(vec_it != vec.end()) {
|
||||||
//vec_it->die.print();
|
//vec_it->die.print();
|
||||||
if(vec_it->die.pc_in_die(dwversion, pc)) {
|
if(vec_it->die.pc_in_die(dwversion, pc)) {
|
||||||
frame.symbol = retrieve_symbol_for_subprogram(cu_die, vec_it->die, pc, dwversion, inlines);
|
frame.symbol = retrieve_symbol_for_subprogram(cu_die, vec_it->die, pc, dwversion, inlines)
|
||||||
|
.value_or("");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT(vec.size() == 0, "Vec should be empty?");
|
ASSERT(vec.size() == 0, "Vec should be empty?");
|
||||||
@ -617,29 +722,35 @@ namespace libdwarf {
|
|||||||
|
|
||||||
// returns a reference to a CU's line table, may be invalidated if the line_tables map is modified
|
// returns a reference to a CU's line table, may be invalidated if the line_tables map is modified
|
||||||
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
|
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
|
||||||
optional<std::reference_wrapper<line_table_info>> get_line_table(const die_object& cu_die) {
|
Result<std::reference_wrapper<line_table_info>, internal_error> get_line_table(const die_object& cu_die) {
|
||||||
auto off = cu_die.get_global_offset();
|
PROP_ASSIGN(off, cu_die.get_global_offset());
|
||||||
auto it = line_tables.find(off);
|
auto it = line_tables.find(off);
|
||||||
if(it != line_tables.end()) {
|
if(it != line_tables.end()) {
|
||||||
return it->second;
|
return std::reference_wrapper<line_table_info>{it->second};
|
||||||
} else {
|
} else {
|
||||||
Dwarf_Unsigned version;
|
Dwarf_Unsigned version;
|
||||||
Dwarf_Small table_count;
|
Dwarf_Small table_count;
|
||||||
Dwarf_Line_Context line_context;
|
Dwarf_Line_Context line_context;
|
||||||
int ret = wrap(
|
PROP_ASSIGN(
|
||||||
dwarf_srclines_b,
|
ret,
|
||||||
cu_die.get(),
|
wrap(
|
||||||
&version,
|
dwarf_srclines_b,
|
||||||
&table_count,
|
cu_die.get(),
|
||||||
&line_context
|
&version,
|
||||||
|
&table_count,
|
||||||
|
&line_context
|
||||||
|
)
|
||||||
);
|
);
|
||||||
static_assert(std::is_unsigned<decltype(table_count)>::value, "Expected unsigned Dwarf_Small");
|
static_assert(std::is_unsigned<decltype(table_count)>::value, "Expected unsigned Dwarf_Small");
|
||||||
VERIFY(/*table_count >= 0 &&*/ table_count <= 2, "Unknown dwarf line table count");
|
if(table_count > 2) {
|
||||||
if(ret == DW_DLV_NO_ENTRY) {
|
return internal_error("Unknown dwarf line table count");
|
||||||
// TODO: Failing silently for now
|
}
|
||||||
return nullopt;
|
if(ret == DW_DLV_NO_ENTRY) {
|
||||||
|
return internal_error("dwarf_srclines_b DW_DLV_NO_ENTRY");
|
||||||
|
}
|
||||||
|
if(ret != DW_DLV_OK) {
|
||||||
|
return internal_error("dwarf_srclines_b not ok");
|
||||||
}
|
}
|
||||||
VERIFY(ret == DW_DLV_OK);
|
|
||||||
|
|
||||||
std::vector<line_entry> line_entries;
|
std::vector<line_entry> line_entries;
|
||||||
|
|
||||||
@ -649,7 +760,7 @@ namespace libdwarf {
|
|||||||
Dwarf_Signed line_count = 0;
|
Dwarf_Signed line_count = 0;
|
||||||
Dwarf_Line* linebuf_actuals = nullptr;
|
Dwarf_Line* linebuf_actuals = nullptr;
|
||||||
Dwarf_Signed linecount_actuals = 0;
|
Dwarf_Signed linecount_actuals = 0;
|
||||||
VERIFY(
|
CHECK_OK(
|
||||||
wrap(
|
wrap(
|
||||||
dwarf_srclines_two_level_from_linecontext,
|
dwarf_srclines_two_level_from_linecontext,
|
||||||
line_context,
|
line_context,
|
||||||
@ -657,7 +768,7 @@ namespace libdwarf {
|
|||||||
&line_count,
|
&line_count,
|
||||||
&linebuf_actuals,
|
&linebuf_actuals,
|
||||||
&linecount_actuals
|
&linecount_actuals
|
||||||
) == DW_DLV_OK
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Make any attempt to note PC ranges? Handle line end sequence?
|
// TODO: Make any attempt to note PC ranges? Handle line end sequence?
|
||||||
@ -665,12 +776,12 @@ namespace libdwarf {
|
|||||||
for(int i = 0; i < line_count; i++) {
|
for(int i = 0; i < line_count; i++) {
|
||||||
Dwarf_Line line = line_buffer[i];
|
Dwarf_Line line = line_buffer[i];
|
||||||
Dwarf_Addr low_addr = 0;
|
Dwarf_Addr low_addr = 0;
|
||||||
VERIFY(wrap(dwarf_lineaddr, line, &low_addr) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_lineaddr, line, &low_addr));
|
||||||
// scan ahead for the last line entry matching this pc
|
// scan ahead for the last line entry matching this pc
|
||||||
int j;
|
int j;
|
||||||
for(j = i + 1; j < line_count; j++) {
|
for(j = i + 1; j < line_count; j++) {
|
||||||
Dwarf_Addr addr = 0;
|
Dwarf_Addr addr = 0;
|
||||||
VERIFY(wrap(dwarf_lineaddr, line_buffer[j], &addr) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_lineaddr, line_buffer[j], &addr));
|
||||||
if(addr != low_addr) {
|
if(addr != low_addr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -707,7 +818,7 @@ namespace libdwarf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it = line_tables.insert({off, {version, line_context, std::move(line_entries)}}).first;
|
it = line_tables.insert({off, {version, line_context, std::move(line_entries)}}).first;
|
||||||
return it->second;
|
return std::reference_wrapper<line_table_info>{it->second};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,9 +830,10 @@ namespace libdwarf {
|
|||||||
) {
|
) {
|
||||||
auto table_info_opt = get_line_table(cu_die);
|
auto table_info_opt = get_line_table(cu_die);
|
||||||
if(!table_info_opt) {
|
if(!table_info_opt) {
|
||||||
return; // failing silently for now
|
table_info_opt.drop_error();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
auto& table_info = table_info_opt.unwrap().get();
|
auto& table_info = table_info_opt.unwrap_value().get();
|
||||||
if(get_cache_mode() == cache_mode::prioritize_speed) {
|
if(get_cache_mode() == cache_mode::prioritize_speed) {
|
||||||
// Lookup in the table
|
// Lookup in the table
|
||||||
auto& line_entries = table_info.line_entries;
|
auto& line_entries = table_info.line_entries;
|
||||||
@ -739,21 +851,42 @@ namespace libdwarf {
|
|||||||
// line number
|
// line number
|
||||||
if(!table_it->line_number) {
|
if(!table_it->line_number) {
|
||||||
Dwarf_Unsigned line_number = 0;
|
Dwarf_Unsigned line_number = 0;
|
||||||
VERIFY(wrap(dwarf_lineno, line, &line_number) == DW_DLV_OK);
|
auto res = wrap(dwarf_lineno, line, &line_number);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
table_it->line_number = static_cast<std::uint32_t>(line_number);
|
table_it->line_number = static_cast<std::uint32_t>(line_number);
|
||||||
}
|
}
|
||||||
frame.line = table_it->line_number.unwrap();
|
frame.line = table_it->line_number.unwrap();
|
||||||
// column number
|
// column number
|
||||||
if(!table_it->column_number) {
|
if(!table_it->column_number) {
|
||||||
Dwarf_Unsigned column_number = 0;
|
Dwarf_Unsigned column_number = 0;
|
||||||
VERIFY(wrap(dwarf_lineoff_b, line, &column_number) == DW_DLV_OK);
|
auto res = wrap(dwarf_lineoff_b, line, &column_number);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
table_it->column_number = static_cast<std::uint32_t>(column_number);
|
table_it->column_number = static_cast<std::uint32_t>(column_number);
|
||||||
}
|
}
|
||||||
frame.column = table_it->column_number.unwrap();
|
frame.column = table_it->column_number.unwrap();
|
||||||
// filename
|
// filename
|
||||||
if(!table_it->path) {
|
if(!table_it->path) {
|
||||||
char* filename = nullptr;
|
char* filename = nullptr;
|
||||||
VERIFY(wrap(dwarf_linesrc, line, &filename) == DW_DLV_OK);
|
auto res = wrap(dwarf_linesrc, line, &filename);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto wrapper = raii_wrap(
|
auto wrapper = raii_wrap(
|
||||||
filename,
|
filename,
|
||||||
[this] (char* str) { if(str) dwarf_dealloc(dbg, str, DW_DLA_STRING); }
|
[this] (char* str) { if(str) dwarf_dealloc(dbg, str, DW_DLA_STRING); }
|
||||||
@ -769,22 +902,34 @@ namespace libdwarf {
|
|||||||
Dwarf_Signed line_count = 0;
|
Dwarf_Signed line_count = 0;
|
||||||
Dwarf_Line* linebuf_actuals = nullptr;
|
Dwarf_Line* linebuf_actuals = nullptr;
|
||||||
Dwarf_Signed linecount_actuals = 0;
|
Dwarf_Signed linecount_actuals = 0;
|
||||||
VERIFY(
|
auto res = wrap(
|
||||||
wrap(
|
dwarf_srclines_two_level_from_linecontext,
|
||||||
dwarf_srclines_two_level_from_linecontext,
|
line_context,
|
||||||
line_context,
|
&line_buffer,
|
||||||
&line_buffer,
|
&line_count,
|
||||||
&line_count,
|
&linebuf_actuals,
|
||||||
&linebuf_actuals,
|
&linecount_actuals
|
||||||
&linecount_actuals
|
|
||||||
) == DW_DLV_OK
|
|
||||||
);
|
);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Dwarf_Addr last_lineaddr = 0;
|
Dwarf_Addr last_lineaddr = 0;
|
||||||
Dwarf_Line last_line = nullptr;
|
Dwarf_Line last_line = nullptr;
|
||||||
for(int i = 0; i < line_count; i++) {
|
for(int i = 0; i < line_count; i++) {
|
||||||
Dwarf_Line line = line_buffer[i];
|
Dwarf_Line line = line_buffer[i];
|
||||||
Dwarf_Addr lineaddr = 0;
|
Dwarf_Addr lineaddr = 0;
|
||||||
VERIFY(wrap(dwarf_lineaddr, line, &lineaddr) == DW_DLV_OK);
|
auto res = wrap(dwarf_lineaddr, line, &lineaddr);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Dwarf_Line found_line = nullptr;
|
Dwarf_Line found_line = nullptr;
|
||||||
if(pc == lineaddr) {
|
if(pc == lineaddr) {
|
||||||
// Multiple PCs may correspond to a line, find the last one
|
// Multiple PCs may correspond to a line, find the last one
|
||||||
@ -792,7 +937,14 @@ namespace libdwarf {
|
|||||||
for(int j = i + 1; j < line_count; j++) {
|
for(int j = i + 1; j < line_count; j++) {
|
||||||
Dwarf_Line line = line_buffer[j];
|
Dwarf_Line line = line_buffer[j];
|
||||||
Dwarf_Addr lineaddr = 0;
|
Dwarf_Addr lineaddr = 0;
|
||||||
VERIFY(wrap(dwarf_lineaddr, line, &lineaddr) == DW_DLV_OK);
|
auto res = wrap(dwarf_lineaddr, line, &lineaddr);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(pc == lineaddr) {
|
if(pc == lineaddr) {
|
||||||
found_line = line;
|
found_line = line;
|
||||||
}
|
}
|
||||||
@ -803,10 +955,24 @@ namespace libdwarf {
|
|||||||
}
|
}
|
||||||
if(found_line) {
|
if(found_line) {
|
||||||
Dwarf_Unsigned line_number = 0;
|
Dwarf_Unsigned line_number = 0;
|
||||||
VERIFY(wrap(dwarf_lineno, found_line, &line_number) == DW_DLV_OK);
|
auto res = wrap(dwarf_lineno, found_line, &line_number);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
frame.line = static_cast<std::uint32_t>(line_number);
|
frame.line = static_cast<std::uint32_t>(line_number);
|
||||||
char* filename = nullptr;
|
char* filename = nullptr;
|
||||||
VERIFY(wrap(dwarf_linesrc, found_line, &filename) == DW_DLV_OK);
|
auto res2 = wrap(dwarf_linesrc, found_line, &filename);
|
||||||
|
if(!res2) {
|
||||||
|
res2.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res2.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto wrapper = raii_wrap(
|
auto wrapper = raii_wrap(
|
||||||
filename,
|
filename,
|
||||||
[this] (char* str) { if(str) dwarf_dealloc(dbg, str, DW_DLA_STRING); }
|
[this] (char* str) { if(str) dwarf_dealloc(dbg, str, DW_DLA_STRING); }
|
||||||
@ -814,7 +980,14 @@ namespace libdwarf {
|
|||||||
frame.filename = filename;
|
frame.filename = filename;
|
||||||
} else {
|
} else {
|
||||||
Dwarf_Bool is_line_end;
|
Dwarf_Bool is_line_end;
|
||||||
VERIFY(wrap(dwarf_lineendsequence, line, &is_line_end) == DW_DLV_OK);
|
auto res = wrap(dwarf_lineendsequence, line, &is_line_end);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(is_line_end) {
|
if(is_line_end) {
|
||||||
last_lineaddr = 0;
|
last_lineaddr = 0;
|
||||||
last_line = nullptr;
|
last_line = nullptr;
|
||||||
@ -841,17 +1014,40 @@ namespace libdwarf {
|
|||||||
if(aranges) {
|
if(aranges) {
|
||||||
// Try to find pc in aranges
|
// Try to find pc in aranges
|
||||||
Dwarf_Arange arange;
|
Dwarf_Arange arange;
|
||||||
if(wrap(dwarf_get_arange, aranges, arange_count, pc, &arange) == DW_DLV_OK) {
|
auto res = wrap(dwarf_get_arange, aranges, arange_count, pc, &arange);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(res.unwrap_value() == DW_DLV_OK) {
|
||||||
// Address in table, load CU die
|
// Address in table, load CU die
|
||||||
Dwarf_Off cu_die_offset;
|
Dwarf_Off cu_die_offset;
|
||||||
VERIFY(wrap(dwarf_get_cu_die_offset, arange, &cu_die_offset) == DW_DLV_OK);
|
auto res = wrap(dwarf_get_cu_die_offset, arange, &cu_die_offset);
|
||||||
|
if(!res) {
|
||||||
|
res.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Dwarf_Die raw_die;
|
Dwarf_Die raw_die;
|
||||||
// Setting is_info = true for now, assuming in .debug_info rather than .debug_types
|
// Setting is_info = true for now, assuming in .debug_info rather than .debug_types
|
||||||
VERIFY(wrap(dwarf_offdie_b, dbg, cu_die_offset, true, &raw_die) == DW_DLV_OK);
|
auto res2 = wrap(dwarf_offdie_b, dbg, cu_die_offset, true, &raw_die);
|
||||||
|
if(!res2) {
|
||||||
|
res2.drop_error();
|
||||||
|
return;
|
||||||
|
} else if(res2.unwrap_value() != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
die_object cu_die(dbg, raw_die);
|
die_object cu_die(dbg, raw_die);
|
||||||
Dwarf_Half offset_size = 0;
|
Dwarf_Half offset_size = 0;
|
||||||
Dwarf_Half dwversion = 0;
|
Dwarf_Half dwversion = 0;
|
||||||
VERIFY(dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size) == DW_DLV_OK);
|
int res3 = dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size);
|
||||||
|
if(res3 != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(trace_dwarf) {
|
if(trace_dwarf) {
|
||||||
std::fprintf(stderr, "Found CU in aranges\n");
|
std::fprintf(stderr, "Found CU in aranges\n");
|
||||||
cu_die.print();
|
cu_die.print();
|
||||||
@ -870,19 +1066,23 @@ namespace libdwarf {
|
|||||||
walk_compilation_units([this, pc, &frame, &inlines] (const die_object& cu_die) {
|
walk_compilation_units([this, pc, &frame, &inlines] (const die_object& cu_die) {
|
||||||
Dwarf_Half offset_size = 0;
|
Dwarf_Half offset_size = 0;
|
||||||
Dwarf_Half dwversion = 0;
|
Dwarf_Half dwversion = 0;
|
||||||
dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size);
|
auto res = dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size);
|
||||||
|
if(res != DW_DLV_OK) {
|
||||||
|
ASSERT(false, "dwarf call not ok");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
//auto p = cu_die.get_pc_range(dwversion);
|
//auto p = cu_die.get_pc_range(dwversion);
|
||||||
//cu_die.print();
|
//cu_die.print();
|
||||||
//fprintf(stderr, " %llx, %llx\n", p.first, p.second);
|
//fprintf(stderr, " %llx, %llx\n", p.first, p.second);
|
||||||
if(trace_dwarf) {
|
if(trace_dwarf) {
|
||||||
std::fprintf(stderr, "CU: %d %s\n", dwversion, cu_die.get_name().c_str());
|
microfmt::print(std::cerr, "CU: {} {}\n", dwversion, cu_die.get_name().value_or("<error>"));
|
||||||
}
|
}
|
||||||
if(cu_die.pc_in_die(dwversion, pc)) {
|
if(cu_die.pc_in_die(dwversion, pc)) {
|
||||||
if(trace_dwarf) {
|
if(trace_dwarf) {
|
||||||
std::fprintf(
|
std::fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"pc in die %08llx %s (now searching for %08llx)\n",
|
"pc in die %08llx %s (now searching for %08llx)\n",
|
||||||
to_ull(cu_die.get_global_offset()),
|
to_ull(cu_die.get_global_offset().value_or(0)),
|
||||||
cu_die.get_tag_name(),
|
cu_die.get_tag_name(),
|
||||||
to_ull(pc)
|
to_ull(pc)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -17,20 +17,57 @@
|
|||||||
#include <dwarf.h>
|
#include <dwarf.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CONCAT_IMPL( x, y ) x##y
|
||||||
|
#define CONCAT( x, y ) CONCAT_IMPL( x, y )
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace libdwarf {
|
namespace libdwarf {
|
||||||
static_assert(std::is_pointer<Dwarf_Die>::value, "Dwarf_Die not a pointer");
|
static_assert(std::is_pointer<Dwarf_Die>::value, "Dwarf_Die not a pointer");
|
||||||
static_assert(std::is_pointer<Dwarf_Debug>::value, "Dwarf_Debug not a pointer");
|
static_assert(std::is_pointer<Dwarf_Debug>::value, "Dwarf_Debug not a pointer");
|
||||||
|
|
||||||
[[noreturn]] void handle_dwarf_error(Dwarf_Debug dbg, Dwarf_Error error) {
|
static NODISCARD ErrorResult<internal_error> handle_dwarf_error(Dwarf_Debug, Dwarf_Error error) {
|
||||||
Dwarf_Unsigned ev = dwarf_errno(error);
|
Dwarf_Unsigned ev = dwarf_errno(error);
|
||||||
char* msg = dwarf_errmsg(error);
|
char* msg = dwarf_errmsg(error);
|
||||||
(void)dbg;
|
return {internal_error("Cpptrace dwarf error {} {}", ev, msg)};
|
||||||
// dwarf_dealloc_error(dbg, error);
|
|
||||||
throw internal_error("Cpptrace dwarf error {} {}", ev, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CHECK_OK_IMPL(res_var, expr) \
|
||||||
|
Result<int, internal_error> res_var = (expr); \
|
||||||
|
if(!res_var) { \
|
||||||
|
return std::move(res_var).unwrap_error(); \
|
||||||
|
} else if(res_var.unwrap_value() != DW_DLV_OK) { \
|
||||||
|
return Error( \
|
||||||
|
internal_error( \
|
||||||
|
"dwarf error: {} didn't evaluate to DW_DLV_OK, instead got {}", \
|
||||||
|
#expr, \
|
||||||
|
res_var.unwrap_value() \
|
||||||
|
) \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the expression is an error or not DW_DLV_OK and error if either
|
||||||
|
#define CHECK_OK(expr) CHECK_OK_IMPL(CONCAT(res, __COUNTER__), (expr))
|
||||||
|
|
||||||
|
#define PROP_ASSIGN_IMPL(var, res_var, expr) \
|
||||||
|
auto res_var = (expr); \
|
||||||
|
if(!res_var) { \
|
||||||
|
return std::move(res_var).unwrap_error(); \
|
||||||
|
} \
|
||||||
|
auto var = res_var.unwrap_value();
|
||||||
|
|
||||||
|
// If the expression is an error, return the error. Otherwise assign the value to the variable.
|
||||||
|
#define PROP_ASSIGN(var, expr) PROP_ASSIGN_IMPL(var, CONCAT(res, __COUNTER__), (expr))
|
||||||
|
|
||||||
|
#define PROP_IMPL(res_var, expr) \
|
||||||
|
auto res_var = (expr); \
|
||||||
|
if(!res_var) { \
|
||||||
|
return std::move(res_var).unwrap_error(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the expression is an error, return the error. Otherwise assign the value to the variable.
|
||||||
|
#define PROP(expr) PROP_IMPL(CONCAT(res, __COUNTER__), (expr))
|
||||||
|
|
||||||
struct die_object {
|
struct die_object {
|
||||||
Dwarf_Debug dbg = nullptr;
|
Dwarf_Debug dbg = nullptr;
|
||||||
Dwarf_Die die = nullptr;
|
Dwarf_Die die = nullptr;
|
||||||
@ -51,19 +88,29 @@ namespace libdwarf {
|
|||||||
int
|
int
|
||||||
>::type = 0
|
>::type = 0
|
||||||
>
|
>
|
||||||
int wrap(int (*f)(Args...), Args2&&... args) const {
|
Result<int, internal_error> wrap(int (*f)(Args...), Args2&&... args) const {
|
||||||
Dwarf_Error error = nullptr;
|
Dwarf_Error error = nullptr;
|
||||||
int ret = f(std::forward<Args2>(args)..., &error);
|
int ret = f(std::forward<Args2>(args)..., &error);
|
||||||
if(ret == DW_DLV_ERROR) {
|
if(ret == DW_DLV_ERROR) {
|
||||||
handle_dwarf_error(dbg, error);
|
return handle_dwarf_error(dbg, error);
|
||||||
}
|
}
|
||||||
return ret;
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
die_object(Dwarf_Debug dbg, Dwarf_Die die) : dbg(dbg), die(die) {
|
die_object(Dwarf_Debug dbg, Dwarf_Die die) : dbg(dbg), die(die) {
|
||||||
ASSERT(dbg != nullptr);
|
ASSERT(dbg != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public:
|
||||||
|
// Result<die_object, internal_error> create(Dwarf_Debug dbg, Dwarf_Die die) {
|
||||||
|
// if(die == nullptr) {
|
||||||
|
// return internal_error("Error creating dwarf die object: Nullptr");
|
||||||
|
// } else {
|
||||||
|
// return die_object(dbg, die);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
~die_object() {
|
~die_object() {
|
||||||
if(die) {
|
if(die) {
|
||||||
dwarf_dealloc_die(die);
|
dwarf_dealloc_die(die);
|
||||||
@ -87,39 +134,42 @@ namespace libdwarf {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
die_object clone() const {
|
Result<die_object, internal_error> clone() const {
|
||||||
Dwarf_Off global_offset = get_global_offset();
|
auto global_offset = get_global_offset();
|
||||||
|
if(!global_offset) {
|
||||||
|
return global_offset.unwrap_error();
|
||||||
|
}
|
||||||
Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die);
|
Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die);
|
||||||
Dwarf_Die die_copy = nullptr;
|
Dwarf_Die die_copy = nullptr;
|
||||||
VERIFY(wrap(dwarf_offdie_b, dbg, global_offset, is_info, &die_copy) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_offdie_b, dbg, global_offset.unwrap_value(), is_info, &die_copy));
|
||||||
return {dbg, die_copy};
|
return die_object(dbg, die_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
die_object get_child() const {
|
Result<die_object, internal_error> get_child() const {
|
||||||
Dwarf_Die child = nullptr;
|
Dwarf_Die child = nullptr;
|
||||||
int ret = wrap(dwarf_child, die, &child);
|
PROP_ASSIGN(ret, wrap(dwarf_child, die, &child));
|
||||||
if(ret == DW_DLV_OK) {
|
if(ret == DW_DLV_OK) {
|
||||||
return die_object(dbg, child);
|
return die_object(dbg, child);
|
||||||
} else if(ret == DW_DLV_NO_ENTRY) {
|
} else if(ret == DW_DLV_NO_ENTRY) {
|
||||||
return die_object(dbg, nullptr);
|
return die_object(dbg, nullptr);
|
||||||
} else {
|
} else {
|
||||||
PANIC();
|
return internal_error("dwarf error: Unexpected return from dwarf_child {}", ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
die_object get_sibling() const {
|
Result<die_object, internal_error> get_sibling() const {
|
||||||
Dwarf_Die sibling = nullptr;
|
Dwarf_Die sibling = nullptr;
|
||||||
int ret = wrap(dwarf_siblingof_b, dbg, die, true, &sibling);
|
PROP_ASSIGN(ret, wrap(dwarf_siblingof_b, dbg, die, true, &sibling));
|
||||||
if(ret == DW_DLV_OK) {
|
if(ret == DW_DLV_OK) {
|
||||||
return die_object(dbg, sibling);
|
return die_object(dbg, sibling);
|
||||||
} else if(ret == DW_DLV_NO_ENTRY) {
|
} else if(ret == DW_DLV_NO_ENTRY) {
|
||||||
return die_object(dbg, nullptr);
|
return die_object(dbg, nullptr);
|
||||||
} else {
|
} else {
|
||||||
PANIC();
|
return internal_error("dwarf error: Unexpected return from dwarf_siblingof_b {}", ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const {
|
explicit operator bool() const {
|
||||||
return die != nullptr;
|
return die != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,79 +177,83 @@ namespace libdwarf {
|
|||||||
return die;
|
return die;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_name() const {
|
Result<std::string, internal_error> get_name() const {
|
||||||
char empty[] = "";
|
char empty[] = "";
|
||||||
char* name = empty;
|
char* name = empty;
|
||||||
int ret = wrap(dwarf_diename, die, &name);
|
PROP_ASSIGN(ret, wrap(dwarf_diename, die, &name));
|
||||||
auto wrapper = raii_wrap(name, [this] (char* str) { dwarf_dealloc(dbg, str, DW_DLA_STRING); });
|
auto wrapper = raii_wrap(name, [this] (char* str) { dwarf_dealloc(dbg, str, DW_DLA_STRING); });
|
||||||
std::string str;
|
std::string str;
|
||||||
if(ret != DW_DLV_NO_ENTRY) {
|
if(ret != DW_DLV_NO_ENTRY) {
|
||||||
str = name;
|
str = name;
|
||||||
}
|
}
|
||||||
return name;
|
return std::string(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<std::string> get_string_attribute(Dwarf_Half attr_num) const {
|
Result<optional<std::string>, internal_error> get_string_attribute(Dwarf_Half attr_num) const {
|
||||||
Dwarf_Attribute attr;
|
Dwarf_Attribute attr;
|
||||||
if(wrap(dwarf_attr, die, attr_num, &attr) == DW_DLV_OK) {
|
auto ret = wrap(dwarf_attr, die, attr_num, &attr);
|
||||||
|
if(ret.is_error()) {
|
||||||
|
ret.drop_error();
|
||||||
|
} else if(ret.unwrap_value() == DW_DLV_OK) {
|
||||||
auto attwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
auto attwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
||||||
char* raw_str;
|
char* raw_str;
|
||||||
VERIFY(wrap(dwarf_formstring, attr, &raw_str) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_formstring, attr, &raw_str));
|
||||||
auto strwrapper = raii_wrap(raw_str, [this] (char* str) { dwarf_dealloc(dbg, str, DW_DLA_STRING); });
|
auto strwrapper = raii_wrap(raw_str, [this] (char* str) { dwarf_dealloc(dbg, str, DW_DLA_STRING); });
|
||||||
std::string str = raw_str;
|
std::string str = raw_str;
|
||||||
return str;
|
return Ok(str);
|
||||||
} else {
|
|
||||||
return nullopt;
|
|
||||||
}
|
}
|
||||||
|
return Ok(nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<Dwarf_Unsigned> get_unsigned_attribute(Dwarf_Half attr_num) const {
|
Result<optional<Dwarf_Unsigned>, internal_error> get_unsigned_attribute(Dwarf_Half attr_num) const {
|
||||||
Dwarf_Attribute attr;
|
Dwarf_Attribute attr;
|
||||||
if(wrap(dwarf_attr, die, attr_num, &attr) == DW_DLV_OK) {
|
auto ret = wrap(dwarf_attr, die, attr_num, &attr);
|
||||||
|
if (ret.is_error()) {
|
||||||
|
ret.drop_error();
|
||||||
|
} else if(ret.unwrap_value() == DW_DLV_OK) {
|
||||||
auto attwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
auto attwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
||||||
// Dwarf_Half form = 0;
|
|
||||||
// VERIFY(wrap(dwarf_whatform, attr, &form) == DW_DLV_OK);
|
|
||||||
Dwarf_Unsigned val;
|
Dwarf_Unsigned val;
|
||||||
VERIFY(wrap(dwarf_formudata, attr, &val) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_formudata, attr, &val));
|
||||||
return val;
|
return Ok(val);
|
||||||
} else {
|
|
||||||
return nullopt;
|
|
||||||
}
|
}
|
||||||
|
return Ok(nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_attr(Dwarf_Half attr_num) const {
|
Result<bool, internal_error> has_attr(Dwarf_Half attr_num) const {
|
||||||
Dwarf_Bool present = false;
|
Dwarf_Bool present = false;
|
||||||
VERIFY(wrap(dwarf_hasattr, die, attr_num, &present) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_hasattr, die, attr_num, &present));
|
||||||
return present;
|
return present;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dwarf_Half get_tag() const {
|
Result<Dwarf_Half, internal_error> get_tag() const {
|
||||||
Dwarf_Half tag = 0;
|
Dwarf_Half tag = 0;
|
||||||
VERIFY(wrap(dwarf_tag, die, &tag) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_tag, die, &tag));
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* get_tag_name() const {
|
const char* get_tag_name() const {
|
||||||
const char* tag_name;
|
const char* tag_name;
|
||||||
if(dwarf_get_TAG_name(get_tag(), &tag_name) == DW_DLV_OK) {
|
auto tag = get_tag();
|
||||||
|
if(!tag) {
|
||||||
|
tag.drop_error();
|
||||||
|
} else if(dwarf_get_TAG_name(tag.unwrap_value(), &tag_name) == DW_DLV_OK) {
|
||||||
return tag_name;
|
return tag_name;
|
||||||
} else {
|
|
||||||
return "<unknown tag name>";
|
|
||||||
}
|
}
|
||||||
|
return "<unknown tag name>";
|
||||||
}
|
}
|
||||||
|
|
||||||
Dwarf_Off get_global_offset() const {
|
Result<Dwarf_Off, internal_error> get_global_offset() const {
|
||||||
Dwarf_Off off;
|
Dwarf_Off off;
|
||||||
VERIFY(wrap(dwarf_dieoffset, die, &off) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_dieoffset, die, &off));
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
die_object resolve_reference_attribute(Dwarf_Half attr_num) const {
|
Result<die_object, internal_error> resolve_reference_attribute(Dwarf_Half attr_num) const {
|
||||||
Dwarf_Attribute attr;
|
Dwarf_Attribute attr;
|
||||||
VERIFY(dwarf_attr(die, attr_num, &attr, nullptr) == DW_DLV_OK);
|
CHECK_OK(dwarf_attr(die, attr_num, &attr, nullptr));
|
||||||
auto wrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
auto wrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
||||||
Dwarf_Half form = 0;
|
Dwarf_Half form = 0;
|
||||||
VERIFY(wrap(dwarf_whatform, attr, &form) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_whatform, attr, &form));
|
||||||
switch(form) {
|
switch(form) {
|
||||||
case DW_FORM_ref1:
|
case DW_FORM_ref1:
|
||||||
case DW_FORM_ref2:
|
case DW_FORM_ref2:
|
||||||
@ -209,77 +263,86 @@ namespace libdwarf {
|
|||||||
{
|
{
|
||||||
Dwarf_Off off = 0;
|
Dwarf_Off off = 0;
|
||||||
Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die);
|
Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die);
|
||||||
VERIFY(wrap(dwarf_formref, attr, &off, &is_info) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_formref, attr, &off, &is_info));
|
||||||
Dwarf_Off global_offset = 0;
|
Dwarf_Off global_offset = 0;
|
||||||
VERIFY(wrap(dwarf_convert_to_global_offset, attr, off, &global_offset) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_convert_to_global_offset, attr, off, &global_offset));
|
||||||
Dwarf_Die target = nullptr;
|
Dwarf_Die target = nullptr;
|
||||||
VERIFY(wrap(dwarf_offdie_b, dbg, global_offset, is_info, &target) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_offdie_b, dbg, global_offset, is_info, &target));
|
||||||
return die_object(dbg, target);
|
return die_object(dbg, target);
|
||||||
}
|
}
|
||||||
case DW_FORM_ref_addr:
|
case DW_FORM_ref_addr:
|
||||||
{
|
{
|
||||||
Dwarf_Off off;
|
Dwarf_Off off;
|
||||||
VERIFY(wrap(dwarf_global_formref, attr, &off) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_global_formref, attr, &off));
|
||||||
int is_info = dwarf_get_die_infotypes_flag(die);
|
int is_info = dwarf_get_die_infotypes_flag(die);
|
||||||
Dwarf_Die target = nullptr;
|
Dwarf_Die target = nullptr;
|
||||||
VERIFY(wrap(dwarf_offdie_b, dbg, off, is_info, &target) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_offdie_b, dbg, off, is_info, &target));
|
||||||
return die_object(dbg, target);
|
return die_object(dbg, target);
|
||||||
}
|
}
|
||||||
case DW_FORM_ref_sig8:
|
case DW_FORM_ref_sig8:
|
||||||
{
|
{
|
||||||
Dwarf_Sig8 signature;
|
Dwarf_Sig8 signature;
|
||||||
VERIFY(wrap(dwarf_formsig8, attr, &signature) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_formsig8, attr, &signature));
|
||||||
Dwarf_Die target = nullptr;
|
Dwarf_Die target = nullptr;
|
||||||
Dwarf_Bool targ_is_info = false;
|
Dwarf_Bool targ_is_info = false;
|
||||||
VERIFY(wrap(dwarf_find_die_given_sig8, dbg, &signature, &target, &targ_is_info) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_find_die_given_sig8, dbg, &signature, &target, &targ_is_info));
|
||||||
return die_object(dbg, target);
|
return die_object(dbg, target);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
PANIC(microfmt::format("unknown form for attribute {} {}\n", attr_num, form));
|
return internal_error(microfmt::format("unknown form for attribute {} {}", attr_num, form));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dwarf_Unsigned get_ranges_offset(Dwarf_Attribute attr) const {
|
Result<Dwarf_Unsigned, internal_error> get_ranges_offset(Dwarf_Attribute attr) const {
|
||||||
Dwarf_Unsigned off = 0;
|
Dwarf_Unsigned off = 0;
|
||||||
Dwarf_Half form = 0;
|
Dwarf_Half form = 0;
|
||||||
VERIFY(wrap(dwarf_whatform, attr, &form) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_whatform, attr, &form));
|
||||||
if (form == DW_FORM_rnglistx) {
|
if (form == DW_FORM_rnglistx) {
|
||||||
VERIFY(wrap(dwarf_formudata, attr, &off) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_formudata, attr, &off));
|
||||||
} else {
|
} else {
|
||||||
VERIFY(wrap(dwarf_global_formref, attr, &off) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_global_formref, attr, &off));
|
||||||
}
|
}
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
// callback should return true to keep going
|
// callback should return true to keep going
|
||||||
void dwarf5_ranges(F callback) const {
|
NODISCARD
|
||||||
|
Result<monostate, internal_error> dwarf5_ranges(F callback) const {
|
||||||
Dwarf_Attribute attr = nullptr;
|
Dwarf_Attribute attr = nullptr;
|
||||||
if(wrap(dwarf_attr, die, DW_AT_ranges, &attr) != DW_DLV_OK) {
|
auto ranges_res = wrap(dwarf_attr, die, DW_AT_ranges, &attr);
|
||||||
return;
|
if(ranges_res.is_error()) {
|
||||||
|
return ranges_res.unwrap_error();
|
||||||
|
} else if(ranges_res.unwrap_value() != DW_DLV_OK) {
|
||||||
|
return monostate{}; // normal
|
||||||
}
|
}
|
||||||
auto attrwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
auto attrwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
||||||
Dwarf_Unsigned offset = get_ranges_offset(attr);
|
PROP_ASSIGN(offset, get_ranges_offset(attr));
|
||||||
Dwarf_Half form = 0;
|
Dwarf_Half form = 0;
|
||||||
VERIFY(wrap(dwarf_whatform, attr, &form) == DW_DLV_OK);
|
CHECK_OK(wrap(dwarf_whatform, attr, &form));
|
||||||
// get .debug_rnglists info
|
// get .debug_rnglists info
|
||||||
Dwarf_Rnglists_Head head = nullptr;
|
Dwarf_Rnglists_Head head = nullptr;
|
||||||
Dwarf_Unsigned rnglists_entries = 0;
|
Dwarf_Unsigned rnglists_entries = 0;
|
||||||
Dwarf_Unsigned dw_global_offset_of_rle_set = 0;
|
Dwarf_Unsigned dw_global_offset_of_rle_set = 0;
|
||||||
int res = wrap(
|
PROP_ASSIGN(
|
||||||
dwarf_rnglists_get_rle_head,
|
res,
|
||||||
attr,
|
wrap(
|
||||||
form,
|
dwarf_rnglists_get_rle_head,
|
||||||
offset,
|
attr,
|
||||||
&head,
|
form,
|
||||||
&rnglists_entries,
|
offset,
|
||||||
&dw_global_offset_of_rle_set
|
&head,
|
||||||
|
&rnglists_entries,
|
||||||
|
&dw_global_offset_of_rle_set
|
||||||
|
)
|
||||||
);
|
);
|
||||||
auto headwrapper = raii_wrap(head, [] (Dwarf_Rnglists_Head head) { dwarf_dealloc_rnglists_head(head); });
|
auto headwrapper = raii_wrap(head, [] (Dwarf_Rnglists_Head head) { dwarf_dealloc_rnglists_head(head); });
|
||||||
if(res == DW_DLV_NO_ENTRY) {
|
if(res == DW_DLV_NO_ENTRY) {
|
||||||
return;
|
return monostate{}; // I guess normal
|
||||||
|
}
|
||||||
|
if(res != DW_DLV_OK) {
|
||||||
|
return internal_error("dwarf_rnglists_get_rle_head not ok");
|
||||||
}
|
}
|
||||||
VERIFY(res == DW_DLV_OK);
|
|
||||||
for(std::size_t i = 0 ; i < rnglists_entries; i++) {
|
for(std::size_t i = 0 ; i < rnglists_entries; i++) {
|
||||||
unsigned entrylen = 0;
|
unsigned entrylen = 0;
|
||||||
unsigned rle_value_out = 0;
|
unsigned rle_value_out = 0;
|
||||||
@ -288,22 +351,27 @@ namespace libdwarf {
|
|||||||
Dwarf_Bool unavailable = 0;
|
Dwarf_Bool unavailable = 0;
|
||||||
Dwarf_Unsigned cooked1 = 0;
|
Dwarf_Unsigned cooked1 = 0;
|
||||||
Dwarf_Unsigned cooked2 = 0;
|
Dwarf_Unsigned cooked2 = 0;
|
||||||
res = wrap(
|
PROP_ASSIGN(
|
||||||
dwarf_get_rnglists_entry_fields_a,
|
res2,
|
||||||
head,
|
wrap(
|
||||||
i,
|
dwarf_get_rnglists_entry_fields_a,
|
||||||
&entrylen,
|
head,
|
||||||
&rle_value_out,
|
i,
|
||||||
&raw1,
|
&entrylen,
|
||||||
&raw2,
|
&rle_value_out,
|
||||||
&unavailable,
|
&raw1,
|
||||||
&cooked1,
|
&raw2,
|
||||||
&cooked2
|
&unavailable,
|
||||||
|
&cooked1,
|
||||||
|
&cooked2
|
||||||
|
)
|
||||||
);
|
);
|
||||||
if(res == DW_DLV_NO_ENTRY) {
|
if(res2 == DW_DLV_NO_ENTRY) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
VERIFY(res == DW_DLV_OK);
|
if(res2 != DW_DLV_OK) {
|
||||||
|
return internal_error("dwarf_get_rnglists_entry_fields_a not ok");
|
||||||
|
}
|
||||||
if(unavailable) {
|
if(unavailable) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -320,27 +388,31 @@ namespace libdwarf {
|
|||||||
case DW_RLE_startx_length:
|
case DW_RLE_startx_length:
|
||||||
case DW_RLE_start_length:
|
case DW_RLE_start_length:
|
||||||
if(!callback(cooked1, cooked2)) {
|
if(!callback(cooked1, cooked2)) {
|
||||||
return;
|
return monostate{};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PANIC("Something is wrong");
|
return internal_error("rle_value_out: something is wrong");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return monostate{};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
// callback should return true to keep going
|
// callback should return true to keep going
|
||||||
void dwarf4_ranges(Dwarf_Addr lowpc, F callback) const {
|
NODISCARD
|
||||||
|
Result<monostate, internal_error> dwarf4_ranges(Dwarf_Addr lowpc, F callback) const {
|
||||||
Dwarf_Attribute attr = nullptr;
|
Dwarf_Attribute attr = nullptr;
|
||||||
if(wrap(dwarf_attr, die, DW_AT_ranges, &attr) != DW_DLV_OK) {
|
PROP_ASSIGN(res, wrap(dwarf_attr, die, DW_AT_ranges, &attr));
|
||||||
return;
|
if(res != DW_DLV_OK) {
|
||||||
|
return monostate{}; // normal
|
||||||
}
|
}
|
||||||
auto attrwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
auto attrwrapper = raii_wrap(attr, [] (Dwarf_Attribute attr) { dwarf_dealloc_attribute(attr); });
|
||||||
Dwarf_Unsigned offset;
|
Dwarf_Unsigned offset;
|
||||||
if(wrap(dwarf_global_formref, attr, &offset) != DW_DLV_OK) {
|
PROP_ASSIGN(res2, wrap(dwarf_global_formref, attr, &offset));
|
||||||
return;
|
if(res2 != DW_DLV_OK) {
|
||||||
|
return monostate{}; // normal
|
||||||
}
|
}
|
||||||
Dwarf_Addr baseaddr = 0;
|
Dwarf_Addr baseaddr = 0;
|
||||||
if(lowpc != (std::numeric_limits<Dwarf_Addr>::max)()) {
|
if(lowpc != (std::numeric_limits<Dwarf_Addr>::max)()) {
|
||||||
@ -348,7 +420,7 @@ namespace libdwarf {
|
|||||||
}
|
}
|
||||||
Dwarf_Ranges* ranges = nullptr;
|
Dwarf_Ranges* ranges = nullptr;
|
||||||
Dwarf_Signed count = 0;
|
Dwarf_Signed count = 0;
|
||||||
VERIFY(
|
CHECK_OK(
|
||||||
wrap(
|
wrap(
|
||||||
dwarf_get_ranges_b,
|
dwarf_get_ranges_b,
|
||||||
dbg,
|
dbg,
|
||||||
@ -358,7 +430,7 @@ namespace libdwarf {
|
|||||||
&ranges,
|
&ranges,
|
||||||
&count,
|
&count,
|
||||||
nullptr
|
nullptr
|
||||||
) == DW_DLV_OK
|
)
|
||||||
);
|
);
|
||||||
auto rangeswrapper = raii_wrap(
|
auto rangeswrapper = raii_wrap(
|
||||||
ranges,
|
ranges,
|
||||||
@ -367,7 +439,7 @@ namespace libdwarf {
|
|||||||
for(int i = 0; i < count; i++) {
|
for(int i = 0; i < count; i++) {
|
||||||
if(ranges[i].dwr_type == DW_RANGES_ENTRY) {
|
if(ranges[i].dwr_type == DW_RANGES_ENTRY) {
|
||||||
if(!callback(baseaddr + ranges[i].dwr_addr1, baseaddr + ranges[i].dwr_addr2)) {
|
if(!callback(baseaddr + ranges[i].dwr_addr1, baseaddr + ranges[i].dwr_addr2)) {
|
||||||
return;
|
return monostate{};
|
||||||
}
|
}
|
||||||
} else if(ranges[i].dwr_type == DW_RANGES_ADDRESS_SELECTION) {
|
} else if(ranges[i].dwr_type == DW_RANGES_ADDRESS_SELECTION) {
|
||||||
baseaddr = ranges[i].dwr_addr2;
|
baseaddr = ranges[i].dwr_addr2;
|
||||||
@ -376,63 +448,76 @@ namespace libdwarf {
|
|||||||
baseaddr = lowpc;
|
baseaddr = lowpc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return monostate{};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
// callback should return true to keep going
|
// callback should return true to keep going
|
||||||
void dwarf_ranges(int version, optional<Dwarf_Addr> pc, F callback) const {
|
NODISCARD
|
||||||
|
Result<monostate, internal_error> dwarf_ranges(int version, optional<Dwarf_Addr> pc, F callback) const {
|
||||||
Dwarf_Addr lowpc = (std::numeric_limits<Dwarf_Addr>::max)();
|
Dwarf_Addr lowpc = (std::numeric_limits<Dwarf_Addr>::max)();
|
||||||
if(wrap(dwarf_lowpc, die, &lowpc) == DW_DLV_OK) {
|
PROP_ASSIGN(res, wrap(dwarf_lowpc, die, &lowpc));
|
||||||
|
if(res == DW_DLV_OK) {
|
||||||
if(pc.has_value() && pc.unwrap() == lowpc) {
|
if(pc.has_value() && pc.unwrap() == lowpc) {
|
||||||
callback(lowpc, lowpc + 1);
|
callback(lowpc, lowpc + 1);
|
||||||
return;
|
return monostate{};
|
||||||
}
|
}
|
||||||
Dwarf_Addr highpc = 0;
|
Dwarf_Addr highpc = 0;
|
||||||
enum Dwarf_Form_Class return_class;
|
enum Dwarf_Form_Class return_class;
|
||||||
if(wrap(dwarf_highpc_b, die, &highpc, nullptr, &return_class) == DW_DLV_OK) {
|
PROP_ASSIGN(res2, wrap(dwarf_highpc_b, die, &highpc, nullptr, &return_class));
|
||||||
|
if(res2 == DW_DLV_OK) {
|
||||||
if(return_class == DW_FORM_CLASS_CONSTANT) {
|
if(return_class == DW_FORM_CLASS_CONSTANT) {
|
||||||
highpc += lowpc;
|
highpc += lowpc;
|
||||||
}
|
}
|
||||||
if(!callback(lowpc, highpc)) {
|
if(!callback(lowpc, highpc)) {
|
||||||
return;
|
return monostate{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(version >= 5) {
|
if(version >= 5) {
|
||||||
dwarf5_ranges(callback);
|
return dwarf5_ranges(callback);
|
||||||
} else {
|
} else {
|
||||||
dwarf4_ranges(lowpc, callback);
|
return dwarf4_ranges(lowpc, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<Dwarf_Addr, Dwarf_Addr>> get_rangelist_entries(int version) const {
|
struct address_range {
|
||||||
std::vector<std::pair<Dwarf_Addr, Dwarf_Addr>> vec;
|
Dwarf_Addr low;
|
||||||
dwarf_ranges(version, nullopt, [&vec] (Dwarf_Addr low, Dwarf_Addr high) {
|
Dwarf_Addr high;
|
||||||
// Simple coalescing optimization:
|
};
|
||||||
// Sometimes the range list entries are really continuous: [100, 200), [200, 300)
|
|
||||||
// Other times there's just one byte of separation [300, 399), [400, 500)
|
Result<std::vector<address_range>, internal_error> get_rangelist_entries(int version) const {
|
||||||
// Those are the main two cases I've observed.
|
std::vector<address_range> vec;
|
||||||
// This will not catch all cases, presumably, as the range lists aren't sorted. But compilers/linkers
|
PROP(
|
||||||
// seem to like to emit the ranges in sorted order.
|
dwarf_ranges(version, nullopt, [&vec] (Dwarf_Addr low, Dwarf_Addr high) {
|
||||||
if(!vec.empty() && low - vec.back().second <= 1) {
|
// Simple coalescing optimization:
|
||||||
vec.back().second = high;
|
// Sometimes the range list entries are really continuous: [100, 200), [200, 300)
|
||||||
} else {
|
// Other times there's just one byte of separation [300, 399), [400, 500)
|
||||||
vec.push_back({low, high});
|
// Those are the main two cases I've observed.
|
||||||
}
|
// This will not catch all cases, presumably, as the range lists aren't sorted.
|
||||||
return true;
|
// But compilers/linkers seem to like to emit the ranges in sorted order.
|
||||||
});
|
if(!vec.empty() && low - vec.back().high <= 1) {
|
||||||
|
vec.back().high = high;
|
||||||
|
} else {
|
||||||
|
vec.push_back({low, high});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
);
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dwarf_Bool pc_in_die(int version, Dwarf_Addr pc) const {
|
Result<Dwarf_Bool, internal_error> pc_in_die(int version, Dwarf_Addr pc) const {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
dwarf_ranges(version, pc, [&found, pc] (Dwarf_Addr low, Dwarf_Addr high) {
|
PROP(
|
||||||
if(pc >= low && pc < high) {
|
dwarf_ranges(version, pc, [&found, pc] (Dwarf_Addr low, Dwarf_Addr high) {
|
||||||
found = true;
|
if(pc >= low && pc < high) {
|
||||||
return false;
|
found = true;
|
||||||
}
|
return false;
|
||||||
return true;
|
}
|
||||||
});
|
return true;
|
||||||
|
})
|
||||||
|
);
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,9 +525,9 @@ namespace libdwarf {
|
|||||||
std::fprintf(
|
std::fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"%08llx %s %s\n",
|
"%08llx %s %s\n",
|
||||||
to_ull(get_global_offset()),
|
to_ull(get_global_offset().value_or(0)),
|
||||||
get_tag_name(),
|
get_tag_name(),
|
||||||
get_name().c_str()
|
get_name().drop_error().value_or("<name error>").c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -457,13 +542,22 @@ namespace libdwarf {
|
|||||||
// TODO: Refactor so there is only one fn call
|
// TODO: Refactor so there is only one fn call
|
||||||
bool continue_traversal = true;
|
bool continue_traversal = true;
|
||||||
if(fn(die)) {
|
if(fn(die)) {
|
||||||
die_object current = die.get_sibling();
|
auto sibling = die.get_sibling();
|
||||||
while(current) {
|
if(!sibling) {
|
||||||
if(fn(current)) {
|
sibling.drop_error();
|
||||||
current = current.get_sibling();
|
} else {
|
||||||
} else {
|
die_object current = std::move(sibling).unwrap_value();
|
||||||
continue_traversal = false;
|
while(current) {
|
||||||
break;
|
if(fn(current)) {
|
||||||
|
auto sibling = current.get_sibling();
|
||||||
|
if(!sibling) {
|
||||||
|
sibling.drop_error();
|
||||||
|
}
|
||||||
|
current = std::move(sibling).unwrap_value();
|
||||||
|
} else {
|
||||||
|
continue_traversal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,8 +575,10 @@ namespace libdwarf {
|
|||||||
die,
|
die,
|
||||||
[&fn](const die_object& die) {
|
[&fn](const die_object& die) {
|
||||||
auto child = die.get_child();
|
auto child = die.get_child();
|
||||||
if(child) {
|
if(child.is_error()) {
|
||||||
if(!walk_die_list_recursive(child, fn)) {
|
child.drop_error();
|
||||||
|
} else if(child.unwrap_value()) {
|
||||||
|
if(!walk_die_list_recursive(child.unwrap_value(), fn)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,10 @@ namespace detail {
|
|||||||
class internal_error : public std::exception {
|
class internal_error : public std::exception {
|
||||||
std::string msg;
|
std::string msg;
|
||||||
public:
|
public:
|
||||||
internal_error(std::string message) : msg(std::move(message)) {}
|
internal_error(std::string message) : msg("Cpptrace internal error: " + std::move(message)) {}
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
internal_error(const char* format, Args&&... args) : msg(microfmt::format(format, args...)) {}
|
internal_error(const char* format, Args&&... args)
|
||||||
|
: msg("Cpptrace internal error: " + microfmt::format(format, args...)) {}
|
||||||
const char* what() const noexcept override {
|
const char* what() const noexcept override {
|
||||||
return msg.c_str();
|
return msg.c_str();
|
||||||
}
|
}
|
||||||
@ -75,23 +76,27 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] inline void panic(
|
// [[noreturn]] inline void panic(
|
||||||
const char* signature,
|
// const char* signature,
|
||||||
source_location location,
|
// source_location location,
|
||||||
const std::string& message = ""
|
// const std::string& message = ""
|
||||||
) {
|
// ) {
|
||||||
if(message == "") {
|
// if(message == "") {
|
||||||
throw internal_error(
|
// throw internal_error(
|
||||||
"Cpptrace panic {}:{}: {}\n",
|
// stringf(
|
||||||
location.file, location.line, signature
|
// "Cpptrace panic %s:%d: %s\n",
|
||||||
);
|
// location.file, location.line, signature
|
||||||
} else {
|
// )
|
||||||
throw internal_error(
|
// );
|
||||||
"Cpptrace panic {}:{}: {}: {}\n",
|
// } else {
|
||||||
location.file, location.line, signature, message.c_str()
|
// throw internal_error(
|
||||||
);
|
// stringf(
|
||||||
}
|
// "Cpptrace panic %s:%d: %s: %s\n",
|
||||||
}
|
// location.file, location.line, signature, message.c_str()
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void nullfn() {
|
void nullfn() {
|
||||||
@ -107,7 +112,7 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check condition in both debug and release. std::runtime_error on failure.
|
// Check condition in both debug and release. std::runtime_error on failure.
|
||||||
#define VERIFY(c, ...) ( \
|
/*#define VERIFY(c, ...) ( \
|
||||||
(::cpptrace::detail::as_bool(c)) \
|
(::cpptrace::detail::as_bool(c)) \
|
||||||
? static_cast<void>(0) \
|
? static_cast<void>(0) \
|
||||||
: (::cpptrace::detail::assert_fail)( \
|
: (::cpptrace::detail::assert_fail)( \
|
||||||
@ -116,7 +121,7 @@ namespace detail {
|
|||||||
CPPTRACE_PFUNC, \
|
CPPTRACE_PFUNC, \
|
||||||
{}, \
|
{}, \
|
||||||
##__VA_ARGS__) \
|
##__VA_ARGS__) \
|
||||||
)
|
)*/
|
||||||
|
|
||||||
// Workaround a compiler warning
|
// Workaround a compiler warning
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -128,8 +133,8 @@ namespace detail {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check condition in both debug and release. std::runtime_error on failure.
|
// // Check condition in both debug and release. std::runtime_error on failure.
|
||||||
#define PANIC(...) ((::cpptrace::detail::panic)(CPPTRACE_PFUNC, {}, ::cpptrace::detail::as_string(__VA_ARGS__)))
|
// #define PANIC(...) ((::cpptrace::detail::panic)(CPPTRACE_PFUNC, {}, ::cpptrace::detail::as_string(__VA_ARGS__)))
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Check condition in both debug. std::runtime_error on failure.
|
// Check condition in both debug. std::runtime_error on failure.
|
||||||
|
|||||||
@ -325,6 +325,26 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct OkResult {
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ErrorResult {
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
OkResult<T> Ok(T value) {
|
||||||
|
return {value};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ErrorResult<T> Error(T value) {
|
||||||
|
return {value};
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Better dump error
|
// TODO: Better dump error
|
||||||
// TODO: Explicit constructors for value, then add Ok()/Error() helpers
|
// TODO: Explicit constructors for value, then add Ok()/Error() helpers
|
||||||
template<typename T, typename E, typename std::enable_if<!std::is_same<T, E>::value, int>::type = 0>
|
template<typename T, typename E, typename std::enable_if<!std::is_same<T, E>::value, int>::type = 0>
|
||||||
@ -339,6 +359,10 @@ namespace detail {
|
|||||||
public:
|
public:
|
||||||
Result(T value) : value_(std::move(value)), active(member::value) {}
|
Result(T value) : value_(std::move(value)), active(member::value) {}
|
||||||
Result(E error) : error_(std::move(error)), active(member::error) {}
|
Result(E error) : error_(std::move(error)), active(member::error) {}
|
||||||
|
template<typename U>
|
||||||
|
Result(OkResult<U>&& value) : value_(std::move(value.value)), active(member::value) {}
|
||||||
|
template<typename U>
|
||||||
|
Result(ErrorResult<U>&& error) : error_(std::move(error.value)), active(member::error) {}
|
||||||
Result(Result&& other) : active(other.active) {
|
Result(Result&& other) : active(other.active) {
|
||||||
if(other.active == member::value) {
|
if(other.active == member::value) {
|
||||||
new (&value_) T(std::move(other.value_));
|
new (&value_) T(std::move(other.value_));
|
||||||
@ -422,10 +446,11 @@ namespace detail {
|
|||||||
return has_value() ? std::move(value_) : static_cast<T>(std::forward<U>(default_value));
|
return has_value() ? std::move(value_) : static_cast<T>(std::forward<U>(default_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void drop_error() const {
|
const Result& drop_error() const {
|
||||||
if(is_error()) {
|
if(is_error()) {
|
||||||
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user