Split address information for DWARF5 split dwarf proposal. This involves

using the DW_FORM_GNU_addr_index and a separate .debug_addr section which
stays in the executable and is fully linked.

Sneak in two other small changes:

a) Print out the debug_str_offsets.dwo section.
b) Change form we're expecting the entries in the debug_str_offsets.dwo
   section to take from ULEB128 to U32.

Add tests for all of this in the fission-cu.ll test.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@172578 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Christopher 2013-01-15 23:56:56 +00:00
parent af50dda410
commit 72f7bfbf0e
13 changed files with 204 additions and 28 deletions

View File

@ -115,6 +115,7 @@ protected:
const MCSection *DwarfLineDWOSection;
const MCSection *DwarfLocDWOSection;
const MCSection *DwarfStrOffDWOSection;
const MCSection *DwarfAddrSection;
// Extra TLS Variable Data section. If the target needs to put additional
// information for a TLS variable, it'll go here.
@ -251,6 +252,9 @@ public:
const MCSection *getDwarfStrOffDWOSection() const {
return DwarfStrOffDWOSection;
}
const MCSection *getDwarfAddrSection() const {
return DwarfAddrSection;
}
const MCSection *getTLSExtraDataSection() const {
return TLSExtraDataSection;

View File

@ -198,6 +198,7 @@ void DIEInteger::EmitValue(AsmPrinter *Asm, unsigned Form) const {
case dwarf::DW_FORM_ref8: // Fall thru
case dwarf::DW_FORM_data8: Size = 8; break;
case dwarf::DW_FORM_GNU_str_index: Asm->EmitULEB128(Integer); return;
case dwarf::DW_FORM_GNU_addr_index: Asm->EmitULEB128(Integer); return;
case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return;
case dwarf::DW_FORM_sdata: Asm->EmitSLEB128(Integer); return;
case dwarf::DW_FORM_addr:
@ -222,6 +223,7 @@ unsigned DIEInteger::SizeOf(AsmPrinter *AP, unsigned Form) const {
case dwarf::DW_FORM_ref8: // Fall thru
case dwarf::DW_FORM_data8: return sizeof(int64_t);
case dwarf::DW_FORM_GNU_str_index: return MCAsmInfo::getULEB128Size(Integer);
case dwarf::DW_FORM_GNU_addr_index: return MCAsmInfo::getULEB128Size(Integer);
case dwarf::DW_FORM_udata: return MCAsmInfo::getULEB128Size(Integer);
case dwarf::DW_FORM_sdata: return MCAsmInfo::getSLEB128Size(Integer);
case dwarf::DW_FORM_addr: return AP->getDataLayout().getPointerSize();

View File

@ -170,6 +170,26 @@ void CompileUnit::addLabel(DIE *Die, unsigned Attribute, unsigned Form,
Die->addValue(Attribute, Form, Value);
}
/// addLabelAddress - Add a dwarf label attribute data and value using
/// DW_FORM_addr or DW_FORM_GNU_addr_index.
///
void CompileUnit::addLabelAddress(DIE *Die, unsigned Attribute,
MCSymbol *Label) {
if (!DD->useSplitDwarf()) {
if (Label != NULL) {
DIEValue *Value = new (DIEValueAllocator) DIELabel(Label);
Die->addValue(Attribute, dwarf::DW_FORM_addr, Value);
} else {
DIEValue *Value = new (DIEValueAllocator) DIEInteger(0);
Die->addValue(Attribute, dwarf::DW_FORM_addr, Value);
}
} else {
unsigned idx = DU->getAddrPoolIndex(Label);
DIEValue *Value = new (DIEValueAllocator) DIEInteger(idx);
Die->addValue(Attribute, dwarf::DW_FORM_GNU_addr_index, Value);
}
}
/// addDelta - Add a label delta attribute data and value.
///
void CompileUnit::addDelta(DIE *Die, unsigned Attribute, unsigned Form,

View File

@ -207,6 +207,11 @@ public:
void addLabel(DIE *Die, unsigned Attribute, unsigned Form,
const MCSymbol *Label);
/// addLabelAddress - Add a dwarf label attribute data and value using
/// either DW_FORM_addr or DW_FORM_GNU_addr_index.
///
void addLabelAddress(DIE *Die, unsigned Attribute, MCSymbol *Label);
/// addDelta - Add a label delta attribute data and value.
///
void addDelta(DIE *Die, unsigned Attribute, unsigned Form,

View File

@ -237,6 +237,15 @@ unsigned DwarfUnits::getStringPoolIndex(StringRef Str) {
return Entry.second;
}
unsigned DwarfUnits::getAddrPoolIndex(MCSymbol *Sym) {
std::pair<MCSymbol*, unsigned> &Entry = AddressPool[Sym];
if (Entry.first) return Entry.second;
Entry.second = NextAddrPoolNumber++;
Entry.first = Sym;
return Entry.second;
}
// Define a unique number for the abbreviation.
//
void DwarfUnits::assignAbbrevNumber(DIEAbbrev &Abbrev) {
@ -384,10 +393,12 @@ DIE *DwarfDebug::updateSubprogramScopeDIE(CompileUnit *SPCU,
}
}
SPCU->addLabel(SPDie, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr,
Asm->GetTempSymbol("func_begin", Asm->getFunctionNumber()));
SPCU->addLabel(SPDie, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr,
Asm->GetTempSymbol("func_end", Asm->getFunctionNumber()));
SPCU->addLabelAddress(SPDie, dwarf::DW_AT_low_pc,
Asm->GetTempSymbol("func_begin",
Asm->getFunctionNumber()));
SPCU->addLabelAddress(SPDie, dwarf::DW_AT_high_pc,
Asm->GetTempSymbol("func_end",
Asm->getFunctionNumber()));
const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
MachineLocation Location(RI->getFrameRegister(*Asm->MF));
SPCU->addAddress(SPDie, dwarf::DW_AT_frame_base, Location);
@ -429,16 +440,16 @@ DIE *DwarfDebug::constructLexicalScopeDIE(CompileUnit *TheCU,
return ScopeDIE;
}
const MCSymbol *Start = getLabelBeforeInsn(RI->first);
const MCSymbol *End = getLabelAfterInsn(RI->second);
MCSymbol *Start = getLabelBeforeInsn(RI->first);
MCSymbol *End = getLabelAfterInsn(RI->second);
if (End == 0) return 0;
assert(Start->isDefined() && "Invalid starting label for an inlined scope!");
assert(End->isDefined() && "Invalid end label for an inlined scope!");
TheCU->addLabel(ScopeDIE, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, Start);
TheCU->addLabel(ScopeDIE, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr, End);
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_low_pc, Start);
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_high_pc, End);
return ScopeDIE;
}
@ -462,8 +473,8 @@ DIE *DwarfDebug::constructInlinedScopeDIE(CompileUnit *TheCU,
}
SmallVector<InsnRange, 4>::const_iterator RI = Ranges.begin();
const MCSymbol *StartLabel = getLabelBeforeInsn(RI->first);
const MCSymbol *EndLabel = getLabelAfterInsn(RI->second);
MCSymbol *StartLabel = getLabelBeforeInsn(RI->first);
MCSymbol *EndLabel = getLabelAfterInsn(RI->second);
if (StartLabel == 0 || EndLabel == 0) {
llvm_unreachable("Unexpected Start and End labels for an inlined scope!");
@ -492,10 +503,8 @@ DIE *DwarfDebug::constructInlinedScopeDIE(CompileUnit *TheCU,
DebugRangeSymbols.push_back(NULL);
DebugRangeSymbols.push_back(NULL);
} else {
TheCU->addLabel(ScopeDIE, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr,
StartLabel);
TheCU->addLabel(ScopeDIE, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr,
EndLabel);
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_low_pc, StartLabel);
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_high_pc, EndLabel);
}
InlinedSubprogramDIEs.insert(OriginDIE);
@ -646,8 +655,8 @@ CompileUnit *DwarfDebug::constructCompileUnit(const MDNode *N) {
DIUnit.getLanguage());
NewCU->addString(Die, dwarf::DW_AT_name, FN);
// 2.17.1 requires that we use DW_AT_low_pc for a single entry point
// into an entity.
NewCU->addUInt(Die, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, 0);
// into an entity. We're using 0 (or a NULL label) for this.
NewCU->addLabelAddress(Die, dwarf::DW_AT_low_pc, NULL);
// DW_AT_stmt_list is a offset of line number information for this
// compile unit in debug_line section.
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
@ -975,6 +984,9 @@ void DwarfDebug::endModule() {
// Emit info into a debug macinfo section.
emitDebugMacInfo();
// Emit DWO addresses.
InfoHolder.emitAddresses(Asm->getObjFileLowering().getDwarfAddrSection());
// Emit inline info.
// TODO: When we don't need the option anymore we
// can remove all of the code that this section
@ -1234,14 +1246,14 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF,
}
// Return Label preceding the instruction.
const MCSymbol *DwarfDebug::getLabelBeforeInsn(const MachineInstr *MI) {
MCSymbol *DwarfDebug::getLabelBeforeInsn(const MachineInstr *MI) {
MCSymbol *Label = LabelsBeforeInsn.lookup(MI);
assert(Label && "Didn't insert label before instruction");
return Label;
}
// Return Label immediately following the instruction.
const MCSymbol *DwarfDebug::getLabelAfterInsn(const MachineInstr *MI) {
MCSymbol *DwarfDebug::getLabelAfterInsn(const MachineInstr *MI) {
return LabelsAfterInsn.lookup(MI);
}
@ -2158,7 +2170,7 @@ void DwarfUnits::emitStrings(const MCSection *StrSection,
if (OffsetSection) {
Asm->OutStreamer.SwitchSection(OffsetSection);
unsigned offset = 0;
unsigned size = 4;
unsigned size = 4; // FIXME: DWARF64 is 8.
for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
Asm->OutStreamer.EmitIntValue(offset, size);
offset += Entries[i].second->getKeyLength() + 1;
@ -2166,6 +2178,38 @@ void DwarfUnits::emitStrings(const MCSection *StrSection,
}
}
// Emit strings into a string section.
void DwarfUnits::emitAddresses(const MCSection *AddrSection) {
if (AddressPool.empty()) return;
// Start the dwarf addr section.
Asm->OutStreamer.SwitchSection(AddrSection);
// Get all of the string pool entries and put them in an array by their ID so
// we can sort them.
SmallVector<std::pair<unsigned,
std::pair<MCSymbol*, unsigned>* >, 64> Entries;
for (DenseMap<MCSymbol*, std::pair<MCSymbol*, unsigned> >::iterator
I = AddressPool.begin(), E = AddressPool.end();
I != E; ++I)
Entries.push_back(std::make_pair(I->second.second, &(I->second)));
array_pod_sort(Entries.begin(), Entries.end());
for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
// Emit a label for reference from debug information entries.
MCSymbol *Sym = Entries[i].second->first;
if (Sym)
Asm->EmitLabelReference(Entries[i].second->first,
Asm->getDataLayout().getPointerSize());
else
Asm->OutStreamer.EmitIntValue(0, Asm->getDataLayout().getPointerSize());
}
}
// Emit visible names into a debug str section.
void DwarfDebug::emitDebugStr() {
DwarfUnits &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder;
@ -2402,8 +2446,9 @@ CompileUnit *DwarfDebug::constructSkeletonCU(const MDNode *N) {
// FIXME: We also need DW_AT_addr_base and DW_AT_dwo_id.
// 2.17.1 requires that we use DW_AT_low_pc for a single entry point
// into an entity.
// into an entity. We're using 0, or a NULL label for this.
NewCU->addUInt(Die, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, 0);
// DW_AT_stmt_list is a offset of line number information for this
// compile unit in debug_line section.
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())

View File

@ -195,6 +195,10 @@ public:
typedef StringMap<std::pair<MCSymbol*, unsigned>,
BumpPtrAllocator&> StrPool;
// A Symbol->pair<Symbol, unsigned> mapping of addresses used by indirect
// references.
typedef DenseMap<MCSymbol *, std::pair<MCSymbol *, unsigned> > AddrPool;
/// \brief Collects and handles information specific to a particular
/// collection of units.
class DwarfUnits {
@ -215,12 +219,17 @@ class DwarfUnits {
unsigned NextStringPoolNumber;
std::string StringPref;
// Collection of addresses for this unit and assorted labels.
AddrPool AddressPool;
unsigned NextAddrPoolNumber;
public:
DwarfUnits(AsmPrinter *AP, FoldingSet<DIEAbbrev> *AS,
std::vector<DIEAbbrev *> *A, const char *Pref,
BumpPtrAllocator &DA) :
Asm(AP), AbbreviationsSet(AS), Abbreviations(A),
StringPool(DA), NextStringPoolNumber(0), StringPref(Pref) {}
StringPool(DA), NextStringPoolNumber(0), StringPref(Pref),
AddressPool(), NextAddrPoolNumber(0) {}
/// \brief Compute the size and offset of a DIE given an incoming Offset.
unsigned computeSizeAndOffset(DIE *Die, unsigned Offset);
@ -242,6 +251,9 @@ public:
/// \brief Emit all of the strings to the section given.
void emitStrings(const MCSection *, const MCSection *, const MCSymbol *);
/// \brief Emit all of the addresses to the section given.
void emitAddresses(const MCSection *);
/// \brief Returns the entry into the start of the pool.
MCSymbol *getStringPoolSym();
@ -255,6 +267,13 @@ public:
/// \brief Returns the string pool.
StrPool *getStringPool() { return &StringPool; }
/// \brief Returns the index into the address pool with the given
/// label/symbol.
unsigned getAddrPoolIndex(MCSymbol *);
/// \brief Returns the address pool.
AddrPool *getAddrPool() { return &AddressPool; }
};
/// \brief Collects and handles dwarf debug information.
@ -560,7 +579,7 @@ private:
}
/// \brief Return Label preceding the instruction.
const MCSymbol *getLabelBeforeInsn(const MachineInstr *MI);
MCSymbol *getLabelBeforeInsn(const MachineInstr *MI);
/// \brief Ensure that a label will be emitted after MI.
void requestLabelAfterInsn(const MachineInstr *MI) {
@ -568,7 +587,7 @@ private:
}
/// \brief Return Label immediately following the instruction.
const MCSymbol *getLabelAfterInsn(const MachineInstr *MI);
MCSymbol *getLabelAfterInsn(const MachineInstr *MI);
public:
//===--------------------------------------------------------------------===//

View File

@ -29,6 +29,7 @@ class DWARFCompileUnit {
StringRef RangeSection;
StringRef StringSection;
StringRef StringOffsetSection;
StringRef AddrOffsetSection;
const RelocAddrMap *RelocMap;
bool isLittleEndian;
@ -43,16 +44,17 @@ class DWARFCompileUnit {
public:
DWARFCompileUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS,
StringRef RS, StringRef SS, StringRef SOS,
StringRef RS, StringRef SS, StringRef SOS, StringRef AOS,
const RelocAddrMap *M, bool LE) :
Abbrev(DA), InfoSection(IS), AbbrevSection(AS),
RangeSection(RS), StringSection(SS), StringOffsetSection(SOS),
RelocMap(M), isLittleEndian(LE) {
AddrOffsetSection(AOS), RelocMap(M), isLittleEndian(LE) {
clear();
}
StringRef getStringSection() const { return StringSection; }
StringRef getStringOffsetSection() const { return StringOffsetSection; }
StringRef getAddrOffsetSection() const { return AddrOffsetSection; }
const RelocAddrMap *getRelocMap() const { return RelocMap; }
DataExtractor getDebugInfoExtractor() const;

View File

@ -86,6 +86,14 @@ void DWARFContext::dump(raw_ostream &OS) {
OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s);
strDWOOffset = offset;
}
OS << "\n.debug_str_offsets.dwo contents:\n";
DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(), 0);
offset = 0;
while (offset < getStringOffsetDWOSection().size()) {
OS << format("0x%8.8x: ", offset);
OS << format("%8.8x\n", strOffsetExt.getU32(&offset));
}
}
const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
@ -152,7 +160,8 @@ void DWARFContext::parseCompileUnits() {
while (DIData.isValidOffset(offset)) {
CUs.push_back(DWARFCompileUnit(getDebugAbbrev(), getInfoSection(),
getAbbrevSection(), getRangeSection(),
getStringSection(), "",
getStringSection(), StringRef(),
getAddrSection(),
&infoRelocMap(),
isLittleEndian()));
if (!CUs.back().extract(DIData, &offset)) {
@ -174,6 +183,7 @@ void DWARFContext::parseDWOCompileUnits() {
getRangeDWOSection(),
getStringDWOSection(),
getStringOffsetDWOSection(),
getAddrSection(),
&infoDWORelocMap(),
isLittleEndian()));
if (!DWOCUs.back().extract(DIData, &offset)) {
@ -386,6 +396,8 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
StringDWOSection = data;
else if (name == "debug_str_offsets.dwo")
StringOffsetDWOSection = data;
else if (name == "debug_addr")
AddrSection = data;
// Any more debug info sections go here.
else
continue;

View File

@ -108,6 +108,7 @@ public:
virtual StringRef getStringDWOSection() = 0;
virtual StringRef getStringOffsetDWOSection() = 0;
virtual StringRef getRangeDWOSection() = 0;
virtual StringRef getAddrSection() = 0;
virtual const RelocAddrMap &infoDWORelocMap() const = 0;
static bool isSupportedVersion(unsigned version) {
@ -143,6 +144,7 @@ class DWARFContextInMemory : public DWARFContext {
StringRef StringDWOSection;
StringRef StringOffsetDWOSection;
StringRef RangeDWOSection;
StringRef AddrSection;
public:
DWARFContextInMemory(object::ObjectFile *);
@ -163,6 +165,9 @@ public:
return StringOffsetDWOSection;
}
virtual StringRef getRangeDWOSection() { return RangeDWOSection; }
virtual StringRef getAddrSection() {
return AddrSection;
}
virtual const RelocAddrMap &infoDWORelocMap() const {
return InfoDWORelocMap;
}

View File

@ -325,6 +325,16 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const {
switch (Form) {
case DW_FORM_addr: OS << format("0x%016" PRIx64, uvalue); break;
case DW_FORM_GNU_addr_index: {
StringRef AddrOffsetSec = cu->getAddrOffsetSection();
OS << format(" indexed (%8.8x) address = ", (uint32_t)uvalue);
if (AddrOffsetSec.size() != 0) {
DataExtractor DA(AddrOffsetSec, true, cu->getAddressByteSize());
OS << format("0x%016" PRIx64, getIndirectAddress(&DA, cu));
} else
OS << "<no .debug_addr section>";
break;
}
case DW_FORM_flag_present: OS << "true"; break;
case DW_FORM_flag:
case DW_FORM_data1: OS << format("0x%02x", (uint8_t)uvalue); break;
@ -452,10 +462,19 @@ DWARFFormValue::getIndirectCString(const DataExtractor *DS,
if (!DS || !DSO) return NULL;
uint32_t offset = Value.uval * 4;
uint32_t soffset = DSO->getULEB128(&offset);
uint32_t soffset = DSO->getU32(&offset);
return DS->getCStr(&soffset);
}
uint64_t
DWARFFormValue::getIndirectAddress(const DataExtractor *DA,
const DWARFCompileUnit *cu) const {
if (!DA) return 0;
uint32_t offset = Value.uval * cu->getAddressByteSize();
return DA->getAddress(&offset);
}
uint64_t DWARFFormValue::getReference(const DWARFCompileUnit *cu) const {
uint64_t die_offset = Value.uval;
switch (Form) {

View File

@ -66,6 +66,8 @@ public:
const char *getAsCString(const DataExtractor *debug_str_data_ptr) const;
const char *getIndirectCString(const DataExtractor *,
const DataExtractor *) const;
uint64_t getIndirectAddress(const DataExtractor *,
const DWARFCompileUnit *) const;
bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr,
const DWARFCompileUnit *cu) const;
static bool skipValue(uint16_t form, DataExtractor debug_info_data,

View File

@ -437,6 +437,9 @@ void MCObjectFileInfo::InitELFMCObjectFileInfo(Triple T) {
DwarfStrOffDWOSection =
Ctx->getELFSection(".debug_str_offsets.dwo", ELF::SHT_PROGBITS, 0,
SectionKind::getMetadata());
DwarfAddrSection =
Ctx->getELFSection(".debug_addr", ELF::SHT_PROGBITS, 0,
SectionKind::getMetadata());
}

View File

@ -26,14 +26,52 @@
; CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x00000000)
; CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000006] = "/usr/local/google/home/echristo/tmp")
; Check that we're using the right forms.
; CHECK: .debug_abbrev.dwo contents:
; CHECK: Abbrev table for offset: 0x00000000
; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_yes
; CHECK: DW_AT_producer DW_FORM_GNU_str_index
; CHECK: DW_AT_language DW_FORM_data2
; CHECK: DW_AT_name DW_FORM_GNU_str_index
; CHECK: DW_AT_low_pc DW_FORM_GNU_addr_index
; CHECK: DW_AT_stmt_list DW_FORM_data4
; CHECK: DW_AT_comp_dir DW_FORM_GNU_str_index
; CHECK: [2] DW_TAG_base_type DW_CHILDREN_no
; CHECK: DW_AT_name DW_FORM_GNU_str_index
; CHECK: DW_AT_encoding DW_FORM_data1
; CHECK: DW_AT_byte_size DW_FORM_data1
; CHECK: [3] DW_TAG_variable DW_CHILDREN_no
; CHECK: DW_AT_name DW_FORM_GNU_str_index
; CHECK: DW_AT_type DW_FORM_ref4
; CHECK: DW_AT_external DW_FORM_flag_present
; CHECK: DW_AT_decl_file DW_FORM_data1
; CHECK: DW_AT_decl_line DW_FORM_data1
; CHECK: DW_AT_location DW_FORM_block1
; Check that the rest of the compile units have information.
; FIXME: Strings will ultimately be a different form.
; CHECK: .debug_info.dwo contents:
; CHECK: DW_TAG_compile_unit
; CHECK: DW_AT_producer [DW_FORM_GNU_str_index] ( indexed (00000000) string = "clang version 3.3 (trunk 169021) (llvm/trunk 169020)")
; CHECK: DW_AT_language [DW_FORM_data2] (0x000c)
; CHECK: DW_AT_name [DW_FORM_GNU_str_index] ( indexed (00000001) string = "baz.c")
; CHECK: DW_AT_low_pc [DW_FORM_GNU_addr_index] ( indexed (00000000) address = 0x0000000000000000)
; CHECK: DW_TAG_base_type
; CHECK: DW_AT_name [DW_FORM_GNU_str_index] ( indexed (00000004) string = "int")
; CHECK: DW_TAG_variable
; CHECK: DW_AT_name [DW_FORM_GNU_str_index] ( indexed (00000003) string = "a")
; CHECK: .debug_str.dwo contents:
; CHECK: 0x00000000: "clang version 3.3 (trunk 169021) (llvm/trunk 169020)"
; CHECK: 0x00000035: "baz.c"
; CHECK: 0x0000003b: "/usr/local/google/home/echristo/tmp"
; CHECK: 0x0000005f: "a"
; CHECK: 0x00000061: "int"
; CHECK: .debug_str_offsets.dwo contents:
; CHECK: 0x00000000: 00000000
; CHECK: 0x00000004: 00000035
; CHECK: 0x00000008: 0000003b
; CHECK: 0x0000000c: 0000005f
; CHECK: 0x00000010: 00000061