diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -396,6 +396,7 @@ return offset - data_offset; } + case DW_OP_GNU_entry_value: case DW_OP_entry_value: // 0xa3 ULEB128 size + variable-length block { uint64_t subexpr_len = data.GetULEB128(&offset); @@ -2522,6 +2523,7 @@ stack.push_back(Scalar(value)); } break; + case DW_OP_GNU_entry_value: case DW_OP_entry_value: { if (!Evaluate_DW_OP_entry_value(stack, exe_ctx, reg_ctx, opcodes, offset, error_ptr, log)) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3601,7 +3601,8 @@ CallSiteParameterArray parameters; for (DWARFDIE child = call_site_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { - if (child.Tag() != DW_TAG_call_site_parameter) + if (child.Tag() != DW_TAG_call_site_parameter && + child.Tag() != DW_TAG_GNU_call_site_parameter) continue; llvm::Optional LocationInCallee; @@ -3631,7 +3632,7 @@ dw_attr_t attr = attributes.AttributeAtIndex(i); if (attr == DW_AT_location) LocationInCallee = parse_simple_location(i); - if (attr == DW_AT_call_value) + if (attr == DW_AT_call_value || attr == DW_AT_GNU_call_site_value) LocationInCaller = parse_simple_location(i); } @@ -3648,8 +3649,9 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // Check if the function has a supported call site-related attribute. // TODO: In the future it may be worthwhile to support call_all_source_calls. - uint64_t has_call_edges = - function_die.GetAttributeValueAsUnsigned(DW_AT_call_all_calls, 0); + bool has_call_edges = + function_die.GetAttributeValueAsUnsigned(DW_AT_call_all_calls, 0) || + function_die.GetAttributeValueAsUnsigned(DW_AT_GNU_all_call_sites, 0); if (!has_call_edges) return {}; @@ -3665,13 +3667,15 @@ std::vector> call_edges; for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { - if (child.Tag() != DW_TAG_call_site) + if (child.Tag() != DW_TAG_call_site && child.Tag() != DW_TAG_GNU_call_site) continue; llvm::Optional call_origin; llvm::Optional call_target; addr_t return_pc = LLDB_INVALID_ADDRESS; addr_t call_inst_pc = LLDB_INVALID_ADDRESS; + addr_t low_pc = LLDB_INVALID_ADDRESS; + bool tail_call = false; DWARFAttributes attributes; const size_t num_attributes = child.GetAttributes(attributes); @@ -3684,8 +3688,11 @@ dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attr == DW_AT_call_tail_call || attr == DW_AT_GNU_tail_call) + tail_call = form_value.Boolean(); + // Extract DW_AT_call_origin (the call target's DIE). - if (attr == DW_AT_call_origin) { + if (attr == DW_AT_call_origin || attr == DW_AT_abstract_origin) { call_origin = form_value.Reference(); if (!call_origin->IsValid()) { LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", @@ -3694,6 +3701,9 @@ } } + if (attr == DW_AT_low_pc) + low_pc = form_value.Address(); + // Extract DW_AT_call_return_pc (the PC the call returns to) if it's // available. It should only ever be unavailable for tail call edges, in // which case use LLDB_INVALID_ADDRESS. @@ -3708,7 +3718,7 @@ // Extract DW_AT_call_target (the location of the address of the indirect // call). - if (attr == DW_AT_call_target) { + if (attr == DW_AT_call_target || attr == DW_AT_GNU_call_site_target) { if (!DWARFFormValue::IsBlockForm(form_value.Form())) { LLDB_LOG(log, "CollectCallEdges: AT_call_target does not have block form"); @@ -3723,6 +3733,15 @@ child.GetCU()); } } + // In DWARF v4 low_pc is either the address of the call instruction or the + // "return to" address, depending on whether the call is a tail call. + if (child.Tag() == DW_TAG_GNU_call_site) { + if (tail_call) + call_inst_pc = low_pc; + else + return_pc = low_pc; + } + if (!call_origin && !call_target) { LLDB_LOG(log, "CollectCallEdges: call site without any call target"); continue; diff --git a/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/TestBasicEntryValues.py b/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/TestBasicEntryValues.py --- a/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/TestBasicEntryValues.py +++ b/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/TestBasicEntryValues.py @@ -11,3 +11,7 @@ lldbinline.MakeInlineTest(__file__, globals(), decorators=decorators, name="BasicEntryValues_V5", build_dict=dict(CXXFLAGS_EXTRAS="-O2 -glldb")) + +lldbinline.MakeInlineTest(__file__, globals(), decorators=decorators, + name="BasicEntryValues_GNU", + build_dict=dict(CXXFLAGS_EXTRAS="-O2 -ggdb")) diff --git a/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/main.cpp b/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/main.cpp --- a/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/main.cpp +++ b/lldb/test/API/functionalities/param_entry_vals/basic_entry_values/main.cpp @@ -18,8 +18,10 @@ use(dummy); ++global; - //% self.filecheck("image lookup -v -a $pc", "main.cpp", "-check-prefix=FUNC1-DESC") - // FUNC1-DESC: name = "sink", type = "int &", location = DW_OP_entry_value + //% prefix = "FUNC1-GNU" if "GNU" in self.name else "FUNC1-V5" + //% self.filecheck("image lookup -v -a $pc", "main.cpp", "-check-prefix="+prefix) + // FUNC1-GNU: name = "sink", type = "int &", location = DW_OP_GNU_entry_value + // FUNC1-V5: name = "sink", type = "int &", location = DW_OP_entry_value } __attribute__((noinline)) void func2(int &sink, int x) {