2017-08-17 23:26:39 +02:00
|
|
|
//===- llvm/CodeGen/DwarfFile.cpp - Dwarf Debug Framework -----------------===//
|
2014-04-23 20:54:00 +02:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2014-04-23 20:54:00 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "DwarfFile.h"
|
2016-02-11 20:57:46 +01:00
|
|
|
#include "DwarfCompileUnit.h"
|
2014-04-23 20:54:00 +02:00
|
|
|
#include "DwarfDebug.h"
|
|
|
|
#include "DwarfUnit.h"
|
2017-08-17 23:26:39 +02:00
|
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
|
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
2020-09-17 13:12:00 +02:00
|
|
|
#include "llvm/IR/Metadata.h"
|
2014-04-23 20:54:00 +02:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2017-08-17 23:26:39 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
using namespace llvm;
|
2014-04-23 20:54:00 +02:00
|
|
|
|
2015-03-04 03:30:17 +01:00
|
|
|
DwarfFile::DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA)
|
Make a DWARF generator so we can unit test DWARF APIs with gtest.
The only tests we have for the DWARF parser are the tests that use llvm-dwarfdump and expect output from textual dumps.
More DWARF parser modification are coming in the next few weeks and I wanted to add tests that can verify that we can encode and decode all form types, as well as test some other basic DWARF APIs where we ask DIE objects for their children and siblings.
DwarfGenerator.cpp was added in the lib/CodeGen directory. This file contains the code necessary to easily create DWARF for tests:
dwarfgen::Generator DG;
Triple Triple("x86_64--");
bool success = DG.init(Triple, Version);
if (!success)
return;
dwarfgen::CompileUnit &CU = DG.addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
dwarfgen::DIE SubprogramDie = CUDie.addChild(DW_TAG_subprogram);
SubprogramDie.addAttribute(DW_AT_name, DW_FORM_strp, "main");
SubprogramDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U);
SubprogramDie.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x2000U);
dwarfgen::DIE IntDie = CUDie.addChild(DW_TAG_base_type);
IntDie.addAttribute(DW_AT_name, DW_FORM_strp, "int");
IntDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_signed);
IntDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
dwarfgen::DIE ArgcDie = SubprogramDie.addChild(DW_TAG_formal_parameter);
ArgcDie.addAttribute(DW_AT_name, DW_FORM_strp, "argc");
// ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref4, IntDie);
ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, IntDie);
StringRef FileBytes = DG.generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
DWARFContextInMemory DwarfContext(*Obj.get());
This code is backed by the AsmPrinter code that emits DWARF for the actual compiler.
While adding unit tests it was discovered that DIEValue that used DIEEntry as their values had bugs where DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref8, and DW_FORM_ref_udata forms were not supported. These are all now supported. Added support for DW_FORM_string so we can emit inlined C strings.
Centralized the code to unique abbreviations into a new DIEAbbrevSet class and made both the dwarfgen::Generator and the llvm::DwarfFile classes use the new class.
Fixed comments in the llvm::DIE class so that the Offset is known to be the compile/type unit offset.
DIEInteger now supports more DW_FORM values.
There are also unit tests that cover:
Encoding and decoding all form types and values
Encoding and decoding all reference types (DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8, DW_FORM_ref_udata, DW_FORM_ref_addr) including cross compile unit references with that go forward one compile unit and backward on compile unit.
Differential Revision: https://reviews.llvm.org/D27326
llvm-svn: 289010
2016-12-08 02:03:48 +01:00
|
|
|
: Asm(AP), Abbrevs(AbbrevAllocator), StrPool(DA, *Asm, Pref) {}
|
2014-04-23 20:54:00 +02:00
|
|
|
|
2016-02-11 20:57:46 +01:00
|
|
|
void DwarfFile::addUnit(std::unique_ptr<DwarfCompileUnit> U) {
|
2014-04-23 20:54:00 +02:00
|
|
|
CUs.push_back(std::move(U));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the various dwarf units to the unit section USection with
|
|
|
|
// the abbreviations going into ASection.
|
2015-03-10 17:58:10 +01:00
|
|
|
void DwarfFile::emitUnits(bool UseOffsets) {
|
2016-02-11 20:57:46 +01:00
|
|
|
for (const auto &TheU : CUs)
|
|
|
|
emitUnit(TheU.get(), UseOffsets);
|
|
|
|
}
|
2014-04-23 20:54:00 +02:00
|
|
|
|
2016-02-11 20:57:46 +01:00
|
|
|
void DwarfFile::emitUnit(DwarfUnit *TheU, bool UseOffsets) {
|
2018-08-01 21:38:20 +02:00
|
|
|
if (TheU->getCUNode()->isDebugDirectivesOnly())
|
|
|
|
return;
|
|
|
|
|
2018-12-14 23:44:46 +01:00
|
|
|
MCSection *S = TheU->getSection();
|
2014-04-23 20:54:00 +02:00
|
|
|
|
2018-12-14 23:44:46 +01:00
|
|
|
if (!S)
|
|
|
|
return;
|
2016-02-11 20:57:46 +01:00
|
|
|
|
2019-02-12 01:00:38 +01:00
|
|
|
// Skip CUs that ended up not being needed (split CUs that were abandoned
|
|
|
|
// because they added no information beyond the non-split CU)
|
|
|
|
if (llvm::empty(TheU->getUnitDie().values()))
|
|
|
|
return;
|
|
|
|
|
2018-12-14 23:44:46 +01:00
|
|
|
Asm->OutStreamer->SwitchSection(S);
|
|
|
|
TheU->emitHeader(UseOffsets);
|
|
|
|
Asm->emitDwarfDIE(TheU->getUnitDie());
|
2018-12-18 02:06:09 +01:00
|
|
|
|
|
|
|
if (MCSymbol *EndLabel = TheU->getEndLabel())
|
2020-02-15 04:21:58 +01:00
|
|
|
Asm->OutStreamer->emitLabel(EndLabel);
|
2014-04-23 20:54:00 +02:00
|
|
|
}
|
2014-10-23 02:16:05 +02:00
|
|
|
|
2014-04-23 20:54:00 +02:00
|
|
|
// Compute the size and offset for each DIE.
|
|
|
|
void DwarfFile::computeSizeAndOffsets() {
|
|
|
|
// Offset from the first CU in the debug info section is 0 initially.
|
2020-09-15 06:32:08 +02:00
|
|
|
uint64_t SecOffset = 0;
|
2014-04-23 20:54:00 +02:00
|
|
|
|
|
|
|
// Iterate over each compile unit and set the size and offsets for each
|
|
|
|
// DIE within each compile unit. All offsets are CU relative.
|
|
|
|
for (const auto &TheU : CUs) {
|
2018-08-01 21:38:20 +02:00
|
|
|
if (TheU->getCUNode()->isDebugDirectivesOnly())
|
|
|
|
continue;
|
|
|
|
|
2019-02-12 01:00:38 +01:00
|
|
|
// Skip CUs that ended up not being needed (split CUs that were abandoned
|
|
|
|
// because they added no information beyond the non-split CU)
|
|
|
|
if (llvm::empty(TheU->getUnitDie().values()))
|
|
|
|
return;
|
|
|
|
|
2016-12-01 19:56:29 +01:00
|
|
|
TheU->setDebugSectionOffset(SecOffset);
|
2016-02-11 20:57:46 +01:00
|
|
|
SecOffset += computeSizeAndOffsetsForUnit(TheU.get());
|
|
|
|
}
|
2020-09-15 06:32:08 +02:00
|
|
|
if (SecOffset > UINT32_MAX && !Asm->isDwarf64())
|
|
|
|
report_fatal_error("The generated debug information is too large "
|
|
|
|
"for the 32-bit DWARF format.");
|
2016-02-11 20:57:46 +01:00
|
|
|
}
|
2014-04-23 20:54:00 +02:00
|
|
|
|
2016-02-11 20:57:46 +01:00
|
|
|
unsigned DwarfFile::computeSizeAndOffsetsForUnit(DwarfUnit *TheU) {
|
|
|
|
// CU-relative offset is reset to 0 here.
|
2020-09-15 06:30:30 +02:00
|
|
|
unsigned Offset = Asm->getUnitLengthFieldByteSize() + // Length of Unit Info
|
|
|
|
TheU->getHeaderSize(); // Unit-specific headers
|
2014-04-23 20:54:00 +02:00
|
|
|
|
2016-02-11 20:57:46 +01:00
|
|
|
// The return value here is CU-relative, after laying out
|
|
|
|
// all of the CU DIE.
|
|
|
|
return computeSizeAndOffset(TheU->getUnitDie(), Offset);
|
2014-04-23 20:54:00 +02:00
|
|
|
}
|
2016-02-11 20:57:46 +01:00
|
|
|
|
2014-04-23 20:54:00 +02:00
|
|
|
// Compute the size and offset of a DIE. The offset is relative to start of the
|
|
|
|
// CU. It returns the offset after laying out the DIE.
|
|
|
|
unsigned DwarfFile::computeSizeAndOffset(DIE &Die, unsigned Offset) {
|
Make a DWARF generator so we can unit test DWARF APIs with gtest.
The only tests we have for the DWARF parser are the tests that use llvm-dwarfdump and expect output from textual dumps.
More DWARF parser modification are coming in the next few weeks and I wanted to add tests that can verify that we can encode and decode all form types, as well as test some other basic DWARF APIs where we ask DIE objects for their children and siblings.
DwarfGenerator.cpp was added in the lib/CodeGen directory. This file contains the code necessary to easily create DWARF for tests:
dwarfgen::Generator DG;
Triple Triple("x86_64--");
bool success = DG.init(Triple, Version);
if (!success)
return;
dwarfgen::CompileUnit &CU = DG.addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
dwarfgen::DIE SubprogramDie = CUDie.addChild(DW_TAG_subprogram);
SubprogramDie.addAttribute(DW_AT_name, DW_FORM_strp, "main");
SubprogramDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U);
SubprogramDie.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x2000U);
dwarfgen::DIE IntDie = CUDie.addChild(DW_TAG_base_type);
IntDie.addAttribute(DW_AT_name, DW_FORM_strp, "int");
IntDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_signed);
IntDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
dwarfgen::DIE ArgcDie = SubprogramDie.addChild(DW_TAG_formal_parameter);
ArgcDie.addAttribute(DW_AT_name, DW_FORM_strp, "argc");
// ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref4, IntDie);
ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, IntDie);
StringRef FileBytes = DG.generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
DWARFContextInMemory DwarfContext(*Obj.get());
This code is backed by the AsmPrinter code that emits DWARF for the actual compiler.
While adding unit tests it was discovered that DIEValue that used DIEEntry as their values had bugs where DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref8, and DW_FORM_ref_udata forms were not supported. These are all now supported. Added support for DW_FORM_string so we can emit inlined C strings.
Centralized the code to unique abbreviations into a new DIEAbbrevSet class and made both the dwarfgen::Generator and the llvm::DwarfFile classes use the new class.
Fixed comments in the llvm::DIE class so that the Offset is known to be the compile/type unit offset.
DIEInteger now supports more DW_FORM values.
There are also unit tests that cover:
Encoding and decoding all form types and values
Encoding and decoding all reference types (DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8, DW_FORM_ref_udata, DW_FORM_ref_addr) including cross compile unit references with that go forward one compile unit and backward on compile unit.
Differential Revision: https://reviews.llvm.org/D27326
llvm-svn: 289010
2016-12-08 02:03:48 +01:00
|
|
|
return Die.computeOffsetsAndAbbrevs(Asm, Abbrevs, Offset);
|
2014-04-23 20:54:00 +02:00
|
|
|
}
|
2015-03-04 03:30:17 +01:00
|
|
|
|
Make a DWARF generator so we can unit test DWARF APIs with gtest.
The only tests we have for the DWARF parser are the tests that use llvm-dwarfdump and expect output from textual dumps.
More DWARF parser modification are coming in the next few weeks and I wanted to add tests that can verify that we can encode and decode all form types, as well as test some other basic DWARF APIs where we ask DIE objects for their children and siblings.
DwarfGenerator.cpp was added in the lib/CodeGen directory. This file contains the code necessary to easily create DWARF for tests:
dwarfgen::Generator DG;
Triple Triple("x86_64--");
bool success = DG.init(Triple, Version);
if (!success)
return;
dwarfgen::CompileUnit &CU = DG.addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
dwarfgen::DIE SubprogramDie = CUDie.addChild(DW_TAG_subprogram);
SubprogramDie.addAttribute(DW_AT_name, DW_FORM_strp, "main");
SubprogramDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U);
SubprogramDie.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x2000U);
dwarfgen::DIE IntDie = CUDie.addChild(DW_TAG_base_type);
IntDie.addAttribute(DW_AT_name, DW_FORM_strp, "int");
IntDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_signed);
IntDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
dwarfgen::DIE ArgcDie = SubprogramDie.addChild(DW_TAG_formal_parameter);
ArgcDie.addAttribute(DW_AT_name, DW_FORM_strp, "argc");
// ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref4, IntDie);
ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, IntDie);
StringRef FileBytes = DG.generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
DWARFContextInMemory DwarfContext(*Obj.get());
This code is backed by the AsmPrinter code that emits DWARF for the actual compiler.
While adding unit tests it was discovered that DIEValue that used DIEEntry as their values had bugs where DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref8, and DW_FORM_ref_udata forms were not supported. These are all now supported. Added support for DW_FORM_string so we can emit inlined C strings.
Centralized the code to unique abbreviations into a new DIEAbbrevSet class and made both the dwarfgen::Generator and the llvm::DwarfFile classes use the new class.
Fixed comments in the llvm::DIE class so that the Offset is known to be the compile/type unit offset.
DIEInteger now supports more DW_FORM values.
There are also unit tests that cover:
Encoding and decoding all form types and values
Encoding and decoding all reference types (DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8, DW_FORM_ref_udata, DW_FORM_ref_addr) including cross compile unit references with that go forward one compile unit and backward on compile unit.
Differential Revision: https://reviews.llvm.org/D27326
llvm-svn: 289010
2016-12-08 02:03:48 +01:00
|
|
|
void DwarfFile::emitAbbrevs(MCSection *Section) { Abbrevs.Emit(Asm, Section); }
|
2014-04-23 20:54:00 +02:00
|
|
|
|
|
|
|
// Emit strings into a string section.
|
2018-01-26 19:52:58 +01:00
|
|
|
void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection,
|
|
|
|
bool UseRelativeOffsets) {
|
|
|
|
StrPool.emit(*Asm, StrSection, OffsetSection, UseRelativeOffsets);
|
2014-04-23 20:54:00 +02:00
|
|
|
}
|
2014-10-23 02:16:05 +02:00
|
|
|
|
2015-02-11 00:18:28 +01:00
|
|
|
bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) {
|
2018-02-06 23:17:45 +01:00
|
|
|
auto &ScopeVars = ScopeVariables[LS];
|
2015-04-29 18:38:44 +02:00
|
|
|
const DILocalVariable *DV = Var->getVariable();
|
2015-04-14 04:22:36 +02:00
|
|
|
if (unsigned ArgNum = DV->getArg()) {
|
2018-02-06 23:17:45 +01:00
|
|
|
auto Cached = ScopeVars.Args.find(ArgNum);
|
|
|
|
if (Cached == ScopeVars.Args.end())
|
|
|
|
ScopeVars.Args[ArgNum] = Var;
|
|
|
|
else {
|
|
|
|
Cached->second->addMMIEntry(*Var);
|
|
|
|
return false;
|
2014-10-24 00:04:30 +02:00
|
|
|
}
|
2018-02-06 23:17:45 +01:00
|
|
|
} else {
|
|
|
|
ScopeVars.Locals.push_back(Var);
|
2018-07-30 21:41:25 +02:00
|
|
|
}
|
2015-02-11 00:18:28 +01:00
|
|
|
return true;
|
2014-10-24 00:04:30 +02:00
|
|
|
}
|
2018-08-17 17:22:04 +02:00
|
|
|
|
|
|
|
void DwarfFile::addScopeLabel(LexicalScope *LS, DbgLabel *Label) {
|
|
|
|
SmallVectorImpl<DbgLabel *> &Labels = ScopeLabels[LS];
|
|
|
|
Labels.push_back(Label);
|
|
|
|
}
|
2018-10-20 09:36:39 +02:00
|
|
|
|
|
|
|
std::pair<uint32_t, RangeSpanList *>
|
2018-11-08 01:35:54 +01:00
|
|
|
DwarfFile::addRange(const DwarfCompileUnit &CU, SmallVector<RangeSpan, 2> R) {
|
|
|
|
CURangeLists.push_back(
|
2019-12-17 00:19:25 +01:00
|
|
|
RangeSpanList{Asm->createTempSymbol("debug_ranges"), &CU, std::move(R)});
|
2018-10-20 09:36:39 +02:00
|
|
|
return std::make_pair(CURangeLists.size() - 1, &CURangeLists.back());
|
|
|
|
}
|