Skip to content

Commit

Permalink
DWARF: Add some support for non-native directory separators
Browse files Browse the repository at this point in the history
Summary:
If we opened a file which was produced on system with different path
syntax, we would parse the paths from the debug info incorrectly.

The reason for that is that we would parse the paths as they were
native. For example this meant that on linux we would treat the entire
windows path as a single file name with no directory component, and then
we would concatenate that with the single directory component from the
DW_AT_comp_dir attribute. When parsing posix paths on windows, we would
at least get the directory separators right, but we still would treat
the posix paths as relative, and concatenate them where we shouldn't.

This patch attempts to remedy this by guessing the path syntax used in
each compile unit. (Unfortunately, there is no info in DWARF which would
give the definitive path style used by the produces, so guessing is all
we can do.) Currently, this guessing is based on the DW_AT_comp_dir
attribute of the compile unit, but this can be refined later if needed
(for example, the DW_AT_name of the compile unit may also contain some
useful info). This style is then used when parsing the line table of
that compile unit.

This patch is sufficient to make the line tables come out right, and
enable breakpoint setting by file name work correctly. Setting a
breakpoint by full path still has some kinks (specifically, using a
windows-style full path will not work on linux because the path will be
parsed as a linux path), but this will require larger changes in how
breakpoint setting works.

Reviewers: clayborg, zturner, JDevlieghere

Subscribers: aprantl, lldb-commits

Differential Revision: https://reviews.llvm.org/D56543

llvm-svn: 351328
  • Loading branch information
labath committed Jan 16, 2019
1 parent fd9780c commit 7d36d72
Show file tree
Hide file tree
Showing 15 changed files with 382 additions and 77 deletions.
4 changes: 4 additions & 0 deletions lldb/include/lldb/Utility/FileSpec.h
Expand Up @@ -326,6 +326,10 @@ class FileSpec {
//------------------------------------------------------------------
bool IsAbsolute() const;

/// Make the FileSpec absolute by treating it relative to \a dir. Absolute
/// FileSpecs are never changed by this function.
void MakeAbsolute(const FileSpec &dir);

/// Temporary helper for FileSystem change.
void SetPath(llvm::StringRef p) { SetFile(p); }

Expand Down
@@ -0,0 +1,3 @@
image dump line-table a.c
breakpoint set -f a.c -l 1
breakpoint set -f foo/b.c -l 1
3 changes: 3 additions & 0 deletions lldb/lit/SymbolFile/DWARF/Inputs/dir-separator-posix.lldbinit
@@ -0,0 +1,3 @@
image dump line-table a.c
breakpoint set -f a.c -l 1
breakpoint set -f /tmp/b.c -l 1
@@ -0,0 +1,7 @@
image dump line-table a.c
breakpoint set -f a.c -l 1
breakpoint set -f C:/tmp/b.c -l 1

# This will fail on non-windows systems because the path will by parsed
# according to posix rules
# breakpoint set -f 'C:\tmp\b.c' -l 1
@@ -0,0 +1,62 @@
# Test that parsing of line tables works reasonably, even if the host directory
# separator does not match the separator of the compile unit.

# REQUIRES: lld

# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj > %t.o
# RUN: ld.lld %t.o -o %t
# RUN: %lldb %t -s %S/Inputs/dir-separator-no-comp-dir-relative-name.lldbinit -o exit | FileCheck %s

# CHECK-LABEL: image dump line-table a.c
# CHECK: Line table for foo/a.c
# CHECK-NEXT: 0x0000000000201000: foo/a.c:1
# CHECK-NEXT: 0x0000000000201001: foo/b.c:1
# CHECK-NEXT: 0x0000000000201002: foo/b.c:1
# CHECK-EMPTY:

# CHECK-LABEL: breakpoint set -f a.c -l 1
# CHECK: Breakpoint 1: {{.*}}`_start,

# CHECK-LABEL: breakpoint set -f foo/b.c -l 1
# CHECK: Breakpoint 2: {{.*}}`_start + 1,

.text
.globl _start
_start:
.file 1 "foo/a.c"
.loc 1 1 0
nop
.file 2 "foo/b.c"
.loc 2 1 0
nop

.section .debug_str,"MS",@progbits,1
.Linfo_string1:
.asciz "foo/a.c"
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 0 # DW_CHILDREN_no
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Lcu_end0-.Lcu_start0 # Length of Unit
.Lcu_start0:
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
.short 12 # DW_AT_language
.long .Linfo_string1 # DW_AT_name
.long .Lline_table_start0 # DW_AT_stmt_list
.Lcu_end0:
.section .debug_line,"",@progbits
.Lline_table_start0:
62 changes: 62 additions & 0 deletions lldb/lit/SymbolFile/DWARF/dir-separator-no-comp-dir.s
@@ -0,0 +1,62 @@
# Test that we properly determine the path syntax of a compile unit even if the
# compile unit does not have a DW_AT_comp_dir attribute.

# REQUIRES: lld

# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj > %t.o
# RUN: ld.lld %t.o -o %t
# RUN: %lldb %t -s %S/Inputs/dir-separator-windows.lldbinit -o exit | FileCheck %s

# CHECK-LABEL: image dump line-table a.c
# CHECK: Line table for C:\tmp\a.c
# CHECK-NEXT: 0x0000000000201000: C:\tmp\a.c:1
# CHECK-NEXT: 0x0000000000201001: C:\tmp\b.c:1
# CHECK-NEXT: 0x0000000000201002: C:\tmp\b.c:1
# CHECK-EMPTY:

# CHECK-LABEL: breakpoint set -f a.c -l 1
# CHECK: Breakpoint 1: {{.*}}`_start,

# CHECK-LABEL: breakpoint set -f C:/tmp/b.c -l 1
# CHECK: Breakpoint 2: {{.*}}`_start + 1,

.text
.globl _start
_start:
.file 1 "C:\\tmp\\a.c"
.loc 1 1 0
nop
.file 2 "C:\\tmp\\b.c"
.loc 2 1 0
nop

.section .debug_str,"MS",@progbits,1
.Linfo_string1:
.asciz "C:\\tmp\\a.c"
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 0 # DW_CHILDREN_no
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Lcu_end0-.Lcu_start0 # Length of Unit
.Lcu_start0:
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
.short 12 # DW_AT_language
.long .Linfo_string1 # DW_AT_name
.long .Lline_table_start0 # DW_AT_stmt_list
.Lcu_end0:
.section .debug_line,"",@progbits
.Lline_table_start0:
67 changes: 67 additions & 0 deletions lldb/lit/SymbolFile/DWARF/dir-separator-posix.s
@@ -0,0 +1,67 @@
# Test that parsing of line tables works reasonably, even if the host directory
# separator does not match the separator of the compile unit.

# REQUIRES: lld

# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj > %t.o
# RUN: ld.lld %t.o -o %t
# RUN: %lldb %t -s %S/Inputs/dir-separator-posix.lldbinit -o exit | FileCheck %s

# CHECK-LABEL: image dump line-table a.c
# CHECK: Line table for /tmp/a.c
# CHECK-NEXT: 0x0000000000201000: /tmp/a.c:1
# CHECK-NEXT: 0x0000000000201001: /tmp/b.c:1
# CHECK-NEXT: 0x0000000000201002: /tmp/b.c:1
# CHECK-EMPTY:

# CHECK-LABEL: breakpoint set -f a.c -l 1
# CHECK: Breakpoint 1: {{.*}}`_start,

# CHECK-LABEL: breakpoint set -f /tmp/b.c -l 1
# CHECK: Breakpoint 2: {{.*}}`_start + 1,

.text
.globl _start
_start:
.file 1 "/tmp/a.c"
.loc 1 1 0
nop
.file 2 "/tmp/b.c"
.loc 2 1 0
nop

.section .debug_str,"MS",@progbits,1
.Linfo_string1:
.asciz "a.c"
.Linfo_string2:
.asciz "/tmp"
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 0 # DW_CHILDREN_no
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 14 # DW_FORM_strp
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Lcu_end0-.Lcu_start0 # Length of Unit
.Lcu_start0:
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
.short 12 # DW_AT_language
.long .Linfo_string1 # DW_AT_name
.long .Lline_table_start0 # DW_AT_stmt_list
.long .Linfo_string2 # DW_AT_comp_dir
.Lcu_end0:
.section .debug_line,"",@progbits
.Lline_table_start0:
67 changes: 67 additions & 0 deletions lldb/lit/SymbolFile/DWARF/dir-separator-windows.s
@@ -0,0 +1,67 @@
# Test that parsing of line tables works reasonably, even if the host directory
# separator does not match the separator of the compile unit.

# REQUIRES: lld

# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj > %t.o
# RUN: ld.lld %t.o -o %t
# RUN: %lldb %t -s %S/Inputs/dir-separator-windows.lldbinit -o exit | FileCheck %s

# CHECK-LABEL: image dump line-table a.c
# CHECK: Line table for C:\tmp\a.c
# CHECK-NEXT: 0x0000000000201000: C:\tmp\a.c:1
# CHECK-NEXT: 0x0000000000201001: C:\tmp\b.c:1
# CHECK-NEXT: 0x0000000000201002: C:\tmp\b.c:1
# CHECK-EMPTY:

# CHECK-LABEL: breakpoint set -f a.c -l 1
# CHECK: Breakpoint 1: {{.*}}`_start,

# CHECK-LABEL: breakpoint set -f C:/tmp/b.c -l 1
# CHECK: Breakpoint 2: {{.*}}`_start + 1,

.text
.globl _start
_start:
.file 1 "C:\\tmp\\a.c"
.loc 1 1 0
nop
.file 2 "C:\\tmp\\b.c"
.loc 2 1 0
nop

.section .debug_str,"MS",@progbits,1
.Linfo_string1:
.asciz "a.c"
.Linfo_string2:
.asciz "C:\\tmp"
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 0 # DW_CHILDREN_no
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 14 # DW_FORM_strp
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Lcu_end0-.Lcu_start0 # Length of Unit
.Lcu_start0:
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
.short 12 # DW_AT_language
.long .Linfo_string1 # DW_AT_name
.long .Lline_table_start0 # DW_AT_stmt_list
.long .Linfo_string2 # DW_AT_comp_dir
.Lcu_end0:
.section .debug_line,"",@progbits
.Lline_table_start0:
14 changes: 9 additions & 5 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
Expand Up @@ -18,6 +18,7 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Timer.h"

#include "DWARFUnit.h"
#include "LogChannelDWARF.h"
#include "SymbolFileDWARF.h"

Expand Down Expand Up @@ -528,8 +529,7 @@ bool DWARFDebugLine::ParsePrologue(const DWARFDataExtractor &debug_line_data,

bool DWARFDebugLine::ParseSupportFiles(
const lldb::ModuleSP &module_sp, const DWARFDataExtractor &debug_line_data,
const lldb_private::FileSpec &cu_comp_dir, dw_offset_t stmt_list,
FileSpecList &support_files, DWARFUnit *dwarf_cu) {
dw_offset_t stmt_list, FileSpecList &support_files, DWARFUnit *dwarf_cu) {
lldb::offset_t offset = stmt_list;

Prologue prologue;
Expand All @@ -545,7 +545,9 @@ bool DWARFDebugLine::ParseSupportFiles(
std::string remapped_file;

for (uint32_t file_idx = 1;
prologue.GetFile(file_idx, cu_comp_dir, file_spec); ++file_idx) {
prologue.GetFile(file_idx, dwarf_cu->GetCompilationDirectory(),
dwarf_cu->GetPathStyle(), file_spec);
++file_idx) {
if (module_sp->RemapSourceFile(file_spec.GetPath(), remapped_file))
file_spec.SetFile(remapped_file, FileSpec::Style::native);
support_files.Append(file_spec);
Expand Down Expand Up @@ -947,10 +949,12 @@ void DWARFDebugLine::Prologue::Dump(Log *log) {
//}

bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx,
const lldb_private::FileSpec &comp_dir, FileSpec &file) const {
const FileSpec &comp_dir,
FileSpec::Style style,
FileSpec &file) const {
uint32_t idx = file_idx - 1; // File indexes are 1 based...
if (idx < file_names.size()) {
file.SetFile(file_names[idx].name, FileSpec::Style::native);
file.SetFile(file_names[idx].name, style);
if (file.IsRelative()) {
if (file_names[idx].dir_idx > 0) {
const uint32_t dir_idx = file_names[idx].dir_idx - 1;
Expand Down
6 changes: 4 additions & 2 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
Expand Up @@ -14,6 +14,7 @@
#include <string>
#include <vector>

#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-private.h"

#include "DWARFDataExtractor.h"
Expand Down Expand Up @@ -99,6 +100,7 @@ class DWARFDebugLine {
file_names.clear();
}
bool GetFile(uint32_t file_idx, const lldb_private::FileSpec &cu_comp_dir,
lldb_private::FileSpec::Style style,
lldb_private::FileSpec &file) const;
};

Expand Down Expand Up @@ -207,9 +209,9 @@ class DWARFDebugLine {
static bool
ParseSupportFiles(const lldb::ModuleSP &module_sp,
const lldb_private::DWARFDataExtractor &debug_line_data,
const lldb_private::FileSpec &cu_comp_dir,
dw_offset_t stmt_list,
lldb_private::FileSpecList &support_files, DWARFUnit *dwarf_cu);
lldb_private::FileSpecList &support_files,
DWARFUnit *dwarf_cu);
static bool
ParsePrologue(const lldb_private::DWARFDataExtractor &debug_line_data,
lldb::offset_t *offset_ptr, Prologue *prologue,
Expand Down

0 comments on commit 7d36d72

Please sign in to comment.