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 @@ -198,15 +198,23 @@ return std::move(rel_path); } -static FileSpecList ParseSupportFilesFromPrologue( - const lldb::ModuleSP &module, - const llvm::DWARFDebugLine::Prologue &prologue, FileSpec::Style style, - llvm::StringRef compile_dir = {}, FileSpec first_file = {}) { +static FileSpecList +ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, + const llvm::DWARFDebugLine::Prologue &prologue, + FileSpec::Style style, + llvm::StringRef compile_dir = {}) { FileSpecList support_files; - support_files.Append(first_file); + size_t first_file = 0; + if (prologue.getVersion() <= 4) { + // File index 0 is not valid before DWARF v5. Add a dummy entry to ensure + // support file list indices match those we get from the debug info and line + // tables. + support_files.Append(FileSpec()); + first_file = 1; + } const size_t number_of_files = prologue.FileNames.size(); - for (size_t idx = 1; idx <= number_of_files; ++idx) { + for (size_t idx = first_file; idx <= number_of_files; ++idx) { std::string remapped_file; if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) if (!module->RemapSourceFile(llvm::StringRef(*file_path), remapped_file)) @@ -1046,8 +1054,7 @@ comp_unit.SetSupportFiles(ParseSupportFilesFromPrologue( comp_unit.GetModule(), line_table->Prologue, dwarf_cu->GetPathStyle(), - dwarf_cu->GetCompilationDirectory().GetCString(), - comp_unit.GetPrimaryFile())); + dwarf_cu->GetCompilationDirectory().GetCString())); return true; } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -1110,9 +1110,7 @@ // LLDB wants the index of the file in the list of support files. auto fn_iter = llvm::find(cci->m_file_list, *efn); lldbassert(fn_iter != cci->m_file_list.end()); - // LLDB support file indices are 1-based. - uint32_t file_index = - 1 + std::distance(cci->m_file_list.begin(), fn_iter); + uint32_t file_index = std::distance(cci->m_file_list.begin(), fn_iter); std::unique_ptr sequence( line_table->CreateLineSequenceContainer()); @@ -1155,14 +1153,6 @@ FileSpec spec(f, style); support_files.Append(spec); } - - llvm::SmallString<64> main_source_file = - m_index->compilands().GetMainSourceFile(*cci); - FileSpec::Style style = main_source_file.startswith("/") - ? FileSpec::Style::posix - : FileSpec::Style::windows; - FileSpec spec(main_source_file, style); - support_files.Insert(0, spec); return true; } diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -371,10 +371,6 @@ support_files.AppendIfUnique(spec); } - // LLDB uses the DWARF-like file numeration (one based), - // the zeroth file is the compile unit itself - support_files.Insert(0, comp_unit.GetPrimaryFile()); - return true; } @@ -1881,9 +1877,7 @@ if (!source_files) return; - // LLDB uses the DWARF-like file numeration (one based) - int index = 1; - + int index = 0; while (auto file = source_files->getNext()) { uint32_t source_id = file->getUniqueId(); index_map[source_id] = index++; diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp --- a/lldb/source/Symbol/CompileUnit.cpp +++ b/lldb/source/Symbol/CompileUnit.cpp @@ -207,30 +207,28 @@ return m_variables; } +std::vector FindFileIndexes(const FileSpecList &files, const FileSpec &file) { + std::vector result; + uint32_t idx = -1; + while ((idx = files.FindFileIndex(idx + 1, file, /*full=*/true)) != + UINT32_MAX) + result.push_back(idx); + return result; +} + uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line, const FileSpec *file_spec_ptr, bool exact, LineEntry *line_entry_ptr) { - uint32_t file_idx = 0; + if (!file_spec_ptr) + file_spec_ptr = &GetPrimaryFile(); + std::vector file_indexes = FindFileIndexes(GetSupportFiles(), *file_spec_ptr); + if (file_indexes.empty()) + return UINT32_MAX; - if (file_spec_ptr) { - file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true); - if (file_idx == UINT32_MAX) - return UINT32_MAX; - } else { - // All the line table entries actually point to the version of the Compile - // Unit that is in the support files (the one at 0 was artificially added.) - // So prefer the one further on in the support files if it exists... - const FileSpecList &support_files = GetSupportFiles(); - const bool full = true; - file_idx = support_files.FindFileIndex( - 1, support_files.GetFileSpecAtIndex(0), full); - if (file_idx == UINT32_MAX) - file_idx = 0; - } LineTable *line_table = GetLineTable(); if (line_table) - return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line, - exact, line_entry_ptr); + return line_table->FindLineEntryIndexByFileIndex( + start_idx, file_indexes, line, exact, line_entry_ptr); return UINT32_MAX; } @@ -252,7 +250,7 @@ return; uint32_t file_idx = - GetSupportFiles().FindFileIndex(1, file_spec, true); + GetSupportFiles().FindFileIndex(0, file_spec, true); while (file_idx != UINT32_MAX) { file_indexes.push_back(file_idx); file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true); diff --git a/lldb/test/Shell/SymbolFile/DWARF/dwarf5-debug_line.s b/lldb/test/Shell/SymbolFile/DWARF/dwarf5-debug_line.s new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/dwarf5-debug_line.s @@ -0,0 +1,129 @@ +# Test handling of DWARF5 line tables. In particular, test that we handle files +# which are present in the line table more than once. + +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -o %t -triple x86_64-pc-linux %s +# RUN: %lldb %t -o "source info -f file0.c" -o "source info -f file1.c" \ +# RUN: -o "breakpoint set -f file0.c -l 42" \ +# RUN: -o "breakpoint set -f file0.c -l 47" \ +# RUN: -o exit | FileCheck %s + +# CHECK-LABEL: source info -f file0.c +# CHECK: [0x0000000000000000-0x0000000000000001): /file0.c:42 +# CHECK-LABEL: source info -f file1.c +# CHECK: [0x0000000000000001-0x0000000000000002): /file1.c:47 +# CHECK-LABEL: breakpoint set -f file0.c -l 42 +# CHECK: Breakpoint 1: {{.*}}`foo, +# CHECK-LABEL: breakpoint set -f file0.c -l 47 +# CHECK: Breakpoint 2: {{.*}}`foo + 2, + + .text + .globl foo +foo: + nop + nop + nop +.Lfoo_end: + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 37 # DW_AT_producer + .byte 8 # DW_FORM_string + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 8 # DW_FORM_string + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x23 DW_TAG_compile_unit + .asciz "Hand-written DWARF" # DW_AT_producer + .short 12 # DW_AT_language + .asciz "file0.c" # DW_AT_name + .long .Lline_table_begin # DW_AT_stmt_list + .asciz "/" # DW_AT_comp_dir + .quad foo # DW_AT_low_pc + .long .Lfoo_end-foo # DW_AT_high_pc +.Ldebug_info_end0: + + .section .debug_line,"",@progbits +.Lline_table_begin: + .long .Lline_end-.Lline_start +.Lline_start: + .short 5 # DWARF version number + .byte 8 # Address Size (in bytes) + .byte 0 # Segment Selector Size + .long .Lheader_end-.Lheader_start +.Lheader_start: + .byte 1 # Minimum Instruction Length + .byte 1 # Maximum Operations per Instruction + .byte 1 # Default is_stmt + .byte 0 # Line Base + .byte 0 # Line Range + .byte 5 # Opcode Base + .byte 0, 1, 1, 1 # Standard Opcode Lengths + + # Directory table format + .byte 1 # One element per directory entry + .byte 1 # DW_LNCT_path + .byte 0x08 # DW_FORM_string + + # Directory table entries + .byte 1 # 1 directory + .asciz "/" + + # File table format + .byte 2 # 2 elements per file entry + .byte 1 # DW_LNCT_path + .byte 0x08 # DW_FORM_string + .byte 2 # DW_LNCT_directory_index + .byte 0x0b # DW_FORM_data1 + + # File table entries + .byte 3 # 3 files + .asciz "file0.c" + .byte 0 + .asciz "file1.c" + .byte 0 + .asciz "file0.c" + .byte 0 +.Lheader_end: + + .byte 4, 0 # DW_LNS_set_file 0 + .byte 0, 9, 2 # DW_LNE_set_address + .quad foo + .byte 3, 41 # DW_LNS_advance_line 41 + .byte 1 # DW_LNS_copy + + .byte 4, 1 # DW_LNS_set_file 1 + .byte 2, 1 # DW_LNS_advance_pc 1 + .byte 3, 5 # DW_LNS_advance_line 5 + .byte 1 # DW_LNS_copy + + .byte 4, 2 # DW_LNS_set_file 2 + .byte 2, 1 # DW_LNS_advance_pc 1 + .byte 1 # DW_LNS_copy + + .byte 2, 1 # DW_LNS_advance_pc 1 + .byte 0, 1, 1 # DW_LNE_end_sequence +.Lline_end: