1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

[CodeView] Implement .cv_inline_linetable

This support is _very_ rudimentary, just enough to get some basic data
into the CodeView debug section.

Left to do is:
- Use the combined opcodes to save space.
- Do something about code offsets.

llvm-svn: 259230
This commit is contained in:
David Majnemer 2016-01-29 19:24:12 +00:00
parent 81271b4305
commit e3c89c41f3
9 changed files with 317 additions and 12 deletions

View File

@ -116,12 +116,24 @@ public:
/// \brief Add a line entry.
void addLineEntry(const MCCVLineEntry &LineEntry) {
MCCVLines[LineEntry.getFunctionId()].push_back(LineEntry);
size_t Offset = MCCVLines.size();
auto I =
MCCVLineStartStop.insert({LineEntry.getFunctionId(), {Offset, Offset}});
if (!I.second)
I.first->second.second = Offset;
MCCVLines.push_back(LineEntry);
}
ArrayRef<MCCVLineEntry> getFunctionLineEntries(unsigned FuncId) {
assert(MCCVLines.find(FuncId) != MCCVLines.end());
return MCCVLines.find(FuncId)->second;
std::vector<MCCVLineEntry> getFunctionLineEntries(unsigned FuncId) {
auto I = MCCVLineStartStop.find(FuncId);
assert(I != MCCVLineStartStop.end());
std::vector<MCCVLineEntry> FilteredLines;
for (size_t Idx = I->second.first, End = I->second.second + 1; Idx != End;
++Idx)
if (MCCVLines[Idx].getFunctionId() == FuncId)
FilteredLines.push_back(MCCVLines[Idx]);
return FilteredLines;
}
/// Emits a line table substream.
@ -129,6 +141,12 @@ public:
const MCSymbol *FuncBegin,
const MCSymbol *FuncEnd);
void emitInlineLineTableForFunction(MCObjectStreamer &OS,
unsigned PrimaryFunctionId,
unsigned SourceFileId,
unsigned SourceLineNum,
ArrayRef<unsigned> SecondaryFunctionIds);
/// Emits the string table substream.
void emitStringTable(MCObjectStreamer &OS);
@ -154,8 +172,12 @@ private:
/// An array of absolute paths. Eventually this may include the file checksum.
SmallVector<StringRef, 4> Filenames;
/// A collection of MCDwarfLineEntry for each section.
std::map<int, std::vector<MCCVLineEntry>> MCCVLines;
/// The offset of the first and last .cv_loc directive for a given function
/// id.
std::map<int, std::pair<size_t, size_t>> MCCVLineStartStop;
/// A collection of MCCVLineEntry for each section.
std::vector<MCCVLineEntry> MCCVLines;
};
} // end namespace llvm

View File

@ -127,6 +127,9 @@ public:
StringRef FileName) override;
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin,
const MCSymbol *End) override;
void EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
ArrayRef<unsigned> SecondaryFunctionIds) override;
void EmitCVStringTableDirective() override;
void EmitCVFileChecksumsDirective() override;
void EmitGPRel32Value(const MCExpr *Value) override;

View File

@ -655,6 +655,13 @@ public:
const MCSymbol *FnStart,
const MCSymbol *FnEnd);
/// \brief This implements the CodeView '.cv_inline_linetable' assembler
/// directive.
virtual void
EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
unsigned SourceFileId, unsigned SourceLineNum,
ArrayRef<unsigned> SecondaryFunctionIds);
/// \brief This implements the CodeView '.cv_stringtable' assembler directive.
virtual void EmitCVStringTableDirective() {}

View File

@ -205,6 +205,9 @@ public:
StringRef FileName) override;
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
const MCSymbol *FnEnd) override;
void EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
ArrayRef<unsigned> SecondaryFunctionIds) override;
void EmitCVStringTableDirective() override;
void EmitCVFileChecksumsDirective() override;
@ -1016,6 +1019,21 @@ void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd);
}
void MCAsmStreamer::EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
ArrayRef<unsigned> SecondaryFunctionIds) {
OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
<< ' ' << SourceLineNum;
if (!SecondaryFunctionIds.empty()) {
OS << " contains";
for (unsigned SecondaryFunctionId : SecondaryFunctionIds)
OS << ' ' << SecondaryFunctionId;
}
EmitEOL();
this->MCStreamer::EmitCVInlineLinetableDirective(
PrimaryFunctionId, SourceFileId, SourceLineNum, SecondaryFunctionIds);
}
void MCAsmStreamer::EmitCVStringTableDirective() {
OS << "\t.cv_stringtable";
EmitEOL();

View File

@ -15,6 +15,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/Support/COFF.h"
@ -151,11 +152,11 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
OS.EmitCOFFSectionIndex(FuncBegin);
// Actual line info.
ArrayRef<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId);
std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId);
bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) {
return LineEntry.getColumn() != 0;
});
OS.EmitIntValue(HaveColumns ? int(codeview::LineFlags::HaveColumns) : 0, 2);
OS.EmitIntValue(HaveColumns ? int(LineFlags::HaveColumns) : 0, 2);
OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
@ -180,7 +181,7 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
unsigned LineData = J->getLine();
if (J->isStmt())
LineData |= codeview::LineInfo::StatementFlag;
LineData |= LineInfo::StatementFlag;
OS.EmitIntValue(LineData, 4);
}
if (HaveColumns) {
@ -194,6 +195,73 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
OS.EmitLabel(LineEnd);
}
static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) {
if (isUInt<7>(Data)) {
Buffer.push_back(Data);
return true;
}
if (isUInt<14>(Data)) {
Buffer.push_back((Data >> 8) | 0x80);
Buffer.push_back(Data & 0xff);
return true;
}
if (isUInt<29>(Data)) {
Buffer.push_back((Data >> 24) | 0xC0);
Buffer.push_back((Data >> 16) & 0xff);
Buffer.push_back((Data >> 8) & 0xff);
Buffer.push_back(Data & 0xff);
return true;
}
return false;
}
static uint32_t encodeSignedNumber(uint32_t Data) {
if (Data >> 31)
return ((-Data) << 1) | 1;
return Data << 1;
}
void CodeViewContext::emitInlineLineTableForFunction(
MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId,
unsigned SourceLineNum, ArrayRef<unsigned> SecondaryFunctionIds) {
std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(PrimaryFunctionId);
std::vector<std::pair<BinaryAnnotationsOpCode, uint32_t>> Annotations;
const MCCVLineEntry *LastLoc = nullptr;
unsigned LastFileId = SourceFileId;
unsigned LastLineNum = SourceLineNum;
for (const MCCVLineEntry &Loc : Locs) {
if (!LastLoc) {
// TODO ChangeCodeOffset
// TODO ChangeCodeLength
}
if (Loc.getFileNum() != LastFileId)
Annotations.push_back({ChangeFile, Loc.getFileNum()});
if (Loc.getLine() != LastLineNum)
Annotations.push_back(
{ChangeLineOffset, encodeSignedNumber(Loc.getLine() - LastLineNum)});
LastLoc = &Loc;
LastFileId = Loc.getFileNum();
LastLineNum = Loc.getLine();
}
SmallString<32> Buffer;
for (auto Annotation : Annotations) {
BinaryAnnotationsOpCode Opcode = Annotation.first;
uint32_t Operand = Annotation.second;
compressAnnotation(Opcode, Buffer);
compressAnnotation(Operand, Buffer);
}
OS.EmitBytes(Buffer);
}
//
// This is called when an instruction is assembled into the specified section
// and if there is information from the last .cv_loc directive that has yet to have

View File

@ -384,6 +384,16 @@ void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
this->MCStreamer::EmitCVLinetableDirective(FunctionId, Begin, End);
}
void MCObjectStreamer::EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
ArrayRef<unsigned> SecondaryFunctionIds) {
getContext().getCVContext().emitInlineLineTableForFunction(
*this, PrimaryFunctionId, SourceFileId, SourceLineNum,
SecondaryFunctionIds);
this->MCStreamer::EmitCVInlineLinetableDirective(
PrimaryFunctionId, SourceFileId, SourceLineNum, SecondaryFunctionIds);
}
void MCObjectStreamer::EmitCVStringTableDirective() {
getContext().getCVContext().emitStringTable(*this);
}

View File

@ -357,8 +357,8 @@ private:
DK_IFNB, DK_IFC, DK_IFEQS, DK_IFNC, DK_IFNES, DK_IFDEF, DK_IFNDEF,
DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF,
DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS,
DK_CV_FILE, DK_CV_LOC, DK_CV_LINETABLE, DK_CV_STRINGTABLE,
DK_CV_FILECHECKSUMS,
DK_CV_FILE, DK_CV_LOC, DK_CV_LINETABLE, DK_CV_INLINE_LINETABLE,
DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS,
DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA,
DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER,
DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA,
@ -396,10 +396,11 @@ private:
bool parseDirectiveLoc();
bool parseDirectiveStabs();
// ".cv_file", ".cv_loc", ".cv_linetable"
// ".cv_file", ".cv_loc", ".cv_linetable", "cv_inline_linetable"
bool parseDirectiveCVFile();
bool parseDirectiveCVLoc();
bool parseDirectiveCVLinetable();
bool parseDirectiveCVInlineLinetable();
bool parseDirectiveCVStringTable();
bool parseDirectiveCVFileChecksums();
@ -1653,6 +1654,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveCVLoc();
case DK_CV_LINETABLE:
return parseDirectiveCVLinetable();
case DK_CV_INLINE_LINETABLE:
return parseDirectiveCVInlineLinetable();
case DK_CV_STRINGTABLE:
return parseDirectiveCVStringTable();
case DK_CV_FILECHECKSUMS:
@ -3225,6 +3228,51 @@ bool AsmParser::parseDirectiveCVLinetable() {
return false;
}
/// parseDirectiveCVInlineLinetable
/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum
/// ("contains" SecondaryFunctionId+)?
bool AsmParser::parseDirectiveCVInlineLinetable() {
int64_t PrimaryFunctionId = getTok().getIntVal();
if (PrimaryFunctionId < 0)
return TokError(
"function id less than zero in '.cv_inline_linetable' directive");
Lex();
int64_t SourceFileId = getTok().getIntVal();
if (SourceFileId <= 0)
return TokError(
"File id less than zero in '.cv_inline_linetable' directive");
Lex();
int64_t SourceLineNum = getTok().getIntVal();
if (SourceLineNum < 0)
return TokError(
"Line number less than zero in '.cv_inline_linetable' directive");
Lex();
SmallVector<unsigned, 8> SecondaryFunctionIds;
if (getLexer().is(AsmToken::Identifier)) {
if (getTok().getIdentifier() != "contains")
return TokError(
"unexpected identifier in '.cv_inline_linetable' directive");
Lex();
while (getLexer().isNot(AsmToken::EndOfStatement)) {
int64_t SecondaryFunctionId = getTok().getIntVal();
if (SecondaryFunctionId < 0)
return TokError(
"function id less than zero in '.cv_inline_linetable' directive");
Lex();
SecondaryFunctionIds.push_back(SecondaryFunctionId);
}
}
getStreamer().EmitCVInlineLinetableDirective(
PrimaryFunctionId, SourceFileId, SourceLineNum, SecondaryFunctionIds);
return false;
}
/// parseDirectiveCVStringTable
/// ::= .cv_stringtable
bool AsmParser::parseDirectiveCVStringTable() {
@ -4553,6 +4601,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".cv_file"] = DK_CV_FILE;
DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;
DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
DirectiveKindMap[".sleb128"] = DK_SLEB128;

View File

@ -196,6 +196,10 @@ void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId,
const MCSymbol *Begin,
const MCSymbol *End) {}
void MCStreamer::EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
ArrayRef<unsigned> SecondaryFunctionIds) {}
void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol) {
}

View File

@ -0,0 +1,124 @@
# RUN: llvm-mc -triple=i686-pc-win32 -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s
.text
.def @feat.00;
.scl 3;
.type 0;
.endef
.globl @feat.00
@feat.00 = 1
.def "?baz@@YAXXZ";
.scl 2;
.type 32;
.endef
.globl "?baz@@YAXXZ"
.p2align 4, 0x90
"?baz@@YAXXZ": # @"\01?baz@@YAXXZ"
Lfunc_begin0:
.cv_file 1 "D:\\src\\llvm\\build\\t.cpp"
.cv_loc 0 1 13 0 is_stmt 0 # t.cpp:13:0
# BB#0: # %entry
pushl %eax
.cv_loc 0 1 14 5 # t.cpp:14:5
addl $6, "?x@@3HC"
.cv_loc 1 1 9 5 # t.cpp:9:5
addl $4, "?x@@3HC"
.cv_loc 2 1 3 7 # t.cpp:3:7
movl $1, (%esp)
leal (%esp), %eax
.cv_loc 2 1 4 5 # t.cpp:4:5
addl %eax, "?x@@3HC"
.cv_loc 2 1 5 5 # t.cpp:5:5
addl $2, "?x@@3HC"
.cv_loc 2 1 6 5 # t.cpp:6:5
addl $3, "?x@@3HC"
.cv_loc 1 1 11 5 # t.cpp:11:5
addl $5, "?x@@3HC"
.cv_loc 0 1 16 5 # t.cpp:16:5
addl $7, "?x@@3HC"
.cv_loc 0 1 17 1 # t.cpp:17:1
popl %eax
retl
Lfunc_end0:
.section .debug$T,"dr"
.long 4
.short 6
.short 4609
.long 0
.short 14
.short 4104
.asciz "\003\000\000\000\000\000\000\000\000\020\000"
.short 14
.short 5633
.asciz "\000\000\000\000\001\020\000"
.ascii "baz"
.byte 0
.short 14
.short 5633
.asciz "\000\000\000\000\001\020\000"
.ascii "bar"
.byte 0
.short 14
.short 5633
.asciz "\000\000\000\000\001\020\000"
.ascii "foo"
.byte 0
.section .debug$S,"dr"
.long 4
.long 241 # Symbol subsection for baz
.long Ltmp1-Ltmp0
Ltmp0:
.short Ltmp3-Ltmp2
Ltmp2:
.short 4423
.zero 12
.long Lfunc_end0-"?baz@@YAXXZ"
.zero 12
.secrel32 "?baz@@YAXXZ"
.secidx "?baz@@YAXXZ"
.byte 0
.ascii "baz"
.byte 0
Ltmp3:
.short Ltmp5-Ltmp4
Ltmp4:
.short 4429
.asciz "\000\000\000\000\000\000\000\000\003\020\000"
.cv_inline_linetable 1 1 9 contains 2
# CHECK: InlineSite {
# CHECK: PtrParent: 0x0
# CHECK: PtrEnd: 0x0
# CHECK: Inlinee: bar (0x1003)
# CHECK: BinaryAnnotations [
# CHECK: ChangeLineOffset: 2
# CHECK: ]
# CHECK: }
Ltmp5:
.short Ltmp7-Ltmp6
Ltmp6:
.short 4429
.asciz "\000\000\000\000\000\000\000\000\004\020\000"
.cv_inline_linetable 2 1 3
# CHECK: InlineSite {
# CHECK: PtrParent: 0x0
# CHECK: PtrEnd: 0x0
# CHECK: Inlinee: foo (0x1004)
# CHECK: BinaryAnnotations [
# CHECK: ChangeLineOffset: 1
# CHECK: ChangeLineOffset: 1
# CHECK: ChangeLineOffset: 1
# CHECK: ]
# CHECK: }
Ltmp7:
.short 2
.short 4430
.short 2
.short 4430
.short 2
.short 4431
Ltmp1:
.zero 1
.cv_linetable 0, "?baz@@YAXXZ", Lfunc_end0
.cv_filechecksums # File index to string table offset subsection
.cv_stringtable # String table