diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1077,33 +1077,6 @@ return None; } -static Optional -getLocationFrameOffset(DWARFCompileUnit *CU, DWARFFormValue &FormValue, - Optional FrameBaseReg) { - if (Optional> Location = FormValue.getAsBlock()) { - return getExpressionFrameOffset(*Location, FrameBaseReg); - } else if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { - uint64_t Offset = *FormValue.getAsSectionOffset(); - const DWARFLocationTable &LocTable = CU->getLocationTable(); - Optional FrameOffset; - Error E = LocTable.visitLocationList( - &Offset, [&](const DWARFLocationEntry &Entry) { - if (Entry.Kind == dwarf::DW_LLE_base_address || - Entry.Kind == dwarf::DW_LLE_base_addressx || - Entry.Kind == dwarf::DW_LLE_end_of_list) { - return true; - } - if ((FrameOffset = getExpressionFrameOffset(Entry.Loc, FrameBaseReg))) - return false; - return true; - }); - if (E) - return None; - return FrameOffset; - } - return None; -} - void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die, std::vector &Result) { if (Die.getTag() == DW_TAG_variable || @@ -1119,8 +1092,19 @@ (*Expr)[0] <= DW_OP_reg31) { FrameBaseReg = (*Expr)[0] - DW_OP_reg0; } - if (auto LocationAttr = Die.find(DW_AT_location)) - Local.FrameOffset = getLocationFrameOffset(CU, *LocationAttr, FrameBaseReg); + + if (Expected> Loc = + Die.getLocations(DW_AT_location)) { + for (const auto &Entry : *Loc) { + if (Optional FrameOffset = + getExpressionFrameOffset(Entry.Expr, FrameBaseReg)) { + Local.FrameOffset = *FrameOffset; + break; + } + } + } else { + consumeError(Loc.takeError()); + } if (auto TagOffsetAttr = Die.find(DW_AT_LLVM_tag_offset)) Local.TagOffset = TagOffsetAttr->getAsUnsignedConstant(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -495,8 +495,18 @@ return createStringError(inconvertibleErrorCode(), "No %s", dwarf::AttributeString(Attr).data()); - if (Optional Off = Location->getAsSectionOffset()) - return U->findLoclistFromOffset(*Off); + if (Optional Off = Location->getAsSectionOffset()) { + uint64_t Offset = *Off; + + if (Location->getForm() == DW_FORM_loclistx) { + if (auto LoclistOffset = U->getLoclistOffset(Offset)) + Offset = *LoclistOffset + getDwarfUnit()->getLocSectionBase(); + else + return createStringError(inconvertibleErrorCode(), + "Loclist table not found"); + } + return U->findLoclistFromOffset(Offset); + } if (Optional> Expr = Location->getAsBlock()) { return DWARFLocationExpressionsVector{ diff --git a/llvm/test/tools/llvm-symbolizer/frame-loclistx.s b/llvm/test/tools/llvm-symbolizer/frame-loclistx.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/frame-loclistx.s @@ -0,0 +1,284 @@ +// Test dwarf-5 DW_AT_location [DW_FORM_loclistx]. +// REQUIRES: aarch64-registered-target + +// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android -o %t.o %s +// RUN: echo 'FRAME %t.o 0x4' | llvm-symbolizer | FileCheck %s + +// DW_AT_location (indexed (0x0) loclist = 0x00000010: +// [0x0000000000000010, 0x0000000000000018): DW_OP_consts +1, DW_OP_stack_value +// [0x0000000000000018, 0x0000000000000028): DW_OP_breg29 W29-4) +// CHECK: f +// CHECK-NEXT: x +// CHECK-NEXT: {{.*}}dbg.cc:5 +// CHECK-NEXT: -4 4 ?? + + .text + .file "dbg.cc" + .file 0 "/tmp" "/tmp/dbg.cc" md5 0xb9e2d9cf63655505d60c734686e688fd + .file 1 "dbg.cc" md5 0xb9e2d9cf63655505d60c734686e688fd + .globl f // -- Begin function f + .p2align 2 + .type f,@function +f: // @f +.Lfunc_begin0: + .loc 1 4 0 // dbg.cc:4:0 + .cfi_startproc +// %bb.0: + sub sp, sp, #32 // =32 + stp x29, x30, [sp, #16] // 16-byte Folded Spill + add x29, sp, #16 // =16 + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + mov w8, #1 +.Ltmp0: + //DEBUG_VALUE: f:x <- 1 + .loc 1 6 3 prologue_end // dbg.cc:6:3 + sub x0, x29, #4 // =4 + .loc 1 5 7 // dbg.cc:5:7 + stur w8, [x29, #-4] +.Ltmp1: + //DEBUG_VALUE: f:x <- [DW_OP_constu 4, DW_OP_minus, DW_OP_deref] $fp + .loc 1 6 3 // dbg.cc:6:3 + bl use +.Ltmp2: + .loc 1 7 1 // dbg.cc:7:1 + ldp x29, x30, [sp, #16] // 16-byte Folded Reload + add sp, sp, #32 // =32 + ret +.Ltmp3: +.Lfunc_end0: + .size f, .Lfunc_end0-f + .cfi_endproc + // -- End function + .section .debug_str_offsets,"",@progbits + .word 32 + .hword 5 + .hword 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 10.0.0 (git@github.com:llvm/llvm-project.git 57e2b50509793c72f562e8a08523f7ab664adfcd)" // string offset=0 +.Linfo_string1: + .asciz "/tmp/dbg.cc" // string offset=101 +.Linfo_string2: + .asciz "/tmp" // string offset=113 +.Linfo_string3: + .asciz "use" // string offset=118 +.Linfo_string4: + .asciz "f" // string offset=122 +.Linfo_string5: + .asciz "x" // string offset=124 +.Linfo_string6: + .asciz "int" // string offset=126 + .section .debug_str_offsets,"",@progbits + .word .Linfo_string0 + .word .Linfo_string1 + .word .Linfo_string2 + .word .Linfo_string3 + .word .Linfo_string4 + .word .Linfo_string5 + .word .Linfo_string6 + .section .debug_loclists,"",@progbits + .word .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 // Length +.Ldebug_loclist_table_start0: + .hword 5 // Version + .byte 8 // Address size + .byte 0 // Segment selector size + .word 1 // Offset entry count +.Lloclists_table_base0: + .word .Ldebug_loc0-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 4 // DW_LLE_offset_pair + .uleb128 .Ltmp0-.Lfunc_begin0 // starting offset + .uleb128 .Ltmp1-.Lfunc_begin0 // ending offset + .byte 3 // Loc expr size + .byte 17 // DW_OP_consts + .byte 1 // 1 + .byte 159 // DW_OP_stack_value + .byte 4 // DW_LLE_offset_pair + .uleb128 .Ltmp1-.Lfunc_begin0 // starting offset + .uleb128 .Lfunc_end0-.Lfunc_begin0 // ending offset + .byte 2 // Loc expr size + .byte 141 // DW_OP_breg29 + .byte 124 // -4 + .byte 0 // DW_LLE_end_of_list +.Ldebug_loclist_table_end0: + .section .debug_abbrev,"",@progbits + .byte 1 // Abbreviation Code + .byte 17 // DW_TAG_compile_unit + .byte 1 // DW_CHILDREN_yes + .byte 37 // DW_AT_producer + .byte 37 // DW_FORM_strx1 + .byte 19 // DW_AT_language + .byte 5 // DW_FORM_data2 + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 114 // DW_AT_str_offsets_base + .byte 23 // DW_FORM_sec_offset + .byte 16 // DW_AT_stmt_list + .byte 23 // DW_FORM_sec_offset + .byte 27 // DW_AT_comp_dir + .byte 37 // DW_FORM_strx1 + .byte 17 // DW_AT_low_pc + .byte 27 // DW_FORM_addrx + .byte 18 // DW_AT_high_pc + .byte 6 // DW_FORM_data4 + .byte 115 // DW_AT_addr_base + .byte 23 // DW_FORM_sec_offset + .ascii "\214\001" // DW_AT_loclists_base + .byte 23 // DW_FORM_sec_offset + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 2 // Abbreviation Code + .byte 46 // DW_TAG_subprogram + .byte 1 // DW_CHILDREN_yes + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 58 // DW_AT_decl_file + .byte 11 // DW_FORM_data1 + .byte 59 // DW_AT_decl_line + .byte 11 // DW_FORM_data1 + .byte 60 // DW_AT_declaration + .byte 25 // DW_FORM_flag_present + .byte 63 // DW_AT_external + .byte 25 // DW_FORM_flag_present + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 3 // Abbreviation Code + .byte 5 // DW_TAG_formal_parameter + .byte 0 // DW_CHILDREN_no + .byte 73 // DW_AT_type + .byte 19 // DW_FORM_ref4 + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 4 // Abbreviation Code + .byte 15 // DW_TAG_pointer_type + .byte 0 // DW_CHILDREN_no + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 5 // Abbreviation Code + .byte 46 // DW_TAG_subprogram + .byte 1 // DW_CHILDREN_yes + .byte 17 // DW_AT_low_pc + .byte 27 // DW_FORM_addrx + .byte 18 // DW_AT_high_pc + .byte 6 // DW_FORM_data4 + .byte 64 // DW_AT_frame_base + .byte 24 // DW_FORM_exprloc + .byte 122 // DW_AT_call_all_calls + .byte 25 // DW_FORM_flag_present + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 58 // DW_AT_decl_file + .byte 11 // DW_FORM_data1 + .byte 59 // DW_AT_decl_line + .byte 11 // DW_FORM_data1 + .byte 63 // DW_AT_external + .byte 25 // DW_FORM_flag_present + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 6 // Abbreviation Code + .byte 52 // DW_TAG_variable + .byte 0 // DW_CHILDREN_no + .byte 2 // DW_AT_location + .byte 34 // DW_FORM_loclistx + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 58 // DW_AT_decl_file + .byte 11 // DW_FORM_data1 + .byte 59 // DW_AT_decl_line + .byte 11 // DW_FORM_data1 + .byte 73 // DW_AT_type + .byte 19 // DW_FORM_ref4 + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 7 // Abbreviation Code + .byte 72 // DW_TAG_call_site + .byte 0 // DW_CHILDREN_no + .byte 127 // DW_AT_call_origin + .byte 19 // DW_FORM_ref4 + .byte 125 // DW_AT_call_return_pc + .byte 1 // DW_FORM_addr + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 8 // Abbreviation Code + .byte 36 // DW_TAG_base_type + .byte 0 // DW_CHILDREN_no + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 62 // DW_AT_encoding + .byte 11 // DW_FORM_data1 + .byte 11 // DW_AT_byte_size + .byte 11 // DW_FORM_data1 + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 0 // EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .word .Ldebug_info_end0-.Ldebug_info_start0 // Length of Unit +.Ldebug_info_start0: + .hword 5 // DWARF version number + .byte 1 // DWARF Unit Type + .byte 8 // Address Size (in bytes) + .word .debug_abbrev // Offset Into Abbrev. Section + .byte 1 // Abbrev [1] 0xc:0x4d DW_TAG_compile_unit + .byte 0 // DW_AT_producer + .hword 33 // DW_AT_language + .byte 1 // DW_AT_name + .word .Lstr_offsets_base0 // DW_AT_str_offsets_base + .word .Lline_table_start0 // DW_AT_stmt_list + .byte 2 // DW_AT_comp_dir + .byte 0 // DW_AT_low_pc + .word .Lfunc_end0-.Lfunc_begin0 // DW_AT_high_pc + .word .Laddr_table_base0 // DW_AT_addr_base + .word .Lloclists_table_base0 // DW_AT_loclists_base + .byte 2 // Abbrev [2] 0x27:0xa DW_TAG_subprogram + .byte 3 // DW_AT_name + .byte 1 // DW_AT_decl_file + .byte 2 // DW_AT_decl_line + // DW_AT_declaration + // DW_AT_external + .byte 3 // Abbrev [3] 0x2b:0x5 DW_TAG_formal_parameter + .word 49 // DW_AT_type + .byte 0 // End Of Children Mark + .byte 4 // Abbrev [4] 0x31:0x1 DW_TAG_pointer_type + .byte 5 // Abbrev [5] 0x32:0x22 DW_TAG_subprogram + .byte 0 // DW_AT_low_pc + .word .Lfunc_end0-.Lfunc_begin0 // DW_AT_high_pc + .byte 1 // DW_AT_frame_base + .byte 109 + // DW_AT_call_all_calls + .byte 4 // DW_AT_name + .byte 1 // DW_AT_decl_file + .byte 4 // DW_AT_decl_line + // DW_AT_external + .byte 6 // Abbrev [6] 0x3d:0x9 DW_TAG_variable + .byte 0 // DW_AT_location + .byte 5 // DW_AT_name + .byte 1 // DW_AT_decl_file + .byte 5 // DW_AT_decl_line + .word 84 // DW_AT_type + .byte 7 // Abbrev [7] 0x46:0xd DW_TAG_call_site + .word 39 // DW_AT_call_origin + .xword .Ltmp2-.Lfunc_begin0 // DW_AT_call_return_pc + .byte 0 // End Of Children Mark + .byte 8 // Abbrev [8] 0x54:0x4 DW_TAG_base_type + .byte 6 // DW_AT_name + .byte 5 // DW_AT_encoding + .byte 4 // DW_AT_byte_size + .byte 0 // End Of Children Mark +.Ldebug_info_end0: + .section .debug_addr,"",@progbits + .word .Ldebug_addr_end0-.Ldebug_addr_start0 // Length of contribution +.Ldebug_addr_start0: + .hword 5 // DWARF version number + .byte 8 // Address size + .byte 0 // Segment selector size +.Laddr_table_base0: + .xword .Lfunc_begin0 +.Ldebug_addr_end0: + .ident "clang version 10.0.0 (git@github.com:llvm/llvm-project.git 57e2b50509793c72f562e8a08523f7ab664adfcd)" + .section ".note.GNU-stack","",@progbits + .section .debug_line,"",@progbits +.Lline_table_start0: