forked from OSchip/llvm-project
[DWARFv5] Parse new line-table header format.
The directory and file tables now have form-based content descriptors. Parse these and extract the per-directory/file records based on the descriptors. For now we support only DW_FORM_string (inline) for the path names; follow-up work will add support for indirect forms (i.e., DW_FORM_strp, strx<N>, and line_strp). Differential Revision: http://reviews.llvm.org/D32713 llvm-svn: 301978
This commit is contained in:
parent
d091e76e0e
commit
2bc3873fe6
|
@ -44,6 +44,10 @@ public:
|
|||
uint64_t TotalLength;
|
||||
/// Version identifier for the statement information format.
|
||||
uint16_t Version;
|
||||
/// In v5, size in bytes of an address (or segment offset).
|
||||
uint8_t AddressSize;
|
||||
/// In v5, size in bytes of a segment selector.
|
||||
uint8_t SegSelectorSize;
|
||||
/// The number of bytes following the prologue_length field to the beginning
|
||||
/// of the first byte of the statement program itself.
|
||||
uint64_t PrologueLength;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
@ -26,11 +27,19 @@ using namespace llvm;
|
|||
using namespace dwarf;
|
||||
|
||||
typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
|
||||
namespace {
|
||||
struct ContentDescriptor {
|
||||
dwarf::LineNumberEntryFormat Type;
|
||||
dwarf::Form Form;
|
||||
};
|
||||
typedef SmallVector<ContentDescriptor, 4> ContentDescriptors;
|
||||
} // end anonmyous namespace
|
||||
|
||||
DWARFDebugLine::Prologue::Prologue() { clear(); }
|
||||
|
||||
void DWARFDebugLine::Prologue::clear() {
|
||||
TotalLength = Version = PrologueLength = 0;
|
||||
AddressSize = SegSelectorSize = 0;
|
||||
MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
|
||||
OpcodeBase = 0;
|
||||
IsDWARF64 = false;
|
||||
|
@ -43,6 +52,8 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
|
|||
OS << "Line table prologue:\n"
|
||||
<< format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength)
|
||||
<< format(" version: %u\n", Version)
|
||||
<< format(Version >= 5 ? " address_size: %u\n" : "", AddressSize)
|
||||
<< format(Version >= 5 ? " seg_select_size: %u\n" : "", SegSelectorSize)
|
||||
<< format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength)
|
||||
<< format(" min_inst_length: %u\n", MinInstLength)
|
||||
<< format(Version >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst)
|
||||
|
@ -74,6 +85,125 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
|
|||
}
|
||||
}
|
||||
|
||||
// Parse v2-v4 directory and file tables.
|
||||
static void
|
||||
parseV2DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr,
|
||||
uint64_t EndPrologueOffset,
|
||||
std::vector<StringRef> &IncludeDirectories,
|
||||
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
StringRef S = DebugLineData.getCStrRef(OffsetPtr);
|
||||
if (S.empty())
|
||||
break;
|
||||
IncludeDirectories.push_back(S);
|
||||
}
|
||||
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
StringRef Name = DebugLineData.getCStrRef(OffsetPtr);
|
||||
if (Name.empty())
|
||||
break;
|
||||
DWARFDebugLine::FileNameEntry FileEntry;
|
||||
FileEntry.Name = Name;
|
||||
FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileNames.push_back(FileEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse v5 directory/file entry content descriptions.
|
||||
// Returns the descriptors, or an empty vector if we did not find a path or
|
||||
// ran off the end of the prologue.
|
||||
static ContentDescriptors
|
||||
parseV5EntryFormat(DataExtractor DebugLineData, uint32_t *OffsetPtr,
|
||||
uint64_t EndPrologueOffset) {
|
||||
ContentDescriptors Descriptors;
|
||||
int FormatCount = DebugLineData.getU8(OffsetPtr);
|
||||
bool HasPath = false;
|
||||
for (int I = 0; I != FormatCount; ++I) {
|
||||
if (*OffsetPtr >= EndPrologueOffset)
|
||||
return ContentDescriptors();
|
||||
ContentDescriptor Descriptor;
|
||||
Descriptor.Type =
|
||||
dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr));
|
||||
Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr));
|
||||
if (Descriptor.Type == dwarf::DW_LNCT_path)
|
||||
HasPath = true;
|
||||
Descriptors.push_back(Descriptor);
|
||||
}
|
||||
return HasPath ? Descriptors : ContentDescriptors();
|
||||
}
|
||||
|
||||
static bool
|
||||
parseV5DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr,
|
||||
uint64_t EndPrologueOffset,
|
||||
std::vector<StringRef> &IncludeDirectories,
|
||||
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
|
||||
// Get the directory entry description.
|
||||
ContentDescriptors DirDescriptors =
|
||||
parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset);
|
||||
if (DirDescriptors.empty())
|
||||
return false;
|
||||
|
||||
// Get the directory entries, according to the format described above.
|
||||
int DirEntryCount = DebugLineData.getU8(OffsetPtr);
|
||||
for (int I = 0; I != DirEntryCount; ++I) {
|
||||
if (*OffsetPtr >= EndPrologueOffset)
|
||||
return false;
|
||||
for (auto Descriptor : DirDescriptors) {
|
||||
DWARFFormValue Value(Descriptor.Form);
|
||||
switch (Descriptor.Type) {
|
||||
case DW_LNCT_path:
|
||||
if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr))
|
||||
return false;
|
||||
IncludeDirectories.push_back(Value.getAsCString().getValue());
|
||||
break;
|
||||
default:
|
||||
if (!Value.skipValue(DebugLineData, OffsetPtr, nullptr))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the file entry description.
|
||||
ContentDescriptors FileDescriptors =
|
||||
parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset);
|
||||
if (FileDescriptors.empty())
|
||||
return false;
|
||||
|
||||
// Get the file entries, according to the format described above.
|
||||
int FileEntryCount = DebugLineData.getU8(OffsetPtr);
|
||||
for (int I = 0; I != FileEntryCount; ++I) {
|
||||
if (*OffsetPtr >= EndPrologueOffset)
|
||||
return false;
|
||||
DWARFDebugLine::FileNameEntry FileEntry;
|
||||
for (auto Descriptor : FileDescriptors) {
|
||||
DWARFFormValue Value(Descriptor.Form);
|
||||
if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr))
|
||||
return false;
|
||||
switch (Descriptor.Type) {
|
||||
case DW_LNCT_path:
|
||||
FileEntry.Name = Value.getAsCString().getValue();
|
||||
break;
|
||||
case DW_LNCT_directory_index:
|
||||
FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue();
|
||||
break;
|
||||
case DW_LNCT_timestamp:
|
||||
FileEntry.ModTime = Value.getAsUnsignedConstant().getValue();
|
||||
break;
|
||||
case DW_LNCT_size:
|
||||
FileEntry.Length = Value.getAsUnsignedConstant().getValue();
|
||||
break;
|
||||
// FIXME: Add MD5
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
FileNames.push_back(FileEntry);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData,
|
||||
uint32_t *OffsetPtr) {
|
||||
const uint64_t PrologueOffset = *OffsetPtr;
|
||||
|
@ -90,6 +220,11 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData,
|
|||
if (Version < 2)
|
||||
return false;
|
||||
|
||||
if (Version >= 5) {
|
||||
AddressSize = DebugLineData.getU8(OffsetPtr);
|
||||
SegSelectorSize = DebugLineData.getU8(OffsetPtr);
|
||||
}
|
||||
|
||||
PrologueLength = DebugLineData.getUnsigned(OffsetPtr, sizeofPrologueLength());
|
||||
const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr;
|
||||
MinInstLength = DebugLineData.getU8(OffsetPtr);
|
||||
|
@ -106,24 +241,18 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData,
|
|||
StandardOpcodeLengths.push_back(OpLen);
|
||||
}
|
||||
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
StringRef S = DebugLineData.getCStrRef(OffsetPtr);
|
||||
if (S.empty())
|
||||
break;
|
||||
IncludeDirectories.push_back(S);
|
||||
}
|
||||
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
StringRef Name = DebugLineData.getCStrRef(OffsetPtr);
|
||||
if (Name.empty())
|
||||
break;
|
||||
FileNameEntry FileEntry;
|
||||
FileEntry.Name = Name;
|
||||
FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileNames.push_back(FileEntry);
|
||||
}
|
||||
if (Version >= 5) {
|
||||
if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
|
||||
IncludeDirectories, FileNames)) {
|
||||
fprintf(stderr,
|
||||
"warning: parsing line table prologue at 0x%8.8" PRIx64
|
||||
" found an invalid directory or file table description at"
|
||||
" 0x%8.8" PRIx64 "\n", PrologueOffset, (uint64_t)*OffsetPtr);
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
|
||||
IncludeDirectories, FileNames);
|
||||
|
||||
if (*OffsetPtr != EndPrologueOffset) {
|
||||
fprintf(stderr,
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,6 @@
|
|||
# Test object to verify dwarfdump handles v4 and v5 CU/TU headers.
|
||||
# Test object to verify dwarfdump handles v4 and v5 CU/TU/line headers.
|
||||
# We have a representative set of units: v4 CU, v5 CU, v4 TU, v5 split TU.
|
||||
# We have v4 and v5 line-table headers.
|
||||
#
|
||||
# To generate the test object:
|
||||
# llvm-mc -triple x86_64-unknown-linux dwarfdump-header.s -filetype=obj \
|
||||
|
@ -28,6 +29,8 @@ dwo_TU_5:
|
|||
.byte 0x0e # DW_FORM_strp
|
||||
.byte 0x03 # DW_AT_name
|
||||
.byte 0x0e # DW_FORM_strp
|
||||
.byte 0x10 # DW_AT_stmt_list
|
||||
.byte 0x17 # DW_FORM_sec_offset
|
||||
.byte 0x00 # EOM(1)
|
||||
.byte 0x00 # EOM(2)
|
||||
.byte 0x02 # Abbrev code
|
||||
|
@ -81,10 +84,11 @@ CU_4_version:
|
|||
.short 4 # DWARF version number
|
||||
.long .debug_abbrev # Offset Into Abbrev. Section
|
||||
.byte 8 # Address Size (in bytes)
|
||||
# The compile-unit DIE, which has just DW_AT_producer and DW_AT_name.
|
||||
# The compile-unit DIE, with DW_AT_producer, DW_AT_name, DW_AT_stmt_list.
|
||||
.byte 1
|
||||
.long str_producer
|
||||
.long str_CU_4
|
||||
.long LH_4_start
|
||||
.byte 0 # NULL
|
||||
CU_4_end:
|
||||
|
||||
|
@ -95,10 +99,11 @@ CU_5_version:
|
|||
.byte 1 # DWARF Unit Type
|
||||
.byte 8 # Address Size (in bytes)
|
||||
.long .debug_abbrev # Offset Into Abbrev. Section
|
||||
# The compile-unit DIE, which has just DW_AT_producer and DW_AT_name.
|
||||
# The compile-unit DIE, with DW_AT_producer, DW_AT_name, DW_AT_stmt_list.
|
||||
.byte 1
|
||||
.long str_producer
|
||||
.long str_CU_5
|
||||
.long LH_5_start
|
||||
.byte 0 # NULL
|
||||
CU_5_end:
|
||||
|
||||
|
@ -147,3 +152,106 @@ TU_split_5_type:
|
|||
.byte 0 # NULL
|
||||
.byte 0 # NULL
|
||||
TU_split_5_end:
|
||||
|
||||
.section .debug_line,"",@progbits
|
||||
# DWARF v4 line-table header.
|
||||
LH_4_start:
|
||||
.long LH_4_end-LH_4_version # Length of Unit
|
||||
LH_4_version:
|
||||
.short 4 # DWARF version number
|
||||
.long LH_4_header_end-LH_4_params # Length of Prologue
|
||||
LH_4_params:
|
||||
.byte 1 # Minimum Instruction Length
|
||||
.byte 1 # Maximum Operations per Instruction
|
||||
.byte 1 # Default is_stmt
|
||||
.byte -5 # Line Base
|
||||
.byte 14 # Line Range
|
||||
.byte 13 # Opcode Base
|
||||
.byte 0 # Standard Opcode Lengths
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 1
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 1
|
||||
# Directory table
|
||||
.asciz "Directory4a"
|
||||
.asciz "Directory4b"
|
||||
.byte 0
|
||||
# File table
|
||||
.asciz "File4a" # File name 1
|
||||
.byte 1 # Directory index 1
|
||||
.byte 0x41 # Timestamp 1
|
||||
.byte 0x42 # File Size 1
|
||||
.asciz "File4b" # File name 2
|
||||
.byte 0 # Directory index 2
|
||||
.byte 0x43 # Timestamp 2
|
||||
.byte 0x44 # File Size 2
|
||||
.byte 0 # End of list
|
||||
LH_4_header_end:
|
||||
# Line number program, which is empty.
|
||||
LH_4_end:
|
||||
|
||||
# DWARF v5 line-table header.
|
||||
LH_5_start:
|
||||
.long LH_5_end-LH_5_version # Length of Unit
|
||||
LH_5_version:
|
||||
.short 5 # DWARF version number
|
||||
.byte 8 # Address Size
|
||||
.byte 0 # Segment Selector Size
|
||||
.long LH_5_header_end-LH_5_params # Length of Prologue
|
||||
LH_5_params:
|
||||
.byte 1 # Minimum Instruction Length
|
||||
.byte 1 # Maximum Operations per Instruction
|
||||
.byte 1 # Default is_stmt
|
||||
.byte -5 # Line Base
|
||||
.byte 14 # Line Range
|
||||
.byte 13 # Opcode Base
|
||||
.byte 0 # Standard Opcode Lengths
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 1
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 1
|
||||
# Directory table format
|
||||
.byte 1 # One element per directory entry
|
||||
.byte 1 # DW_LNCT_path
|
||||
.byte 0x08 # DW_FORM_string
|
||||
# Directory table entries
|
||||
.byte 2 # Two directories
|
||||
.asciz "Directory5a"
|
||||
.asciz "Directory5b"
|
||||
# File table format
|
||||
.byte 4 # Four 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
|
||||
.byte 3 # DW_LNCT_timestamp
|
||||
.byte 0x0f # DW_FORM_udata
|
||||
.byte 4 # DW_LNCT_size
|
||||
.byte 0x0f # DW_FORM_udata
|
||||
# File table entries
|
||||
.byte 2 # Two files
|
||||
.asciz "File5a"
|
||||
.byte 1
|
||||
.byte 0x51
|
||||
.byte 0x52
|
||||
.asciz "File5b"
|
||||
.byte 2
|
||||
.byte 0x53
|
||||
.byte 0x54
|
||||
LH_5_header_end:
|
||||
# Line number program, which is empty.
|
||||
LH_5_end:
|
||||
|
|
|
@ -7,13 +7,13 @@ CHECK-LABEL: .debug_info contents:
|
|||
|
||||
The v4 CU header.
|
||||
|
||||
CHECK: 0x00000000: Compile Unit: length = 0x00000011 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000015)
|
||||
CHECK: 0x00000000: Compile Unit: length = 0x00000015 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000019)
|
||||
CHECK: 0x0000000b: DW_TAG_compile_unit
|
||||
|
||||
The v5 normal CU header.
|
||||
|
||||
CHECK: 0x00000015: Compile Unit: length = 0x00000012 version = 0x0005 unit_type = DW_UT_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x0000002b)
|
||||
CHECK: 0x00000021: DW_TAG_compile_unit
|
||||
CHECK: 0x00000019: Compile Unit: length = 0x00000016 version = 0x0005 unit_type = DW_UT_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000033)
|
||||
CHECK: 0x00000025: DW_TAG_compile_unit
|
||||
|
||||
CHECK-LABEL: .debug_types contents:
|
||||
|
||||
|
@ -27,3 +27,33 @@ CHECK: .debug_types.dwo contents:
|
|||
|
||||
CHECK: 0x00000000: Type Unit: length = 0x00000020 version = 0x0005 unit_type = DW_UT_split_type abbr_offset = 0x0000 addr_size = 0x08 name = 'V5_split_type_unit' type_signature = 0x8899aabbccddeeff type_offset = 0x001d (next unit at 0x00000024)
|
||||
CHECK: 0x00000018: DW_TAG_type_unit
|
||||
|
||||
CHECK-LABEL: .debug_line contents:
|
||||
|
||||
The v4 line table header.
|
||||
|
||||
CHECK: Line table prologue:
|
||||
CHECK: version: 4
|
||||
CHECK-NOT: address_size
|
||||
CHECK-NOT: seg_select_size
|
||||
CHECK: max_ops_per_inst: 1
|
||||
CHECK: include_directories[ 1] = 'Directory4a'
|
||||
CHECK: include_directories[ 2] = 'Directory4b'
|
||||
CHECK-NOT: include_directories
|
||||
CHECK: file_names[ 1] 1 0x00000041 0x00000042 File4a{{$}}
|
||||
CHECK: file_names[ 2] 0 0x00000043 0x00000044 File4b{{$}}
|
||||
CHECK-NOT: file_names
|
||||
|
||||
The v5 line table header.
|
||||
|
||||
CHECK: Line table prologue:
|
||||
CHECK: version: 5
|
||||
CHECK: address_size: 8
|
||||
CHECK: seg_select_size: 0
|
||||
CHECK: max_ops_per_inst: 1
|
||||
CHECK: include_directories[ 1] = 'Directory5a'
|
||||
CHECK: include_directories[ 2] = 'Directory5b'
|
||||
CHECK-NOT: include_directories
|
||||
CHECK: file_names[ 1] 1 0x00000051 0x00000052 File5a{{$}}
|
||||
CHECK: file_names[ 2] 2 0x00000053 0x00000054 File5b{{$}}
|
||||
CHECK-NOT: file_names
|
||||
|
|
Loading…
Reference in New Issue