mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-13 14:47:00 +00:00
[CodeView] Use assembler directives for line tables
Adds a new family of .cv_* directives to LLVM's variant of GAS syntax: - .cv_file: Similar to DWARF .file directives - .cv_loc: Similar to the DWARF .loc directive, but starts with a function id. CodeView line tables are emitted by function instead of by compilation unit, so we needed an extra field to communicate this. Rather than overloading the .loc direction further, we decided it was better to have our own directive. - .cv_stringtable: Emits the codeview string table at the current position. Currently this just contains the filenames as null-terminated strings. - .cv_filechecksums: Emits the file checksum table for all files used with .cv_file so far. There is currently no support for emitting actual checksums, just filenames. This moves the line table emission code down into the assembler. This is in preparation for implementing the inlined call site line table format. The inline line table format encoding algorithm requires knowing the absolute code offsets, so it must run after the assembler has laid out the code. David Majnemer collaborated on this patch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@259117 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
eac4c34846
commit
200dc330a0
@ -21,17 +21,26 @@ using llvm::support::ulittle32_t;
|
||||
|
||||
class LineInfo {
|
||||
public:
|
||||
static const uint32_t AlwaysStepIntoLineNumber = 0xfeefee;
|
||||
static const uint32_t NeverStepIntoLineNumber = 0xf00f00;
|
||||
enum : uint32_t {
|
||||
AlwaysStepIntoLineNumber = 0xfeefee,
|
||||
NeverStepIntoLineNumber = 0xf00f00
|
||||
};
|
||||
|
||||
private:
|
||||
static const uint32_t StartLineMask = 0x00ffffff;
|
||||
static const uint32_t EndLineDeltaMask = 0x7f000000;
|
||||
static const int EndLineDeltaShift = 24;
|
||||
static const uint32_t StatementFlag = 0x80000000u;
|
||||
enum : int { EndLineDeltaShift = 24 };
|
||||
|
||||
public:
|
||||
LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement);
|
||||
enum : uint32_t {
|
||||
StartLineMask = 0x00ffffff,
|
||||
EndLineDeltaMask = 0x7f000000,
|
||||
StatementFlag = 0x80000000u
|
||||
};
|
||||
|
||||
LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) {
|
||||
LineData = StartLine & StartLineMask;
|
||||
uint32_t Delta = EndLine - StartLine;
|
||||
LineData |= (Delta << EndLineDeltaShift) & EndLineDeltaShift;
|
||||
if (IsStatement)
|
||||
LineData |= StatementFlag;
|
||||
}
|
||||
|
||||
uint32_t getStartLine() const { return LineData & StartLineMask; }
|
||||
|
||||
@ -151,6 +160,10 @@ struct FileChecksum {
|
||||
// Checksum bytes follow.
|
||||
};
|
||||
|
||||
enum LineFlags : uint32_t {
|
||||
HaveColumns = 1, // CV_LINES_HAVE_COLUMNS
|
||||
};
|
||||
|
||||
} // namespace codeview
|
||||
} // namespace llvm
|
||||
|
||||
|
162
include/llvm/MC/MCCodeView.h
Normal file
162
include/llvm/MC/MCCodeView.h
Normal file
@ -0,0 +1,162 @@
|
||||
//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Holds state from .cv_file and .cv_loc directives for later emission.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_MC_MCCODEVIEW_H
|
||||
#define LLVM_MC_MCCODEVIEW_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/MC/MCObjectStreamer.h"
|
||||
#include "llvm/MC/MCFragment.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class MCContext;
|
||||
class MCObjectStreamer;
|
||||
class MCStreamer;
|
||||
|
||||
/// \brief Instances of this class represent the information from a
|
||||
/// .cv_loc directive.
|
||||
class MCCVLoc {
|
||||
uint32_t FunctionId;
|
||||
uint32_t FileNum;
|
||||
uint32_t Line;
|
||||
uint16_t Column;
|
||||
uint16_t PrologueEnd : 1;
|
||||
uint16_t IsStmt : 1;
|
||||
|
||||
private: // MCContext manages these
|
||||
friend class MCContext;
|
||||
MCCVLoc(unsigned functionid, unsigned fileNum, unsigned line, unsigned column,
|
||||
bool prologueend, bool isstmt)
|
||||
: FunctionId(functionid), FileNum(fileNum), Line(line), Column(column),
|
||||
PrologueEnd(prologueend), IsStmt(isstmt) {}
|
||||
|
||||
// Allow the default copy constructor and assignment operator to be used
|
||||
// for an MCCVLoc object.
|
||||
|
||||
public:
|
||||
unsigned getFunctionId() const { return FunctionId; }
|
||||
|
||||
/// \brief Get the FileNum of this MCCVLoc.
|
||||
unsigned getFileNum() const { return FileNum; }
|
||||
|
||||
/// \brief Get the Line of this MCCVLoc.
|
||||
unsigned getLine() const { return Line; }
|
||||
|
||||
/// \brief Get the Column of this MCCVLoc.
|
||||
unsigned getColumn() const { return Column; }
|
||||
|
||||
bool isPrologueEnd() const { return PrologueEnd; }
|
||||
bool isStmt() const { return IsStmt; }
|
||||
|
||||
void setFunctionId(unsigned FID) { FunctionId = FID; }
|
||||
|
||||
/// \brief Set the FileNum of this MCCVLoc.
|
||||
void setFileNum(unsigned fileNum) { FileNum = fileNum; }
|
||||
|
||||
/// \brief Set the Line of this MCCVLoc.
|
||||
void setLine(unsigned line) { Line = line; }
|
||||
|
||||
/// \brief Set the Column of this MCCVLoc.
|
||||
void setColumn(unsigned column) {
|
||||
assert(column <= UINT16_MAX);
|
||||
Column = column;
|
||||
}
|
||||
|
||||
void setPrologueEnd(bool PE) { PrologueEnd = PE; }
|
||||
void setIsStmt(bool IS) { IsStmt = IS; }
|
||||
};
|
||||
|
||||
/// \brief Instances of this class represent the line information for
|
||||
/// the CodeView line table entries. Which is created after a machine
|
||||
/// instruction is assembled and uses an address from a temporary label
|
||||
/// created at the current address in the current section and the info from
|
||||
/// the last .cv_loc directive seen as stored in the context.
|
||||
class MCCVLineEntry : public MCCVLoc {
|
||||
MCSymbol *Label;
|
||||
|
||||
private:
|
||||
// Allow the default copy constructor and assignment operator to be used
|
||||
// for an MCCVLineEntry object.
|
||||
|
||||
public:
|
||||
// Constructor to create an MCCVLineEntry given a symbol and the dwarf loc.
|
||||
MCCVLineEntry(MCSymbol *label, const MCCVLoc loc)
|
||||
: MCCVLoc(loc), Label(label) {}
|
||||
|
||||
MCSymbol *getLabel() const { return Label; }
|
||||
|
||||
// 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 a line entry made for it is made.
|
||||
static void Make(MCObjectStreamer *MCOS);
|
||||
};
|
||||
|
||||
/// Holds state from .cv_file and .cv_loc directives for later emission.
|
||||
class CodeViewContext {
|
||||
public:
|
||||
CodeViewContext();
|
||||
~CodeViewContext();
|
||||
|
||||
bool isValidFileNumber(unsigned FileNumber) const;
|
||||
bool addFile(unsigned FileNumber, StringRef Filename);
|
||||
ArrayRef<StringRef> getFilenames() { return Filenames; }
|
||||
|
||||
/// \brief Add a line entry.
|
||||
void addLineEntry(const MCCVLineEntry &LineEntry) {
|
||||
MCCVLines[LineEntry.getFunctionId()].push_back(LineEntry);
|
||||
}
|
||||
|
||||
ArrayRef<MCCVLineEntry> getFunctionLineEntries(unsigned FuncId) {
|
||||
assert(MCCVLines.find(FuncId) != MCCVLines.end());
|
||||
return MCCVLines.find(FuncId)->second;
|
||||
}
|
||||
|
||||
/// Emits a line table substream.
|
||||
void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId,
|
||||
const MCSymbol *FuncBegin,
|
||||
const MCSymbol *FuncEnd);
|
||||
|
||||
/// Emits the string table substream.
|
||||
void emitStringTable(MCObjectStreamer &OS);
|
||||
|
||||
/// Emits the file checksum substream.
|
||||
void emitFileChecksums(MCObjectStreamer &OS);
|
||||
|
||||
private:
|
||||
/// Map from string to string table offset.
|
||||
StringMap<unsigned> StringTable;
|
||||
|
||||
/// The fragment that ultimately holds our strings.
|
||||
MCDataFragment *StrTabFragment = nullptr;
|
||||
bool InsertedStrTabFragment = false;
|
||||
|
||||
MCDataFragment *getStringTableFragment();
|
||||
|
||||
/// Add something to the string table.
|
||||
StringRef addToStringTable(StringRef S);
|
||||
|
||||
/// Get a string table offset.
|
||||
unsigned getStringTableOffset(StringRef S);
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
#endif
|
@ -16,6 +16,7 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/MC/MCCodeView.h"
|
||||
#include "llvm/MC/MCDwarf.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/SectionKind.h"
|
||||
@ -42,6 +43,7 @@ namespace llvm {
|
||||
class MCSectionMachO;
|
||||
class MCSectionELF;
|
||||
class MCSectionCOFF;
|
||||
class CodeViewContext;
|
||||
|
||||
/// Context object for machine code objects. This class owns all of the
|
||||
/// sections that it creates.
|
||||
@ -66,6 +68,8 @@ namespace llvm {
|
||||
/// The MCObjectFileInfo for this target.
|
||||
const MCObjectFileInfo *MOFI;
|
||||
|
||||
std::unique_ptr<CodeViewContext> CVContext;
|
||||
|
||||
/// Allocator object used for creating machine code objects.
|
||||
///
|
||||
/// We use a bump pointer allocator to avoid the need to track all allocated
|
||||
@ -135,6 +139,10 @@ namespace llvm {
|
||||
MCDwarfLoc CurrentDwarfLoc;
|
||||
bool DwarfLocSeen;
|
||||
|
||||
/// The current CodeView line information from the last .cv_loc directive.
|
||||
MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true);
|
||||
bool CVLocSeen = false;
|
||||
|
||||
/// Generate dwarf debugging info for assembly source files.
|
||||
bool GenDwarfForAssembly;
|
||||
|
||||
@ -237,6 +245,8 @@ namespace llvm {
|
||||
|
||||
const MCObjectFileInfo *getObjectFileInfo() const { return MOFI; }
|
||||
|
||||
CodeViewContext &getCVContext();
|
||||
|
||||
void setAllowTemporaryLabels(bool Value) { AllowTemporaryLabels = Value; }
|
||||
void setUseNamesOnTempLabels(bool Value) { UseNamesOnTempLabels = Value; }
|
||||
|
||||
@ -505,6 +515,35 @@ namespace llvm {
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// \name CodeView Management
|
||||
/// @{
|
||||
|
||||
/// Creates an entry in the cv file table.
|
||||
unsigned getCVFile(StringRef FileName, unsigned FileNumber);
|
||||
|
||||
/// Saves the information from the currently parsed .cv_loc directive
|
||||
/// and sets CVLocSeen. When the next instruction is assembled an entry
|
||||
/// in the line number table with this information and the address of the
|
||||
/// instruction will be created.
|
||||
void setCurrentCVLoc(unsigned FunctionId, unsigned FileNo, unsigned Line,
|
||||
unsigned Column, bool PrologueEnd, bool IsStmt) {
|
||||
CurrentCVLoc.setFunctionId(FunctionId);
|
||||
CurrentCVLoc.setFileNum(FileNo);
|
||||
CurrentCVLoc.setLine(Line);
|
||||
CurrentCVLoc.setColumn(Column);
|
||||
CurrentCVLoc.setPrologueEnd(PrologueEnd);
|
||||
CurrentCVLoc.setIsStmt(IsStmt);
|
||||
CVLocSeen = true;
|
||||
}
|
||||
void clearCVLocSeen() { CVLocSeen = false; }
|
||||
|
||||
bool getCVLocSeen() { return CVLocSeen; }
|
||||
const MCCVLoc &getCurrentCVLoc() { return CurrentCVLoc; }
|
||||
|
||||
bool isValidCVFileNumber(unsigned FileNumber);
|
||||
/// @}
|
||||
|
||||
char *getSecureLogFile() { return SecureLogFile; }
|
||||
raw_fd_ostream *getSecureLog() { return SecureLog.get(); }
|
||||
bool getSecureLogUsed() { return SecureLogUsed; }
|
||||
|
@ -59,7 +59,6 @@ public:
|
||||
void EmitFrames(MCAsmBackend *MAB);
|
||||
void EmitCFISections(bool EH, bool Debug) override;
|
||||
|
||||
protected:
|
||||
MCFragment *getCurrentFragment() const;
|
||||
|
||||
void insert(MCFragment *F) {
|
||||
@ -73,6 +72,7 @@ protected:
|
||||
/// fragment is not a data fragment.
|
||||
MCDataFragment *getOrCreateDataFragment();
|
||||
|
||||
protected:
|
||||
bool changeSectionImpl(MCSection *Section, const MCExpr *Subsection);
|
||||
|
||||
/// If any labels have been emitted but not assigned fragments, ensure that
|
||||
@ -122,6 +122,13 @@ public:
|
||||
unsigned PointerSize);
|
||||
void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
|
||||
const MCSymbol *Label);
|
||||
void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
|
||||
unsigned Column, bool PrologueEnd, bool IsStmt,
|
||||
StringRef FileName) override;
|
||||
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin,
|
||||
const MCSymbol *End) override;
|
||||
void EmitCVStringTableDirective() override;
|
||||
void EmitCVFileChecksumsDirective() override;
|
||||
void EmitGPRel32Value(const MCExpr *Value) override;
|
||||
void EmitGPRel64Value(const MCExpr *Value) override;
|
||||
bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
|
@ -640,6 +640,27 @@ public:
|
||||
unsigned Isa, unsigned Discriminator,
|
||||
StringRef FileName);
|
||||
|
||||
/// \brief Associate a filename with a specified logical file number. This
|
||||
/// implements the '.cv_file 4 "foo.c"' assembler directive.
|
||||
virtual unsigned EmitCVFileDirective(unsigned FileNo, StringRef Filename);
|
||||
|
||||
/// \brief This implements the CodeView '.cv_loc' assembler directive.
|
||||
virtual void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
|
||||
unsigned Line, unsigned Column,
|
||||
bool PrologueEnd, bool IsStmt,
|
||||
StringRef FileName);
|
||||
|
||||
/// \brief This implements the CodeView '.cv_linetable' assembler directive.
|
||||
virtual void EmitCVLinetableDirective(unsigned FunctionId,
|
||||
const MCSymbol *FnStart,
|
||||
const MCSymbol *FnEnd);
|
||||
|
||||
/// \brief This implements the CodeView '.cv_stringtable' assembler directive.
|
||||
virtual void EmitCVStringTableDirective() {}
|
||||
|
||||
/// \brief This implements the CodeView '.cv_filechecksums' assembler directive.
|
||||
virtual void EmitCVFileChecksumsDirective() {}
|
||||
|
||||
/// Emit the absolute difference between two symbols.
|
||||
///
|
||||
/// \pre Offset of \c Hi is greater than the offset \c Lo.
|
||||
|
@ -27,6 +27,8 @@ private:
|
||||
size_t Size = 0;
|
||||
Kind K;
|
||||
|
||||
void finalizeStringTable(bool Optimize);
|
||||
|
||||
public:
|
||||
StringTableBuilder(Kind K);
|
||||
|
||||
@ -39,6 +41,10 @@ public:
|
||||
/// be added after this point.
|
||||
void finalize();
|
||||
|
||||
/// Finalize the string table without reording it. In this mode, offsets
|
||||
/// returned by add will still be valid.
|
||||
void finalizeInOrder();
|
||||
|
||||
/// \brief Retrieve the string table data. Can only be used after the table
|
||||
/// is finalized.
|
||||
StringRef data() const {
|
||||
|
@ -656,17 +656,7 @@ namespace COFF {
|
||||
}
|
||||
};
|
||||
|
||||
enum CodeViewLine : unsigned {
|
||||
CVL_LineNumberStartBits = 24,
|
||||
CVL_LineNumberEndDeltaBits = 7,
|
||||
CVL_LineNumberEndDeltaMask = (1U << CVL_LineNumberEndDeltaBits) - 1,
|
||||
CVL_MaxLineNumber = (1U << CVL_LineNumberStartBits) - 1,
|
||||
CVL_IsStatement = 1U << 31,
|
||||
CVL_MaxColumnNumber = UINT16_MAX,
|
||||
};
|
||||
|
||||
enum CodeViewIdentifiers {
|
||||
DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS = 0x1,
|
||||
DEBUG_SECTION_MAGIC = 0x4,
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "CodeViewDebug.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
@ -74,6 +75,18 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) {
|
||||
return Filepath;
|
||||
}
|
||||
|
||||
unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
|
||||
unsigned NextId = FileIdMap.size() + 1;
|
||||
auto Insertion = FileIdMap.insert(std::make_pair(F, NextId));
|
||||
if (Insertion.second) {
|
||||
// We have to compute the full filepath and emit a .cv_file directive.
|
||||
StringRef FullPath = getFullFilepath(F);
|
||||
NextId = Asm->OutStreamer->EmitCVFileDirective(NextId, FullPath);
|
||||
assert(NextId == FileIdMap.size() && ".cv_file directive failed");
|
||||
}
|
||||
return Insertion.first->second;
|
||||
}
|
||||
|
||||
void CodeViewDebug::maybeRecordLocation(DebugLoc DL,
|
||||
const MachineFunction *MF) {
|
||||
// Skip this instruction if it has the same location as the previous one.
|
||||
@ -85,15 +98,26 @@ void CodeViewDebug::maybeRecordLocation(DebugLoc DL,
|
||||
return;
|
||||
|
||||
// Skip this line if it is longer than the maximum we can record.
|
||||
if (DL.getLine() > COFF::CVL_MaxLineNumber)
|
||||
LineInfo LI(DL.getLine(), DL.getLine(), /*IsStatement=*/true);
|
||||
if (LI.getStartLine() != DL.getLine() || LI.isAlwaysStepInto() ||
|
||||
LI.isNeverStepInto())
|
||||
return;
|
||||
|
||||
CurFn->LastLoc = DL;
|
||||
ColumnInfo CI(DL.getCol(), /*EndColumn=*/0);
|
||||
if (CI.getStartColumn() != DL.getCol())
|
||||
return;
|
||||
|
||||
MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol();
|
||||
Asm->OutStreamer->EmitLabel(MCL);
|
||||
CurFn->Instrs.push_back(MCL);
|
||||
LabelsAndLocs[MCL] = DL;
|
||||
if (!CurFn->HaveLineInfo)
|
||||
CurFn->HaveLineInfo = true;
|
||||
unsigned FileId = 0;
|
||||
if (CurFn->LastLoc.get() && CurFn->LastLoc->getFile() == DL->getFile())
|
||||
FileId = CurFn->LastFileId;
|
||||
else
|
||||
FileId = CurFn->LastFileId = maybeRecordFile(DL->getFile());
|
||||
CurFn->LastLoc = DL;
|
||||
Asm->OutStreamer->EmitCVLocDirective(CurFn->FuncId, FileId, DL.getLine(),
|
||||
DL.getCol(), /*PrologueEnd=*/false,
|
||||
/*IsStmt=*/false, DL->getFilename());
|
||||
}
|
||||
|
||||
CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
|
||||
@ -128,39 +152,17 @@ void CodeViewDebug::endModule() {
|
||||
// of the payload followed by the payload itself. The subsections are 4-byte
|
||||
// aligned.
|
||||
|
||||
// Emit per-function debug information. This code is extracted into a
|
||||
// separate function for readability.
|
||||
for (size_t I = 0, E = VisitedFunctions.size(); I != E; ++I)
|
||||
emitDebugInfoForFunction(VisitedFunctions[I]);
|
||||
// Emit per-function debug information.
|
||||
for (auto &P : FnDebugInfo)
|
||||
emitDebugInfoForFunction(P.first, P.second);
|
||||
|
||||
// This subsection holds a file index to offset in string table table.
|
||||
Asm->OutStreamer->AddComment("File index to string table offset subsection");
|
||||
Asm->EmitInt32(unsigned(ModuleSubstreamKind::FileChecksums));
|
||||
size_t NumFilenames = FileNameRegistry.Infos.size();
|
||||
Asm->EmitInt32(8 * NumFilenames);
|
||||
for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
|
||||
StringRef Filename = FileNameRegistry.Filenames[I];
|
||||
// For each unique filename, just write its offset in the string table.
|
||||
Asm->EmitInt32(FileNameRegistry.Infos[Filename].StartOffset);
|
||||
// The function name offset is not followed by any additional data.
|
||||
Asm->EmitInt32(0);
|
||||
}
|
||||
Asm->OutStreamer->EmitCVFileChecksumsDirective();
|
||||
|
||||
// This subsection holds the string table.
|
||||
Asm->OutStreamer->AddComment("String table");
|
||||
Asm->EmitInt32(unsigned(ModuleSubstreamKind::StringTable));
|
||||
Asm->EmitInt32(FileNameRegistry.LastOffset);
|
||||
// The payload starts with a null character.
|
||||
Asm->EmitInt8(0);
|
||||
|
||||
for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
|
||||
// Just emit unique filenames one by one, separated by a null character.
|
||||
Asm->OutStreamer->EmitBytes(FileNameRegistry.Filenames[I]);
|
||||
Asm->EmitInt8(0);
|
||||
}
|
||||
|
||||
// No more subsections. Fill with zeros to align the end of the section by 4.
|
||||
Asm->OutStreamer->EmitFill((-FileNameRegistry.LastOffset) % 4, 0);
|
||||
Asm->OutStreamer->EmitCVStringTableDirective();
|
||||
|
||||
clear();
|
||||
}
|
||||
@ -177,21 +179,13 @@ static void EmitLabelDiff(MCStreamer &Streamer,
|
||||
Streamer.EmitValue(AddrDelta, Size);
|
||||
}
|
||||
|
||||
static const DIFile *getFileFromLoc(DebugLoc DL) {
|
||||
return DL.get()->getScope()->getFile();
|
||||
}
|
||||
|
||||
void CodeViewDebug::emitDebugInfoForFunction(const Function *GV) {
|
||||
void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
|
||||
FunctionInfo &FI) {
|
||||
// For each function there is a separate subsection
|
||||
// which holds the PC to file:line table.
|
||||
const MCSymbol *Fn = Asm->getSymbol(GV);
|
||||
assert(Fn);
|
||||
|
||||
const FunctionInfo &FI = FnDebugInfo[GV];
|
||||
if (FI.Instrs.empty())
|
||||
return;
|
||||
assert(FI.End && "Don't know where the function ends?");
|
||||
|
||||
StringRef FuncName;
|
||||
if (auto *SP = getDISubprogram(GV))
|
||||
FuncName = SP->getDisplayName();
|
||||
@ -238,102 +232,8 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV) {
|
||||
// Every subsection must be aligned to a 4-byte boundary.
|
||||
Asm->OutStreamer->EmitFill((-FuncName.size()) % 4, 0);
|
||||
|
||||
// PCs/Instructions are grouped into segments sharing the same filename.
|
||||
// Pre-calculate the lengths (in instructions) of these segments and store
|
||||
// them in a map for convenience. Each index in the map is the sequential
|
||||
// number of the respective instruction that starts a new segment.
|
||||
DenseMap<size_t, size_t> FilenameSegmentLengths;
|
||||
size_t LastSegmentEnd = 0;
|
||||
const DIFile *PrevFile = getFileFromLoc(LabelsAndLocs[FI.Instrs[0]]);
|
||||
for (size_t J = 1, F = FI.Instrs.size(); J != F; ++J) {
|
||||
const DIFile *CurFile = getFileFromLoc(LabelsAndLocs[FI.Instrs[J]]);
|
||||
if (PrevFile == CurFile)
|
||||
continue;
|
||||
FilenameSegmentLengths[LastSegmentEnd] = J - LastSegmentEnd;
|
||||
LastSegmentEnd = J;
|
||||
PrevFile = CurFile;
|
||||
}
|
||||
FilenameSegmentLengths[LastSegmentEnd] = FI.Instrs.size() - LastSegmentEnd;
|
||||
|
||||
// Emit a line table subsection, required to do PC-to-file:line lookup.
|
||||
Asm->OutStreamer->AddComment("Line table subsection for " + Twine(FuncName));
|
||||
Asm->EmitInt32(unsigned(ModuleSubstreamKind::Lines));
|
||||
MCSymbol *LineTableBegin = Asm->MMI->getContext().createTempSymbol(),
|
||||
*LineTableEnd = Asm->MMI->getContext().createTempSymbol();
|
||||
EmitLabelDiff(*Asm->OutStreamer, LineTableBegin, LineTableEnd);
|
||||
Asm->OutStreamer->EmitLabel(LineTableBegin);
|
||||
|
||||
// Identify the function this subsection is for.
|
||||
Asm->OutStreamer->EmitCOFFSecRel32(Fn);
|
||||
Asm->OutStreamer->EmitCOFFSectionIndex(Fn);
|
||||
// Insert flags after a 16-bit section index.
|
||||
Asm->EmitInt16(COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS);
|
||||
|
||||
// Length of the function's code, in bytes.
|
||||
EmitLabelDiff(*Asm->OutStreamer, Fn, FI.End);
|
||||
|
||||
// PC-to-linenumber lookup table:
|
||||
MCSymbol *FileSegmentEnd = nullptr;
|
||||
|
||||
// The start of the last segment:
|
||||
size_t LastSegmentStart = 0;
|
||||
|
||||
auto FinishPreviousChunk = [&] {
|
||||
if (!FileSegmentEnd)
|
||||
return;
|
||||
for (size_t ColSegI = LastSegmentStart,
|
||||
ColSegEnd = ColSegI + FilenameSegmentLengths[LastSegmentStart];
|
||||
ColSegI != ColSegEnd; ++ColSegI) {
|
||||
unsigned ColumnNumber = LabelsAndLocs[FI.Instrs[ColSegI]].getCol();
|
||||
// Truncate the column number if it is longer than the maximum we can
|
||||
// record.
|
||||
if (ColumnNumber > COFF::CVL_MaxColumnNumber)
|
||||
ColumnNumber = 0;
|
||||
Asm->EmitInt16(ColumnNumber); // Start column
|
||||
Asm->EmitInt16(0); // End column
|
||||
}
|
||||
Asm->OutStreamer->EmitLabel(FileSegmentEnd);
|
||||
};
|
||||
|
||||
for (size_t J = 0, F = FI.Instrs.size(); J != F; ++J) {
|
||||
MCSymbol *Instr = FI.Instrs[J];
|
||||
assert(LabelsAndLocs.count(Instr));
|
||||
|
||||
if (FilenameSegmentLengths.count(J)) {
|
||||
// We came to a beginning of a new filename segment.
|
||||
FinishPreviousChunk();
|
||||
const DIFile *File = getFileFromLoc(LabelsAndLocs[FI.Instrs[J]]);
|
||||
StringRef CurFilename = getFullFilepath(File);
|
||||
size_t IndexInFileTable = FileNameRegistry.add(CurFilename);
|
||||
// Each segment starts with the offset of the filename
|
||||
// in the string table.
|
||||
Asm->OutStreamer->AddComment(
|
||||
"Segment for file '" + Twine(CurFilename) + "' begins");
|
||||
MCSymbol *FileSegmentBegin = Asm->MMI->getContext().createTempSymbol();
|
||||
Asm->OutStreamer->EmitLabel(FileSegmentBegin);
|
||||
Asm->EmitInt32(8 * IndexInFileTable);
|
||||
|
||||
// Number of PC records in the lookup table.
|
||||
size_t SegmentLength = FilenameSegmentLengths[J];
|
||||
Asm->EmitInt32(SegmentLength);
|
||||
|
||||
// Full size of the segment for this filename, including the prev two
|
||||
// records.
|
||||
FileSegmentEnd = Asm->MMI->getContext().createTempSymbol();
|
||||
EmitLabelDiff(*Asm->OutStreamer, FileSegmentBegin, FileSegmentEnd);
|
||||
LastSegmentStart = J;
|
||||
}
|
||||
|
||||
// The first PC with the given linenumber and the linenumber itself.
|
||||
EmitLabelDiff(*Asm->OutStreamer, Fn, Instr);
|
||||
uint32_t LineNumber = LabelsAndLocs[Instr].getLine();
|
||||
assert(LineNumber <= COFF::CVL_MaxLineNumber);
|
||||
uint32_t LineData = LineNumber | COFF::CVL_IsStatement;
|
||||
Asm->EmitInt32(LineData);
|
||||
}
|
||||
|
||||
FinishPreviousChunk();
|
||||
Asm->OutStreamer->EmitLabel(LineTableEnd);
|
||||
// We have an assembler directive that takes care of the whole line table.
|
||||
Asm->OutStreamer->EmitCVLinetableDirective(FI.FuncId, Fn, FI.End);
|
||||
}
|
||||
|
||||
void CodeViewDebug::beginFunction(const MachineFunction *MF) {
|
||||
@ -344,8 +244,8 @@ void CodeViewDebug::beginFunction(const MachineFunction *MF) {
|
||||
|
||||
const Function *GV = MF->getFunction();
|
||||
assert(FnDebugInfo.count(GV) == false);
|
||||
VisitedFunctions.push_back(GV);
|
||||
CurFn = &FnDebugInfo[GV];
|
||||
CurFn->FuncId = NextFuncId++;
|
||||
|
||||
// Find the end of the function prolog.
|
||||
// FIXME: is there a simpler a way to do this? Can we just search
|
||||
@ -384,9 +284,9 @@ void CodeViewDebug::endFunction(const MachineFunction *MF) {
|
||||
assert(FnDebugInfo.count(GV));
|
||||
assert(CurFn == &FnDebugInfo[GV]);
|
||||
|
||||
if (CurFn->Instrs.empty()) {
|
||||
// Don't emit anything if we don't have any line tables.
|
||||
if (!CurFn->HaveLineInfo) {
|
||||
FnDebugInfo.erase(GV);
|
||||
VisitedFunctions.pop_back();
|
||||
} else {
|
||||
CurFn->End = Asm->getFunctionEnd();
|
||||
}
|
||||
|
@ -37,72 +37,38 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public AsmPrinterHandler {
|
||||
// to the end of the function.
|
||||
struct FunctionInfo {
|
||||
DebugLoc LastLoc;
|
||||
SmallVector<MCSymbol *, 10> Instrs;
|
||||
MCSymbol *End;
|
||||
FunctionInfo() : End(nullptr) {}
|
||||
MCSymbol *End = nullptr;
|
||||
unsigned FuncId = 0;
|
||||
unsigned LastFileId;
|
||||
bool HaveLineInfo = false;
|
||||
};
|
||||
FunctionInfo *CurFn;
|
||||
|
||||
typedef DenseMap<const Function *, FunctionInfo> FnDebugInfoTy;
|
||||
FnDebugInfoTy FnDebugInfo;
|
||||
// Store the functions we've visited in a vector so we can maintain a stable
|
||||
// order while emitting subsections.
|
||||
SmallVector<const Function *, 10> VisitedFunctions;
|
||||
unsigned NextFuncId = 0;
|
||||
|
||||
DenseMap<MCSymbol *, DebugLoc> LabelsAndLocs;
|
||||
/// Remember some debug info about each function. Keep it in a stable order to
|
||||
/// emit at the end of the TU.
|
||||
MapVector<const Function *, FunctionInfo> FnDebugInfo;
|
||||
|
||||
// FileNameRegistry - Manages filenames observed while generating debug info
|
||||
// by filtering out duplicates and bookkeeping the offsets in the string
|
||||
// table to be generated.
|
||||
struct FileNameRegistryTy {
|
||||
SmallVector<StringRef, 10> Filenames;
|
||||
struct PerFileInfo {
|
||||
size_t FilenameID, StartOffset;
|
||||
};
|
||||
StringMap<PerFileInfo> Infos;
|
||||
|
||||
// The offset in the string table where we'll write the next unique
|
||||
// filename.
|
||||
size_t LastOffset;
|
||||
|
||||
FileNameRegistryTy() {
|
||||
clear();
|
||||
}
|
||||
|
||||
// Add Filename to the registry, if it was not observed before.
|
||||
size_t add(StringRef Filename) {
|
||||
size_t OldSize = Infos.size();
|
||||
bool Inserted;
|
||||
StringMap<PerFileInfo>::iterator It;
|
||||
std::tie(It, Inserted) = Infos.insert(
|
||||
std::make_pair(Filename, PerFileInfo{OldSize, LastOffset}));
|
||||
if (Inserted) {
|
||||
LastOffset += Filename.size() + 1;
|
||||
Filenames.push_back(Filename);
|
||||
}
|
||||
return It->second.FilenameID;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
LastOffset = 1;
|
||||
Infos.clear();
|
||||
Filenames.clear();
|
||||
}
|
||||
} FileNameRegistry;
|
||||
/// Map from DIFile to .cv_file id.
|
||||
DenseMap<const DIFile *, unsigned> FileIdMap;
|
||||
|
||||
typedef std::map<const DIFile *, std::string> FileToFilepathMapTy;
|
||||
FileToFilepathMapTy FileToFilepathMap;
|
||||
StringRef getFullFilepath(const DIFile *S);
|
||||
|
||||
unsigned maybeRecordFile(const DIFile *F);
|
||||
|
||||
void maybeRecordLocation(DebugLoc DL, const MachineFunction *MF);
|
||||
|
||||
void clear() {
|
||||
assert(CurFn == nullptr);
|
||||
FileNameRegistry.clear();
|
||||
LabelsAndLocs.clear();
|
||||
FileIdMap.clear();
|
||||
FnDebugInfo.clear();
|
||||
FileToFilepathMap.clear();
|
||||
}
|
||||
|
||||
void emitDebugInfoForFunction(const Function *GV);
|
||||
void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI);
|
||||
|
||||
public:
|
||||
CodeViewDebug(AsmPrinter *Asm);
|
||||
|
@ -10,6 +10,7 @@ add_llvm_library(LLVMMC
|
||||
MCAssembler.cpp
|
||||
MCCodeEmitter.cpp
|
||||
MCCodeGenInfo.cpp
|
||||
MCCodeView.cpp
|
||||
MCContext.cpp
|
||||
MCDwarf.cpp
|
||||
MCELFObjectTargetWriter.cpp
|
||||
|
@ -199,6 +199,15 @@ public:
|
||||
StringRef FileName) override;
|
||||
MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
|
||||
|
||||
unsigned EmitCVFileDirective(unsigned FileNo, StringRef Filename) override;
|
||||
void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
|
||||
unsigned Column, bool PrologueEnd, bool IsStmt,
|
||||
StringRef FileName) override;
|
||||
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
|
||||
const MCSymbol *FnEnd) override;
|
||||
void EmitCVStringTableDirective() override;
|
||||
void EmitCVFileChecksumsDirective() override;
|
||||
|
||||
void EmitIdent(StringRef IdentString) override;
|
||||
void EmitCFISections(bool EH, bool Debug) override;
|
||||
void EmitCFIDefCfa(int64_t Register, int64_t Offset) override;
|
||||
@ -954,6 +963,69 @@ MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
|
||||
return MCStreamer::getDwarfLineTableSymbol(0);
|
||||
}
|
||||
|
||||
unsigned MCAsmStreamer::EmitCVFileDirective(unsigned FileNo,
|
||||
StringRef Filename) {
|
||||
if (!getContext().getCVFile(Filename, FileNo))
|
||||
return 0;
|
||||
|
||||
OS << "\t.cv_file\t" << FileNo << ' ';
|
||||
|
||||
PrintQuotedString(Filename, OS);
|
||||
EmitEOL();
|
||||
|
||||
return FileNo;
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
|
||||
unsigned Line, unsigned Column,
|
||||
bool PrologueEnd, bool IsStmt,
|
||||
StringRef FileName) {
|
||||
OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
|
||||
<< Column;
|
||||
if (PrologueEnd)
|
||||
OS << " prologue_end";
|
||||
|
||||
unsigned OldIsStmt = getContext().getCurrentCVLoc().isStmt();
|
||||
if (IsStmt != OldIsStmt) {
|
||||
OS << " is_stmt ";
|
||||
|
||||
if (IsStmt)
|
||||
OS << "1";
|
||||
else
|
||||
OS << "0";
|
||||
}
|
||||
|
||||
if (IsVerboseAsm) {
|
||||
OS.PadToColumn(MAI->getCommentColumn());
|
||||
OS << MAI->getCommentString() << ' ' << FileName << ':'
|
||||
<< Line << ':' << Column;
|
||||
}
|
||||
EmitEOL();
|
||||
this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column,
|
||||
PrologueEnd, IsStmt, FileName);
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
|
||||
const MCSymbol *FnStart,
|
||||
const MCSymbol *FnEnd) {
|
||||
OS << "\t.cv_linetable\t" << FunctionId << ", ";
|
||||
FnStart->print(OS, MAI);
|
||||
OS << ", ";
|
||||
FnEnd->print(OS, MAI);
|
||||
EmitEOL();
|
||||
this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd);
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitCVStringTableDirective() {
|
||||
OS << "\t.cv_stringtable";
|
||||
EmitEOL();
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitCVFileChecksumsDirective() {
|
||||
OS << "\t.cv_filechecksums";
|
||||
EmitEOL();
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitIdent(StringRef IdentString) {
|
||||
assert(MAI->hasIdentDirective() && ".ident directive not supported");
|
||||
OS << "\t.ident\t";
|
||||
|
222
lib/MC/MCCodeView.cpp
Normal file
222
lib/MC/MCCodeView.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Holds state from .cv_file and .cv_loc directives for later emission.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/MC/MCCodeView.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCObjectStreamer.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
CodeViewContext::CodeViewContext() {}
|
||||
|
||||
CodeViewContext::~CodeViewContext() {
|
||||
// If someone inserted strings into the string table but never actually
|
||||
// emitted them somewhere, clean up the fragment.
|
||||
if (!InsertedStrTabFragment)
|
||||
delete StrTabFragment;
|
||||
}
|
||||
|
||||
/// This is a valid number for use with .cv_loc if we've already seen a .cv_file
|
||||
/// for it.
|
||||
bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const {
|
||||
unsigned Idx = FileNumber - 1;
|
||||
if (Idx < Filenames.size())
|
||||
return !Filenames[Idx].empty();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) {
|
||||
assert(FileNumber > 0);
|
||||
Filename = addToStringTable(Filename);
|
||||
unsigned Idx = FileNumber - 1;
|
||||
if (Idx >= Filenames.size())
|
||||
Filenames.resize(Idx + 1);
|
||||
|
||||
if (Filename.empty())
|
||||
Filename = "<stdin>";
|
||||
|
||||
if (!Filenames[Idx].empty())
|
||||
return false;
|
||||
|
||||
// FIXME: We should store the string table offset of the filename, rather than
|
||||
// the filename itself for efficiency.
|
||||
Filename = addToStringTable(Filename);
|
||||
|
||||
Filenames[Idx] = Filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
MCDataFragment *CodeViewContext::getStringTableFragment() {
|
||||
if (!StrTabFragment) {
|
||||
StrTabFragment = new MCDataFragment();
|
||||
// Start a new string table out with a null byte.
|
||||
StrTabFragment->getContents().push_back('\0');
|
||||
}
|
||||
return StrTabFragment;
|
||||
}
|
||||
|
||||
StringRef CodeViewContext::addToStringTable(StringRef S) {
|
||||
SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents();
|
||||
auto Insertion =
|
||||
StringTable.insert(std::make_pair(S, unsigned(Contents.size())));
|
||||
// Return the string from the table, since it is stable.
|
||||
S = Insertion.first->first();
|
||||
if (Insertion.second) {
|
||||
// The string map key is always null terminated.
|
||||
Contents.append(S.begin(), S.end() + 1);
|
||||
}
|
||||
return S;
|
||||
}
|
||||
|
||||
unsigned CodeViewContext::getStringTableOffset(StringRef S) {
|
||||
// A string table offset of zero is always the empty string.
|
||||
if (S.empty())
|
||||
return 0;
|
||||
auto I = StringTable.find(S);
|
||||
assert(I != StringTable.end());
|
||||
return I->second;
|
||||
}
|
||||
|
||||
void CodeViewContext::emitStringTable(MCObjectStreamer &OS) {
|
||||
MCContext &Ctx = OS.getContext();
|
||||
MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin"),
|
||||
*StringEnd = Ctx.createTempSymbol("strtab_end");
|
||||
|
||||
OS.EmitIntValue(unsigned(ModuleSubstreamKind::StringTable), 4);
|
||||
OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4);
|
||||
OS.EmitLabel(StringBegin);
|
||||
|
||||
// Put the string table data fragment here, if we haven't already put it
|
||||
// somewhere else. If somebody wants two string tables in their .s file, one
|
||||
// will just be empty.
|
||||
if (!InsertedStrTabFragment) {
|
||||
OS.insert(getStringTableFragment());
|
||||
InsertedStrTabFragment = true;
|
||||
}
|
||||
|
||||
OS.EmitValueToAlignment(4, 0);
|
||||
|
||||
OS.EmitLabel(StringEnd);
|
||||
}
|
||||
|
||||
void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) {
|
||||
MCContext &Ctx = OS.getContext();
|
||||
MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin"),
|
||||
*FileEnd = Ctx.createTempSymbol("filechecksums_end");
|
||||
|
||||
OS.EmitIntValue(unsigned(ModuleSubstreamKind::FileChecksums), 4);
|
||||
OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4);
|
||||
OS.EmitLabel(FileBegin);
|
||||
|
||||
// Emit an array of FileChecksum entries. We index into this table using the
|
||||
// user-provided file number. Each entry is currently 8 bytes, as we don't
|
||||
// emit checksums.
|
||||
for (StringRef Filename : Filenames) {
|
||||
OS.EmitIntValue(getStringTableOffset(Filename), 4);
|
||||
// Zero the next two fields and align back to 4 bytes. This indicates that
|
||||
// no checksum is present.
|
||||
OS.EmitIntValue(0, 4);
|
||||
}
|
||||
|
||||
OS.EmitLabel(FileEnd);
|
||||
}
|
||||
|
||||
void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
|
||||
unsigned FuncId,
|
||||
const MCSymbol *FuncBegin,
|
||||
const MCSymbol *FuncEnd) {
|
||||
MCContext &Ctx = OS.getContext();
|
||||
MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin"),
|
||||
*LineEnd = Ctx.createTempSymbol("linetable_end");
|
||||
|
||||
OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4);
|
||||
OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
|
||||
OS.EmitLabel(LineBegin);
|
||||
OS.EmitCOFFSecRel32(FuncBegin);
|
||||
OS.EmitCOFFSectionIndex(FuncBegin);
|
||||
|
||||
// Actual line info.
|
||||
ArrayRef<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId);
|
||||
bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) {
|
||||
return LineEntry.getColumn() != 0;
|
||||
});
|
||||
OS.EmitIntValue(HaveColumns ? codeview::LineFlags::HaveColumns : 0, 2);
|
||||
OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
|
||||
|
||||
for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
|
||||
// Emit a file segment for the run of locations that share a file id.
|
||||
unsigned CurFileNum = I->getFileNum();
|
||||
auto FileSegEnd =
|
||||
std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) {
|
||||
return Loc.getFileNum() != CurFileNum;
|
||||
});
|
||||
unsigned EntryCount = FileSegEnd - I;
|
||||
OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) +
|
||||
"' begins");
|
||||
OS.EmitIntValue(8 * (CurFileNum - 1), 4);
|
||||
OS.EmitIntValue(EntryCount, 4);
|
||||
uint32_t SegmentSize = 12;
|
||||
SegmentSize += 8 * EntryCount;
|
||||
if (HaveColumns)
|
||||
SegmentSize += 4 * EntryCount;
|
||||
OS.EmitIntValue(SegmentSize, 4);
|
||||
|
||||
for (auto J = I; J != FileSegEnd; ++J) {
|
||||
OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
|
||||
unsigned LineData = J->getLine();
|
||||
if (J->isStmt())
|
||||
LineData |= codeview::LineInfo::StatementFlag;
|
||||
OS.EmitIntValue(LineData, 4);
|
||||
}
|
||||
if (HaveColumns) {
|
||||
for (auto J = I; J != FileSegEnd; ++J) {
|
||||
OS.EmitIntValue(J->getColumn(), 2);
|
||||
OS.EmitIntValue(0, 2);
|
||||
}
|
||||
}
|
||||
I = FileSegEnd;
|
||||
}
|
||||
OS.EmitLabel(LineEnd);
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
// a line entry made for it is made.
|
||||
//
|
||||
void MCCVLineEntry::Make(MCObjectStreamer *MCOS) {
|
||||
if (!MCOS->getContext().getCVLocSeen())
|
||||
return;
|
||||
|
||||
// Create a symbol at in the current section for use in the line entry.
|
||||
MCSymbol *LineSym = MCOS->getContext().createTempSymbol();
|
||||
// Set the value of the symbol to use for the MCCVLineEntry.
|
||||
MCOS->EmitLabel(LineSym);
|
||||
|
||||
// Get the current .loc info saved in the context.
|
||||
const MCCVLoc &CVLoc = MCOS->getContext().getCurrentCVLoc();
|
||||
|
||||
// Create a (local) line entry with the symbol and the current .loc info.
|
||||
MCCVLineEntry LineEntry(LineSym, CVLoc);
|
||||
|
||||
// clear CVLocSeen saying the current .loc info is now used.
|
||||
MCOS->getContext().clearCVLocSeen();
|
||||
|
||||
// Add the line entry to this section's entries.
|
||||
MCOS->getContext().getCVContext().addLineEntry(LineEntry);
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/MC/MCAssembler.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCCodeView.h"
|
||||
#include "llvm/MC/MCDwarf.h"
|
||||
#include "llvm/MC/MCLabel.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
@ -90,6 +91,8 @@ void MCContext::reset() {
|
||||
DwarfCompileUnitID = 0;
|
||||
CurrentDwarfLoc = MCDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0);
|
||||
|
||||
CVContext.reset();
|
||||
|
||||
MachOUniquingMap.clear();
|
||||
ELFUniquingMap.clear();
|
||||
COFFUniquingMap.clear();
|
||||
@ -474,6 +477,20 @@ void MCContext::finalizeDwarfSections(MCStreamer &MCOS) {
|
||||
[&](MCSection *Sec) { return !MCOS.mayHaveInstructions(*Sec); });
|
||||
}
|
||||
|
||||
CodeViewContext &MCContext::getCVContext() {
|
||||
if (!CVContext.get())
|
||||
CVContext.reset(new CodeViewContext);
|
||||
return *CVContext.get();
|
||||
}
|
||||
|
||||
unsigned MCContext::getCVFile(StringRef FileName, unsigned FileNumber) {
|
||||
return getCVContext().addFile(FileNumber, FileName) ? FileNumber : 0;
|
||||
}
|
||||
|
||||
bool MCContext::isValidCVFileNumber(unsigned FileNumber) {
|
||||
return getCVContext().isValidFileNumber(FileNumber);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Error Reporting
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -125,6 +125,7 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
|
||||
MCDataFragment *DF = getOrCreateDataFragment();
|
||||
flushPendingLabels(DF, DF->getContents().size());
|
||||
|
||||
MCCVLineEntry::Make(this);
|
||||
MCDwarfLineEntry::Make(this, getCurrentSection().first);
|
||||
|
||||
// Avoid fixups when possible.
|
||||
@ -232,6 +233,7 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst,
|
||||
|
||||
// Now that a machine instruction has been assembled into this section, make
|
||||
// a line entry for any .loc directive that has been seen.
|
||||
MCCVLineEntry::Make(this);
|
||||
MCDwarfLineEntry::Make(this, getCurrentSection().first);
|
||||
|
||||
// If this instruction doesn't need relaxation, just emit it as data.
|
||||
@ -362,7 +364,36 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
|
||||
insert(new MCDwarfCallFrameFragment(*AddrDelta));
|
||||
}
|
||||
|
||||
void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
|
||||
unsigned Line, unsigned Column,
|
||||
bool PrologueEnd, bool IsStmt,
|
||||
StringRef FileName) {
|
||||
// In case we see two .cv_loc directives in a row, make sure the
|
||||
// first one gets a line entry.
|
||||
MCCVLineEntry::Make(this);
|
||||
|
||||
this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column,
|
||||
PrologueEnd, IsStmt, FileName);
|
||||
}
|
||||
|
||||
void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
|
||||
const MCSymbol *Begin,
|
||||
const MCSymbol *End) {
|
||||
getContext().getCVContext().emitLineTableForFunction(*this, FunctionId, Begin,
|
||||
End);
|
||||
this->MCStreamer::EmitCVLinetableDirective(FunctionId, Begin, End);
|
||||
}
|
||||
|
||||
void MCObjectStreamer::EmitCVStringTableDirective() {
|
||||
getContext().getCVContext().emitStringTable(*this);
|
||||
}
|
||||
void MCObjectStreamer::EmitCVFileChecksumsDirective() {
|
||||
getContext().getCVContext().emitFileChecksums(*this);
|
||||
}
|
||||
|
||||
|
||||
void MCObjectStreamer::EmitBytes(StringRef Data) {
|
||||
MCCVLineEntry::Make(this);
|
||||
MCDwarfLineEntry::Make(this, getCurrentSection().first);
|
||||
MCDataFragment *DF = getOrCreateDataFragment();
|
||||
flushPendingLabels(DF, DF->getContents().size());
|
||||
|
@ -357,6 +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_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,
|
||||
@ -394,6 +396,13 @@ private:
|
||||
bool parseDirectiveLoc();
|
||||
bool parseDirectiveStabs();
|
||||
|
||||
// ".cv_file", ".cv_loc", ".cv_linetable"
|
||||
bool parseDirectiveCVFile();
|
||||
bool parseDirectiveCVLoc();
|
||||
bool parseDirectiveCVLinetable();
|
||||
bool parseDirectiveCVStringTable();
|
||||
bool parseDirectiveCVFileChecksums();
|
||||
|
||||
// .cfi directives
|
||||
bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
|
||||
bool parseDirectiveCFIWindowSave();
|
||||
@ -1638,6 +1647,16 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
|
||||
return parseDirectiveLoc();
|
||||
case DK_STABS:
|
||||
return parseDirectiveStabs();
|
||||
case DK_CV_FILE:
|
||||
return parseDirectiveCVFile();
|
||||
case DK_CV_LOC:
|
||||
return parseDirectiveCVLoc();
|
||||
case DK_CV_LINETABLE:
|
||||
return parseDirectiveCVLinetable();
|
||||
case DK_CV_STRINGTABLE:
|
||||
return parseDirectiveCVStringTable();
|
||||
case DK_CV_FILECHECKSUMS:
|
||||
return parseDirectiveCVFileChecksums();
|
||||
case DK_CFI_SECTIONS:
|
||||
return parseDirectiveCFISections();
|
||||
case DK_CFI_STARTPROC:
|
||||
@ -3070,6 +3089,156 @@ bool AsmParser::parseDirectiveStabs() {
|
||||
return TokError("unsupported directive '.stabs'");
|
||||
}
|
||||
|
||||
/// parseDirectiveCVFile
|
||||
/// ::= .cv_file number filename
|
||||
bool AsmParser::parseDirectiveCVFile() {
|
||||
SMLoc FileNumberLoc = getLexer().getLoc();
|
||||
if (getLexer().isNot(AsmToken::Integer))
|
||||
return TokError("expected file number in '.cv_file' directive");
|
||||
|
||||
int64_t FileNumber = getTok().getIntVal();
|
||||
Lex();
|
||||
|
||||
if (FileNumber < 1)
|
||||
return TokError("file number less than one");
|
||||
|
||||
if (getLexer().isNot(AsmToken::String))
|
||||
return TokError("unexpected token in '.cv_file' directive");
|
||||
|
||||
// Usually the directory and filename together, otherwise just the directory.
|
||||
// Allow the strings to have escaped octal character sequence.
|
||||
std::string Filename;
|
||||
if (parseEscapedString(Filename))
|
||||
return true;
|
||||
Lex();
|
||||
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement))
|
||||
return TokError("unexpected token in '.cv_file' directive");
|
||||
|
||||
if (getStreamer().EmitCVFileDirective(FileNumber, Filename) == 0)
|
||||
Error(FileNumberLoc, "file number already allocated");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDirectiveCVLoc
|
||||
/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]
|
||||
/// [is_stmt VALUE]
|
||||
/// The first number is a file number, must have been previously assigned with
|
||||
/// a .file directive, the second number is the line number and optionally the
|
||||
/// third number is a column position (zero if not specified). The remaining
|
||||
/// optional items are .loc sub-directives.
|
||||
bool AsmParser::parseDirectiveCVLoc() {
|
||||
if (getLexer().isNot(AsmToken::Integer))
|
||||
return TokError("unexpected token in '.cv_loc' directive");
|
||||
|
||||
int64_t FunctionId = getTok().getIntVal();
|
||||
if (FunctionId < 0)
|
||||
return TokError("function id less than zero in '.cv_loc' directive");
|
||||
Lex();
|
||||
|
||||
int64_t FileNumber = getTok().getIntVal();
|
||||
if (FileNumber < 1)
|
||||
return TokError("file number less than one in '.cv_loc' directive");
|
||||
if (!getContext().isValidCVFileNumber(FileNumber))
|
||||
return TokError("unassigned file number in '.cv_loc' directive");
|
||||
Lex();
|
||||
|
||||
int64_t LineNumber = 0;
|
||||
if (getLexer().is(AsmToken::Integer)) {
|
||||
LineNumber = getTok().getIntVal();
|
||||
if (LineNumber < 0)
|
||||
return TokError("line number less than zero in '.cv_loc' directive");
|
||||
Lex();
|
||||
}
|
||||
|
||||
int64_t ColumnPos = 0;
|
||||
if (getLexer().is(AsmToken::Integer)) {
|
||||
ColumnPos = getTok().getIntVal();
|
||||
if (ColumnPos < 0)
|
||||
return TokError("column position less than zero in '.cv_loc' directive");
|
||||
Lex();
|
||||
}
|
||||
|
||||
bool PrologueEnd = false;
|
||||
uint64_t IsStmt = 0;
|
||||
while (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
StringRef Name;
|
||||
SMLoc Loc = getTok().getLoc();
|
||||
if (parseIdentifier(Name))
|
||||
return TokError("unexpected token in '.cv_loc' directive");
|
||||
|
||||
if (Name == "prologue_end")
|
||||
PrologueEnd = true;
|
||||
else if (Name == "is_stmt") {
|
||||
Loc = getTok().getLoc();
|
||||
const MCExpr *Value;
|
||||
if (parseExpression(Value))
|
||||
return true;
|
||||
// The expression must be the constant 0 or 1.
|
||||
IsStmt = ~0ULL;
|
||||
if (const auto *MCE = dyn_cast<MCConstantExpr>(Value))
|
||||
IsStmt = MCE->getValue();
|
||||
|
||||
if (IsStmt > 1)
|
||||
return Error(Loc, "is_stmt value not 0 or 1");
|
||||
} else {
|
||||
return Error(Loc, "unknown sub-directive in '.cv_loc' directive");
|
||||
}
|
||||
}
|
||||
|
||||
getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber,
|
||||
ColumnPos, PrologueEnd, IsStmt, StringRef());
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDirectiveCVLinetable
|
||||
/// ::= .cv_linetable FunctionId, FnStart, FnEnd
|
||||
bool AsmParser::parseDirectiveCVLinetable() {
|
||||
int64_t FunctionId = getTok().getIntVal();
|
||||
if (FunctionId < 0)
|
||||
return TokError("function id less than zero in '.cv_linetable' directive");
|
||||
Lex();
|
||||
|
||||
if (Lexer.isNot(AsmToken::Comma))
|
||||
return TokError("unexpected token in '.cv_linetable' directive");
|
||||
Lex();
|
||||
|
||||
SMLoc Loc = getLexer().getLoc();
|
||||
StringRef FnStartName;
|
||||
if (parseIdentifier(FnStartName))
|
||||
return Error(Loc, "expected identifier in directive");
|
||||
|
||||
if (Lexer.isNot(AsmToken::Comma))
|
||||
return TokError("unexpected token in '.cv_linetable' directive");
|
||||
Lex();
|
||||
|
||||
Loc = getLexer().getLoc();
|
||||
StringRef FnEndName;
|
||||
if (parseIdentifier(FnEndName))
|
||||
return Error(Loc, "expected identifier in directive");
|
||||
|
||||
MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);
|
||||
MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
|
||||
|
||||
getStreamer().EmitCVLinetableDirective(FunctionId, FnStartSym, FnEndSym);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDirectiveCVStringTable
|
||||
/// ::= .cv_stringtable
|
||||
bool AsmParser::parseDirectiveCVStringTable() {
|
||||
getStreamer().EmitCVStringTableDirective();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDirectiveCVFileChecksums
|
||||
/// ::= .cv_filechecksums
|
||||
bool AsmParser::parseDirectiveCVFileChecksums() {
|
||||
getStreamer().EmitCVFileChecksumsDirective();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDirectiveCFISections
|
||||
/// ::= .cfi_sections section [, section]
|
||||
bool AsmParser::parseDirectiveCFISections() {
|
||||
@ -4381,6 +4550,11 @@ void AsmParser::initializeDirectiveKindMap() {
|
||||
DirectiveKindMap[".line"] = DK_LINE;
|
||||
DirectiveKindMap[".loc"] = DK_LOC;
|
||||
DirectiveKindMap[".stabs"] = DK_STABS;
|
||||
DirectiveKindMap[".cv_file"] = DK_CV_FILE;
|
||||
DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
|
||||
DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
|
||||
DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
|
||||
DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
|
||||
DirectiveKindMap[".sleb128"] = DK_SLEB128;
|
||||
DirectiveKindMap[".uleb128"] = DK_ULEB128;
|
||||
DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
|
||||
|
@ -180,6 +180,22 @@ void MCStreamer::EnsureValidDwarfFrame() {
|
||||
report_fatal_error("No open frame");
|
||||
}
|
||||
|
||||
unsigned MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) {
|
||||
return getContext().getCVFile(Filename, FileNo);
|
||||
}
|
||||
|
||||
void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
|
||||
unsigned Line, unsigned Column,
|
||||
bool PrologueEnd, bool IsStmt,
|
||||
StringRef FileName) {
|
||||
getContext().setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd,
|
||||
IsStmt);
|
||||
}
|
||||
|
||||
void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId,
|
||||
const MCSymbol *Begin,
|
||||
const MCSymbol *End) {}
|
||||
|
||||
void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
|
||||
MCSymbol *EHSymbol) {
|
||||
}
|
||||
|
@ -16,7 +16,22 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
StringTableBuilder::StringTableBuilder(Kind K) : K(K) {}
|
||||
StringTableBuilder::StringTableBuilder(Kind K) : K(K) {
|
||||
// Account for leading bytes in table so that offsets returned from add are
|
||||
// correct.
|
||||
switch (K) {
|
||||
case RAW:
|
||||
Size = 0;
|
||||
break;
|
||||
case MachO:
|
||||
case ELF:
|
||||
Size = 1;
|
||||
break;
|
||||
case WinCOFF:
|
||||
Size = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::pair<StringRef, size_t> StringPair;
|
||||
|
||||
@ -62,13 +77,32 @@ tailcall:
|
||||
}
|
||||
|
||||
void StringTableBuilder::finalize() {
|
||||
std::vector<std::pair<StringRef, size_t> *> Strings;
|
||||
finalizeStringTable(/*Optimize=*/true);
|
||||
}
|
||||
|
||||
void StringTableBuilder::finalizeInOrder() {
|
||||
finalizeStringTable(/*Optimize=*/false);
|
||||
}
|
||||
|
||||
void StringTableBuilder::finalizeStringTable(bool Optimize) {
|
||||
typedef std::pair<StringRef, size_t> StringOffsetPair;
|
||||
std::vector<StringOffsetPair *> Strings;
|
||||
Strings.reserve(StringIndexMap.size());
|
||||
for (std::pair<StringRef, size_t> &P : StringIndexMap)
|
||||
for (StringOffsetPair &P : StringIndexMap)
|
||||
Strings.push_back(&P);
|
||||
|
||||
if (!Strings.empty())
|
||||
multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
|
||||
if (!Strings.empty()) {
|
||||
// If we're optimizing, sort by name. If not, sort by previously assigned
|
||||
// offset.
|
||||
if (Optimize) {
|
||||
multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
|
||||
} else {
|
||||
std::sort(Strings.begin(), Strings.end(),
|
||||
[](const StringOffsetPair *LHS, const StringOffsetPair *RHS) {
|
||||
return LHS->second < RHS->second;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
switch (K) {
|
||||
case RAW:
|
||||
@ -85,17 +119,22 @@ void StringTableBuilder::finalize() {
|
||||
}
|
||||
|
||||
StringRef Previous;
|
||||
for (std::pair<StringRef, size_t> *P : Strings) {
|
||||
for (StringOffsetPair *P : Strings) {
|
||||
StringRef S = P->first;
|
||||
if (K == WinCOFF)
|
||||
assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
|
||||
|
||||
if (Previous.endswith(S)) {
|
||||
if (Optimize && Previous.endswith(S)) {
|
||||
P->second = StringTable.size() - S.size() - (K != RAW);
|
||||
continue;
|
||||
}
|
||||
|
||||
P->second = StringTable.size();
|
||||
if (Optimize)
|
||||
P->second = StringTable.size();
|
||||
else
|
||||
assert(P->second == StringTable.size() &&
|
||||
"different strtab offset after finalization");
|
||||
|
||||
StringTable += S;
|
||||
if (K != RAW)
|
||||
StringTable += '\x00';
|
||||
|
@ -13,11 +13,11 @@
|
||||
; 6 }
|
||||
|
||||
; X86-LABEL: _f:
|
||||
; X86: # BB
|
||||
; X86-NEXT: [[ASM_LINE:^L.*]]:{{$}}
|
||||
; X86: [[CALL_LINE:^L.*]]:{{$}}
|
||||
; X86: .cv_file 1 "D:\\asm.c"
|
||||
; X86: .cv_loc 0 1 4 0 is_stmt 0
|
||||
; X86: .cv_loc 0 1 5 0
|
||||
; X86: calll _g
|
||||
; X86-NEXT: [[RETURN_STMT:.*]]:
|
||||
; X86: .cv_loc 0 1 6 0
|
||||
; X86: ret
|
||||
; X86-NEXT: [[END_OF_F:^L.*]]:
|
||||
;
|
||||
@ -45,48 +45,15 @@
|
||||
; Padding
|
||||
; X86-NEXT: .zero 3
|
||||
; Line table
|
||||
; X86-NEXT: .long 242
|
||||
; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X86-NEXT: [[F2_START]]:
|
||||
; X86-NEXT: .secrel32 _f
|
||||
; X86-NEXT: .secidx _f
|
||||
; X86-NEXT: .short 1
|
||||
; X86-NEXT: .long [[END_OF_F]]-_f
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 3
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[ASM_LINE]]-_f
|
||||
; X86-NEXT: .long -2147483644
|
||||
; X86-NEXT: .long [[CALL_LINE]]-_f
|
||||
; X86-NEXT: .long -2147483643
|
||||
; X86-NEXT: .long [[RETURN_STMT]]-_f
|
||||
; X86-NEXT: .long -2147483642
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X86-NEXT: [[F2_END]]:
|
||||
; X86-NEXT: .cv_linetable 0, _f, [[END_OF_F]]
|
||||
; File index to string table offset subsection
|
||||
; X86-NEXT: .long 244
|
||||
; X86-NEXT: .long 8
|
||||
; X86-NEXT: .long 1
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .cv_filechecksums
|
||||
; String table
|
||||
; X86-NEXT: .long 243
|
||||
; X86-NEXT: .long 10
|
||||
; X86-NEXT: .byte 0
|
||||
; X86-NEXT: .ascii "D:\\asm.c"
|
||||
; X86-NEXT: .byte 0
|
||||
; Padding
|
||||
; X86-NEXT: .zero 2
|
||||
; X86-NEXT: .cv_stringtable
|
||||
|
||||
; OBJ32: Section {
|
||||
; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ32: Characteristics [ (0x42100040)
|
||||
; OBJ32: Characteristics [ (0x42300040)
|
||||
; OBJ32: ]
|
||||
; OBJ32: Relocations [
|
||||
; OBJ32-NEXT: 0x2C IMAGE_REL_I386_SECREL _f
|
||||
@ -107,7 +74,7 @@
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32: FunctionLineTable [
|
||||
; OBJ32-NEXT: Name: _f
|
||||
; OBJ32-NEXT: Flags: 0x1
|
||||
; OBJ32-NEXT: Flags: 0x0
|
||||
; OBJ32-NEXT: CodeSize: 0x6
|
||||
; OBJ32-NEXT: FilenameSegment [
|
||||
; OBJ32-NEXT: Filename: D:\asm.c
|
||||
@ -118,34 +85,27 @@
|
||||
; OBJ32-NEXT: LineNumberStart: 4
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: +0x0 [
|
||||
; OBJ32-NEXT: LineNumberStart: 5
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: +0x5 [
|
||||
; OBJ32-NEXT: LineNumberStart: 6
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: ]
|
||||
|
||||
; X64-LABEL: f:
|
||||
; X64-NEXT: .L{{.*}}:{{$}}
|
||||
; X64-NEXT: [[START:.*]]:{{$}}
|
||||
; X64: # BB
|
||||
; X64: .cv_file 1 "D:\\asm.c"
|
||||
; X64: .cv_loc 0 1 3 0 is_stmt 0
|
||||
; X64: subq $40, %rsp
|
||||
; X64-NEXT: [[ASM_LINE:.*]]:{{$}}
|
||||
; X64: [[CALL_LINE:.*]]:{{$}}
|
||||
; X64: .cv_loc 0 1 4 0
|
||||
; X64: .cv_loc 0 1 5 0
|
||||
; X64: callq g
|
||||
; X64-NEXT: [[EPILOG_AND_RET:.*]]:
|
||||
; X64: .cv_loc 0 1 6 0
|
||||
; X64: addq $40, %rsp
|
||||
; X64-NEXT: ret
|
||||
; X64-NEXT: [[END_OF_F:.*]]:
|
||||
@ -174,52 +134,15 @@
|
||||
; Padding
|
||||
; X64-NEXT: .zero 3
|
||||
; Line table
|
||||
; X64-NEXT: .long 242
|
||||
; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X64-NEXT: [[F2_START]]:
|
||||
; X64-NEXT: .secrel32 f
|
||||
; X64-NEXT: .secidx f
|
||||
; X64-NEXT: .short 1
|
||||
; X64-NEXT: .long [[END_OF_F]]-f
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 4
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[START]]-f
|
||||
; X64-NEXT: .long -2147483645
|
||||
; X64-NEXT: .long [[ASM_LINE]]-f
|
||||
; X64-NEXT: .long -2147483644
|
||||
; X64-NEXT: .long [[CALL_LINE]]-f
|
||||
; X64-NEXT: .long -2147483643
|
||||
; X64-NEXT: .long [[EPILOG_AND_RET]]-f
|
||||
; X64-NEXT: .long -2147483642
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X64-NEXT: [[F2_END]]:
|
||||
; X64-NEXT: .cv_linetable 0, f, [[END_OF_F]]
|
||||
; File index to string table offset subsection
|
||||
; X64-NEXT: .long 244
|
||||
; X64-NEXT: .long 8
|
||||
; X64-NEXT: .long 1
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .cv_filechecksums
|
||||
; String table
|
||||
; X64-NEXT: .long 243
|
||||
; X64-NEXT: .long 10
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .ascii "D:\\asm.c"
|
||||
; X64-NEXT: .byte 0
|
||||
; Padding
|
||||
; X64-NEXT: .zero 2
|
||||
; X64-NEXT: .cv_stringtable
|
||||
|
||||
; OBJ64: Section {
|
||||
; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ64: Characteristics [ (0x42100040)
|
||||
; OBJ64: Characteristics [ (0x42300040)
|
||||
; OBJ64: ]
|
||||
; OBJ64: Relocations [
|
||||
; OBJ64-NEXT: 0x2C IMAGE_REL_AMD64_SECREL f
|
||||
@ -239,7 +162,7 @@
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64: FunctionLineTable [
|
||||
; OBJ64-NEXT: Name: f
|
||||
; OBJ64-NEXT: Flags: 0x1
|
||||
; OBJ64-NEXT: Flags: 0x0
|
||||
; OBJ64-NEXT: CodeSize: 0xE
|
||||
; OBJ64-NEXT: FilenameSegment [
|
||||
; OBJ64-NEXT: Filename: D:\asm.c
|
||||
@ -249,29 +172,21 @@
|
||||
; OBJ64-NEXT: LineNumberStart: 3
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: +0x4 [
|
||||
; OBJ64-NEXT: LineNumberStart: 4
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: +0x4 [
|
||||
; OBJ64-NEXT: LineNumberStart: 5
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: +0x9 [
|
||||
; OBJ64-NEXT: LineNumberStart: 6
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: ]
|
||||
|
@ -18,13 +18,15 @@
|
||||
|
||||
; X86-LABEL: _f:
|
||||
; X86: # BB
|
||||
; X86-NEXT: [[CALL_LINE_1:.*]]:{{$}}
|
||||
; X86: .cv_file 1 "D:\\one.c"
|
||||
; X86: .cv_loc 0 1 1 0 is_stmt 0 # one.c:1:0
|
||||
; X86: calll _g
|
||||
; X86-NEXT: [[CALL_LINE_2:.*]]:{{$}}
|
||||
; X86: .cv_file 2 "D:\\two.c"
|
||||
; X86: .cv_loc 0 2 2 0 # two.c:2:0
|
||||
; X86: calll _g
|
||||
; X86-NEXT: [[CALL_LINE_3:.*]]:{{$}}
|
||||
; X86: .cv_loc 0 1 7 0 # one.c:7:0
|
||||
; X86: calll _g
|
||||
; X86-NEXT: [[RETURN_STMT:.*]]:
|
||||
; X86: .cv_loc 0 1 8 0 # one.c:8:0
|
||||
; X86: ret
|
||||
; X86-NEXT: [[END_OF_F:.*]]:
|
||||
;
|
||||
@ -52,68 +54,15 @@
|
||||
; Padding
|
||||
; X86-NEXT: .zero 3
|
||||
; Line table
|
||||
; X86-NEXT: .long 242
|
||||
; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X86-NEXT: [[F2_START]]:
|
||||
; X86-NEXT: .secrel32 _f
|
||||
; X86-NEXT: .secidx _f
|
||||
; X86-NEXT: .short 1
|
||||
; X86-NEXT: .long [[END_OF_F]]-_f
|
||||
; Segment for file 'D:\\one.c' begins
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 1
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[CALL_LINE_1]]-_f
|
||||
; X86-NEXT: .long -2147483647
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; Segment for file 'D:\\two.c' begins
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 8
|
||||
; X86-NEXT: .long 1
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[CALL_LINE_2]]-_f
|
||||
; X86-NEXT: .long -2147483646
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; A new segment for file 'D:\\one.c' begins
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 2
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[CALL_LINE_3]]-_f
|
||||
; X86-NEXT: .long -2147483641
|
||||
; X86-NEXT: .long [[RETURN_STMT]]-_f
|
||||
; X86-NEXT: .long -2147483640
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X86-NEXT: [[F2_END]]:
|
||||
; X86-NEXT: .cv_linetable 0, _f, [[END_OF_F]]
|
||||
; File index to string table offset subsection
|
||||
; X86-NEXT: .long 244
|
||||
; X86-NEXT: .long 16
|
||||
; X86-NEXT: .long 1
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 10
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .cv_filechecksums
|
||||
; String table
|
||||
; X86-NEXT: .long 243
|
||||
; X86-NEXT: .long 19
|
||||
; X86-NEXT: .byte 0
|
||||
; X86-NEXT: .ascii "D:\\one.c"
|
||||
; X86-NEXT: .byte 0
|
||||
; X86-NEXT: .ascii "D:\\two.c"
|
||||
; X86-NEXT: .byte 0
|
||||
; X86-NEXT: .zero 1
|
||||
; X86-NEXT: .cv_stringtable
|
||||
|
||||
; OBJ32: Section {
|
||||
; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ32: Characteristics [ (0x42100040)
|
||||
; OBJ32: Characteristics [ (0x42300040)
|
||||
; OBJ32: ]
|
||||
; OBJ32: Relocations [
|
||||
; OBJ32-NEXT: 0x2C IMAGE_REL_I386_SECREL _f
|
||||
@ -133,7 +82,7 @@
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32: FunctionLineTable [
|
||||
; OBJ32-NEXT: Name: _f
|
||||
; OBJ32-NEXT: Flags: 0x1
|
||||
; OBJ32-NEXT: Flags: 0x0
|
||||
; OBJ32-NEXT: CodeSize: 0x10
|
||||
; OBJ32-NEXT: FilenameSegment [
|
||||
; OBJ32-NEXT: Filename: D:\one.c
|
||||
@ -141,8 +90,6 @@
|
||||
; OBJ32-NEXT: LineNumberStart: 1
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: FilenameSegment [
|
||||
@ -151,8 +98,6 @@
|
||||
; OBJ32-NEXT: LineNumberStart: 2
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: FilenameSegment [
|
||||
@ -161,31 +106,30 @@
|
||||
; OBJ32-NEXT: LineNumberStart: 7
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: +0xF [
|
||||
; OBJ32-NEXT: LineNumberStart: 8
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: ]
|
||||
|
||||
; X64-LABEL: f:
|
||||
; X64-NEXT: .L{{.*}}:{{$}}
|
||||
; X64-NEXT: [[START:.*]]:{{$}}
|
||||
; X64: .cv_file 1 "D:\\input.c"
|
||||
; X64: .cv_loc 0 1 3 0 is_stmt 0 # input.c:3:0
|
||||
; X64: # BB
|
||||
; X64: subq $40, %rsp
|
||||
; X64-NEXT: [[CALL_LINE_1:.*]]:{{$}}
|
||||
; X64: .cv_file 2 "D:\\one.c"
|
||||
; X64: .cv_loc 0 2 1 0 # one.c:1:0
|
||||
; X64: callq g
|
||||
; X64-NEXT: [[CALL_LINE_2:.*]]:{{$}}
|
||||
; X64: .cv_file 3 "D:\\two.c"
|
||||
; X64: .cv_loc 0 3 2 0 # two.c:2:0
|
||||
; X64: callq g
|
||||
; X64-NEXT: [[CALL_LINE_3:.*]]:{{$}}
|
||||
; X64: .cv_loc 0 2 7 0 # one.c:7:0
|
||||
; X64: callq g
|
||||
; X64-NEXT: [[EPILOG_AND_RET:.*]]:
|
||||
; X64: .cv_loc 0 2 8 0 # one.c:8:0
|
||||
; X64: addq $40, %rsp
|
||||
; X64-NEXT: ret
|
||||
; X64-NEXT: [[END_OF_F:.*]]:
|
||||
@ -213,83 +157,13 @@
|
||||
; X64-NEXT: [[F1_END]]:
|
||||
; Padding
|
||||
; X64-NEXT: .zero 3
|
||||
; Line table
|
||||
; X64-NEXT: .long 242
|
||||
; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X64-NEXT: [[F2_START]]:
|
||||
; X64-NEXT: .secrel32 f
|
||||
; X64-NEXT: .secidx f
|
||||
; X64-NEXT: .short 1
|
||||
; X64-NEXT: .long [[END_OF_F]]-f
|
||||
; Segment for file 'D:\\input.c' begins
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 1
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[START]]-f
|
||||
; X64-NEXT: .long -2147483645
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; Segment for file 'D:\\one.c' begins
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 8
|
||||
; X64-NEXT: .long 1
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[CALL_LINE_1]]-f
|
||||
; X64-NEXT: .long -2147483647
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; Segment for file 'D:\\two.c' begins
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 16
|
||||
; X64-NEXT: .long 1
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[CALL_LINE_2]]-f
|
||||
; X64-NEXT: .long -2147483646
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; A new segment for file 'D:\\one.c' begins
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 8
|
||||
; X64-NEXT: .long 2
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[CALL_LINE_3]]-f
|
||||
; X64-NEXT: .long -2147483641
|
||||
; X64-NEXT: .long [[EPILOG_AND_RET]]-f
|
||||
; X64-NEXT: .long -2147483640
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X64-NEXT: [[F2_END]]:
|
||||
; File index to string table offset subsection
|
||||
; X64-NEXT: .long 244
|
||||
; X64-NEXT: .long 24
|
||||
; X64-NEXT: .long 1
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 12
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 21
|
||||
; X64-NEXT: .long 0
|
||||
; String table
|
||||
; X64-NEXT: .long 243
|
||||
; X64-NEXT: .long 30
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .ascii "D:\\input.c"
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .ascii "D:\\one.c"
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .ascii "D:\\two.c"
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .zero 2
|
||||
; X64: .cv_linetable 0, f, [[END_OF_F]]
|
||||
; X64: .cv_filechecksums
|
||||
; X64: .cv_stringtable
|
||||
|
||||
; OBJ64: Section {
|
||||
; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ64: Characteristics [ (0x42100040)
|
||||
; OBJ64: Characteristics [ (0x42300040)
|
||||
; OBJ64: ]
|
||||
; OBJ64: Relocations [
|
||||
; OBJ64-NEXT: 0x2C IMAGE_REL_AMD64_SECREL f
|
||||
@ -309,7 +183,7 @@
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64: FunctionLineTable [
|
||||
; OBJ64-NEXT: Name: f
|
||||
; OBJ64-NEXT: Flags: 0x1
|
||||
; OBJ64-NEXT: Flags: 0x0
|
||||
; OBJ64-NEXT: CodeSize: 0x18
|
||||
; OBJ64-NEXT: FilenameSegment [
|
||||
; OBJ64-NEXT: Filename: D:\input.c
|
||||
@ -317,8 +191,6 @@
|
||||
; OBJ64-NEXT: LineNumberStart: 3
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: FilenameSegment [
|
||||
@ -327,8 +199,6 @@
|
||||
; OBJ64-NEXT: LineNumberStart: 1
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: FilenameSegment [
|
||||
@ -337,8 +207,6 @@
|
||||
; OBJ64-NEXT: LineNumberStart: 2
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: FilenameSegment [
|
||||
@ -347,15 +215,11 @@
|
||||
; OBJ64-NEXT: LineNumberStart: 7
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: +0x13 [
|
||||
; OBJ64-NEXT: LineNumberStart: 8
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: ]
|
||||
|
@ -24,29 +24,30 @@
|
||||
|
||||
; X86-LABEL: _x:
|
||||
; X86: # BB
|
||||
; X86-NEXT: [[X_CALL:.*]]:{{$}}
|
||||
; X86: .cv_file 1 "D:\\source.c"
|
||||
; X86: .cv_loc 0 1 4 42 is_stmt 0 # source.c:4:42
|
||||
; X86: calll _z
|
||||
; X86-NEXT: [[X_RETURN:.*]]:
|
||||
; X86: .cv_loc 0 1 5 43 # source.c:5:43
|
||||
; X86: ret
|
||||
; X86-NEXT: [[END_OF_X:.*]]:
|
||||
;
|
||||
; X86-LABEL: _y:
|
||||
; X86: # BB
|
||||
; X86-NEXT: [[Y_CALL:.*]]:{{$}}
|
||||
; X86: .cv_loc 1 1 8 52 # source.c:8:52
|
||||
; X86: calll _z
|
||||
; X86-NEXT: [[Y_RETURN:.*]]:
|
||||
; X86: .cv_loc 1 1 9 53 # source.c:9:53
|
||||
; X86: ret
|
||||
; X86-NEXT: [[END_OF_Y:.*]]:
|
||||
;
|
||||
; X86-LABEL: _f:
|
||||
; X86: # BB
|
||||
; X86-NEXT: [[F_CALLS_X:.*]]:{{$}}
|
||||
; X86: .cv_loc 2 1 12 62 # source.c:12:62
|
||||
; X86: calll _x
|
||||
; X86-NEXT: [[F_CALLS_Y:.*]]:
|
||||
; X86: .cv_loc 2 1 13 63 # source.c:13:63
|
||||
; X86: calll _y
|
||||
; X86-NEXT: [[F_CALLS_Z:.*]]:
|
||||
; X86: .cv_loc 2 1 14 72 # source.c:14:72
|
||||
; X86: calll _z
|
||||
; X86-NEXT: [[F_RETURN:.*]]:
|
||||
; X86: .cv_loc 2 1 15 73 # source.c:15:73
|
||||
; X86: ret
|
||||
; X86-NEXT: [[END_OF_F:.*]]:
|
||||
;
|
||||
@ -74,27 +75,7 @@
|
||||
; Padding
|
||||
; X86-NEXT: .zero 3
|
||||
; Line table subsection for x
|
||||
; X86-NEXT: .long 242
|
||||
; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X86-NEXT: [[F2_START]]:
|
||||
; X86-NEXT: .secrel32 _x
|
||||
; X86-NEXT: .secidx _x
|
||||
; X86-NEXT: .short 1
|
||||
; X86-NEXT: .long [[END_OF_X]]-_x
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 2
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[X_CALL]]-_x
|
||||
; X86-NEXT: .long -2147483644
|
||||
; X86-NEXT: .long [[X_RETURN]]-_x
|
||||
; X86-NEXT: .long -2147483643
|
||||
; X86-NEXT: .short 42
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 43
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X86-NEXT: [[F2_END]]:
|
||||
; X86: .cv_linetable 0, _x, [[END_OF_X]]
|
||||
; Symbol subsection for y
|
||||
; X86-NEXT: .long 241
|
||||
; X86-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]]
|
||||
@ -117,27 +98,7 @@
|
||||
; Padding
|
||||
; X86-NEXT: .zero 3
|
||||
; Line table subsection for y
|
||||
; X86-NEXT: .long 242
|
||||
; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X86-NEXT: [[F2_START]]:
|
||||
; X86-NEXT: .secrel32 _y
|
||||
; X86-NEXT: .secidx _y
|
||||
; X86-NEXT: .short 1
|
||||
; X86-NEXT: .long [[END_OF_Y]]-_y
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 2
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[Y_CALL]]-_y
|
||||
; X86-NEXT: .long -2147483640
|
||||
; X86-NEXT: .long [[Y_RETURN]]-_y
|
||||
; X86-NEXT: .long -2147483639
|
||||
; X86-NEXT: .short 52
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 53
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X86-NEXT: [[F2_END]]:
|
||||
; X86: .cv_linetable 1, _y, [[END_OF_Y]]
|
||||
; Symbol subsection for f
|
||||
; X86-NEXT: .long 241
|
||||
; X86-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]]
|
||||
@ -160,51 +121,13 @@
|
||||
; Padding
|
||||
; X86-NEXT: .zero 3
|
||||
; Line table subsection for f
|
||||
; X86-NEXT: .long 242
|
||||
; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X86-NEXT: [[F2_START]]:
|
||||
; X86-NEXT: .secrel32 _f
|
||||
; X86-NEXT: .secidx _f
|
||||
; X86-NEXT: .short 1
|
||||
; X86-NEXT: .long [[END_OF_F]]-_f
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 4
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[F_CALLS_X]]-_f
|
||||
; X86-NEXT: .long -2147483636
|
||||
; X86-NEXT: .long [[F_CALLS_Y]]-_f
|
||||
; X86-NEXT: .long -2147483635
|
||||
; X86-NEXT: .long [[F_CALLS_Z]]-_f
|
||||
; X86-NEXT: .long -2147483634
|
||||
; X86-NEXT: .long [[F_RETURN]]-_f
|
||||
; X86-NEXT: .long -2147483633
|
||||
; X86-NEXT: .short 62
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 63
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 72
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 73
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X86-NEXT: [[F2_END]]:
|
||||
; File index to string table offset subsection
|
||||
; X86-NEXT: .long 244
|
||||
; X86-NEXT: .long 8
|
||||
; X86-NEXT: .long 1
|
||||
; X86-NEXT: .long 0
|
||||
; String table
|
||||
; X86-NEXT: .long 243
|
||||
; X86-NEXT: .long 13
|
||||
; X86-NEXT: .byte 0
|
||||
; X86-NEXT: .ascii "D:\\source.c"
|
||||
; X86-NEXT: .byte 0
|
||||
; X86-NEXT: .zero 3
|
||||
; X86: .cv_linetable 2, _f, [[END_OF_F]]
|
||||
; X86: .cv_filechecksums
|
||||
; X86: .cv_stringtable
|
||||
|
||||
; OBJ32: Section {
|
||||
; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ32: Characteristics [ (0x42100040)
|
||||
; OBJ32: Characteristics [ (0x42300040)
|
||||
; OBJ32: ]
|
||||
; OBJ32: Relocations [
|
||||
; OBJ32-NEXT: 0x2C IMAGE_REL_I386_SECREL _x
|
||||
@ -343,40 +266,41 @@
|
||||
|
||||
; X64-LABEL: x:
|
||||
; X64-NEXT: .L{{.*}}:
|
||||
; X64-NEXT: [[X_START:.*]]:{{$}}
|
||||
; X64: .cv_file 1 "D:\\source.c"
|
||||
; X64: .cv_loc 0 1 3 0 is_stmt 0 # source.c:3:0
|
||||
; X64: # BB
|
||||
; X64: subq $40, %rsp
|
||||
; X64-NEXT: [[X_CALL_LINE:.*]]:{{$}}
|
||||
; X64: .cv_loc 0 1 4 42 # source.c:4:42
|
||||
; X64-NEXT: callq z
|
||||
; X64-NEXT: [[X_EPILOG_AND_RET:.*]]:
|
||||
; X64: .cv_loc 0 1 5 43 # source.c:5:43
|
||||
; X64: addq $40, %rsp
|
||||
; X64-NEXT: ret
|
||||
; X64-NEXT: [[END_OF_X:.*]]:
|
||||
;
|
||||
; X64-LABEL: y:
|
||||
; X64-NEXT: .L{{.*}}:
|
||||
; X64-NEXT: [[Y_START:.*]]:{{$}}
|
||||
; X64: .cv_loc 1 1 7 0 # source.c:7:0
|
||||
; X64: # BB
|
||||
; X64: subq $40, %rsp
|
||||
; X64-NEXT: [[Y_CALL_LINE:.*]]:{{$}}
|
||||
; X64: .cv_loc 1 1 8 52 # source.c:8:52
|
||||
; X64-NEXT: callq z
|
||||
; X64-NEXT: [[Y_EPILOG_AND_RET:.*]]:
|
||||
; X64: .cv_loc 1 1 9 53 # source.c:9:53
|
||||
; X64: addq $40, %rsp
|
||||
; X64-NEXT: ret
|
||||
; X64-NEXT: [[END_OF_Y:.*]]:
|
||||
;
|
||||
; X64-LABEL: f:
|
||||
; X64-NEXT: .L{{.*}}:
|
||||
; X64-NEXT: [[F_START:.*]]:{{$}}
|
||||
; X64: .cv_loc 2 1 11 0 # source.c:11:0
|
||||
; X64: # BB
|
||||
; X64: subq $40, %rsp
|
||||
; X64-NEXT: [[F_CALLS_X:.*]]:{{$}}
|
||||
; X64: .cv_loc 2 1 12 62 # source.c:12:62
|
||||
; X64-NEXT: callq x
|
||||
; X64-NEXT: [[F_CALLS_Y:.*]]:
|
||||
; X64: .cv_loc 2 1 13 63 # source.c:13:63
|
||||
; X64: callq y
|
||||
; X64-NEXT: [[F_CALLS_Z:.*]]:
|
||||
; X64: .cv_loc 2 1 14 72 # source.c:14:72
|
||||
; X64: callq z
|
||||
; X64-NEXT: [[F_EPILOG_AND_RET:.*]]:
|
||||
; X64: .cv_loc 2 1 15 73 # source.c:15:73
|
||||
; X64: addq $40, %rsp
|
||||
; X64-NEXT: ret
|
||||
; X64-NEXT: [[END_OF_F:.*]]:
|
||||
@ -405,31 +329,7 @@
|
||||
; Padding
|
||||
; X64-NEXT: .zero 3
|
||||
; Line table subsection for x
|
||||
; X64-NEXT: .long 242
|
||||
; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X64-NEXT: [[F2_START]]:
|
||||
; X64-NEXT: .secrel32 x
|
||||
; X64-NEXT: .secidx x
|
||||
; X64-NEXT: .short 1
|
||||
; X64-NEXT: .long [[END_OF_X]]-x
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 3
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[X_START]]-x
|
||||
; X64-NEXT: .long -2147483645
|
||||
; X64-NEXT: .long [[X_CALL_LINE]]-x
|
||||
; X64-NEXT: .long -2147483644
|
||||
; X64-NEXT: .long [[X_EPILOG_AND_RET]]-x
|
||||
; X64-NEXT: .long -2147483643
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 42
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 43
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X64-NEXT: [[F2_END]]:
|
||||
; X64: .cv_linetable 0, x, [[END_OF_X]]
|
||||
; Symbol subsection for y
|
||||
; X64-NEXT: .long 241
|
||||
; X64-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]]
|
||||
@ -452,31 +352,7 @@
|
||||
; Padding
|
||||
; X64-NEXT: .zero 3
|
||||
; Line table subsection for y
|
||||
; X64-NEXT: .long 242
|
||||
; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X64-NEXT: [[F2_START]]:
|
||||
; X64-NEXT: .secrel32 y
|
||||
; X64-NEXT: .secidx y
|
||||
; X64-NEXT: .short 1
|
||||
; X64-NEXT: .long [[END_OF_Y]]-y
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 3
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[Y_START]]-y
|
||||
; X64-NEXT: .long -2147483641
|
||||
; X64-NEXT: .long [[Y_CALL_LINE]]-y
|
||||
; X64-NEXT: .long -2147483640
|
||||
; X64-NEXT: .long [[Y_EPILOG_AND_RET]]-y
|
||||
; X64-NEXT: .long -2147483639
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 52
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 53
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X64-NEXT: [[F2_END]]:
|
||||
; X64: .cv_linetable 1, y, [[END_OF_Y]]
|
||||
; Symbol subsection for f
|
||||
; X64-NEXT: .long 241
|
||||
; X64-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]]
|
||||
@ -499,55 +375,15 @@
|
||||
; Padding
|
||||
; X64-NEXT: .zero 3
|
||||
; Line table subsection for f
|
||||
; X64-NEXT: .long 242
|
||||
; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X64-NEXT: [[F2_START]]:
|
||||
; X64-NEXT: .secrel32 f
|
||||
; X64-NEXT: .secidx f
|
||||
; X64-NEXT: .short 1
|
||||
; X64-NEXT: .long [[END_OF_F]]-f
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 5
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[F_START]]-f
|
||||
; X64-NEXT: .long -2147483637
|
||||
; X64-NEXT: .long [[F_CALLS_X]]-f
|
||||
; X64-NEXT: .long -2147483636
|
||||
; X64-NEXT: .long [[F_CALLS_Y]]-f
|
||||
; X64-NEXT: .long -2147483635
|
||||
; X64-NEXT: .long [[F_CALLS_Z]]-f
|
||||
; X64-NEXT: .long -2147483634
|
||||
; X64-NEXT: .long [[F_EPILOG_AND_RET]]-f
|
||||
; X64-NEXT: .long -2147483633
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 62
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 63
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 72
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 73
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X64-NEXT: [[F2_END]]:
|
||||
; X64: .cv_linetable 2, f, [[END_OF_F]]
|
||||
; File index to string table offset subsection
|
||||
; X64-NEXT: .long 244
|
||||
; X64-NEXT: .long 8
|
||||
; X64-NEXT: .long 1
|
||||
; X64-NEXT: .long 0
|
||||
; X64: .cv_filechecksums
|
||||
; String table
|
||||
; X64-NEXT: .long 243
|
||||
; X64-NEXT: .long 13
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .ascii "D:\\source.c"
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .zero 3
|
||||
; X64: .cv_stringtable
|
||||
|
||||
; OBJ64: Section {
|
||||
; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ64: Characteristics [ (0x42100040)
|
||||
; OBJ64: Characteristics [ (0x42300040)
|
||||
; OBJ64: ]
|
||||
; OBJ64: Relocations [
|
||||
; OBJ64-NEXT: 0x2C IMAGE_REL_AMD64_SECREL x
|
||||
|
@ -13,9 +13,10 @@
|
||||
|
||||
; X86-LABEL: _f:
|
||||
; X86: # BB
|
||||
; X86-NEXT: [[CALL_LINE:^L.*]]:{{$}}
|
||||
; X86: .cv_file 1 "D:\\test.c"
|
||||
; X86: .cv_loc 0 1 4 2 is_stmt 0 # test.c:4:2
|
||||
; X86: calll _g
|
||||
; X86-NEXT: [[RETURN_STMT:.*]]:
|
||||
; X86: .cv_loc 0 1 5 0 # test.c:5:0
|
||||
; X86: ret
|
||||
; X86-NEXT: [[END_OF_F:.*]]:
|
||||
;
|
||||
@ -43,44 +44,15 @@
|
||||
; Padding
|
||||
; X86-NEXT: .zero 3
|
||||
; Line table
|
||||
; X86-NEXT: .long 242
|
||||
; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X86-NEXT: [[F2_START]]:
|
||||
; X86-NEXT: .secrel32 _f
|
||||
; X86-NEXT: .secidx _f
|
||||
; X86-NEXT: .short 1
|
||||
; X86-NEXT: .long [[END_OF_F]]-_f
|
||||
; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .long 2
|
||||
; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X86-NEXT: .long [[CALL_LINE]]-_f
|
||||
; X86-NEXT: .long -2147483644
|
||||
; X86-NEXT: .long [[RETURN_STMT]]-_f
|
||||
; X86-NEXT: .long -2147483643
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: .short 0
|
||||
; X86-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X86-NEXT: [[F2_END]]:
|
||||
; X86-NEXT: .cv_linetable 0, _f, [[END_OF_F]]
|
||||
; File index to string table offset subsection
|
||||
; X86-NEXT: .long 244
|
||||
; X86-NEXT: .long 8
|
||||
; X86-NEXT: .long 1
|
||||
; X86-NEXT: .long 0
|
||||
; X86-NEXT: .cv_filechecksums
|
||||
; String table
|
||||
; X86-NEXT: .long 243
|
||||
; X86-NEXT: .long 11
|
||||
; X86-NEXT: .byte 0
|
||||
; X86-NEXT: .ascii "D:\\test.c"
|
||||
; X86-NEXT: .byte 0
|
||||
; Padding
|
||||
; X86-NEXT: .zero 1
|
||||
; X86-NEXT: .cv_stringtable
|
||||
|
||||
; OBJ32: Section {
|
||||
; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ32: Characteristics [ (0x42100040)
|
||||
; OBJ32: Characteristics [ (0x42300040)
|
||||
; OBJ32: ]
|
||||
; OBJ32: Relocations [
|
||||
; OBJ32-NEXT: 0x2C IMAGE_REL_I386_SECREL _f
|
||||
@ -108,7 +80,7 @@
|
||||
; OBJ32-NEXT: LineNumberStart: 4
|
||||
; OBJ32-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ32-NEXT: IsStatement: Yes
|
||||
; OBJ32-NEXT: ColStart: 0
|
||||
; OBJ32-NEXT: ColStart: 2
|
||||
; OBJ32-NEXT: ColEnd: 0
|
||||
; OBJ32-NEXT: ]
|
||||
; OBJ32-NEXT: +0x5 [
|
||||
@ -123,12 +95,13 @@
|
||||
|
||||
; X64-LABEL: f:
|
||||
; X64-NEXT: .L{{.*}}:{{$}}
|
||||
; X64-NEXT: [[START:.*]]:{{$}}
|
||||
; X64: .cv_file 1 "D:\\test.c"
|
||||
; X64: .cv_loc 0 1 3 0 is_stmt 0 # test.c:3:0
|
||||
; X64: # BB
|
||||
; X64: subq $40, %rsp
|
||||
; X64-NEXT: [[CALL_LINE:.*]]:{{$}}
|
||||
; X64: .cv_loc 0 1 4 2 # test.c:4:2
|
||||
; X64-NEXT: callq g
|
||||
; X64-NEXT: [[EPILOG_AND_RET:.*]]:
|
||||
; X64: .cv_loc 0 1 5 0 # test.c:5:0
|
||||
; X64: addq $40, %rsp
|
||||
; X64-NEXT: ret
|
||||
; X64-NEXT: [[END_OF_F:.*]]:
|
||||
@ -157,48 +130,15 @@
|
||||
; Padding
|
||||
; X64-NEXT: .zero 3
|
||||
; Line table
|
||||
; X64-NEXT: .long 242
|
||||
; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
|
||||
; X64-NEXT: [[F2_START]]:
|
||||
; X64-NEXT: .secrel32 f
|
||||
; X64-NEXT: .secidx f
|
||||
; X64-NEXT: .short 1
|
||||
; X64-NEXT: .long [[END_OF_F]]-f
|
||||
; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .long 3
|
||||
; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
|
||||
; X64-NEXT: .long [[START]]-f
|
||||
; X64-NEXT: .long -2147483645
|
||||
; X64-NEXT: .long [[CALL_LINE]]-f
|
||||
; X64-NEXT: .long -2147483644
|
||||
; X64-NEXT: .long [[EPILOG_AND_RET]]-f
|
||||
; X64-NEXT: .long -2147483643
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: .short 0
|
||||
; X64-NEXT: [[FILE_SEGMENT_END]]:
|
||||
; X64-NEXT: [[F2_END]]:
|
||||
; X64-NEXT: .cv_linetable 0, f, [[END_OF_F]]
|
||||
; File index to string table offset subsection
|
||||
; X64-NEXT: .long 244
|
||||
; X64-NEXT: .long 8
|
||||
; X64-NEXT: .long 1
|
||||
; X64-NEXT: .long 0
|
||||
; X64-NEXT: .cv_filechecksums
|
||||
; String table
|
||||
; X64-NEXT: .long 243
|
||||
; X64-NEXT: .long 11
|
||||
; X64-NEXT: .byte 0
|
||||
; X64-NEXT: .ascii "D:\\test.c"
|
||||
; X64-NEXT: .byte 0
|
||||
; Padding
|
||||
; X64-NEXT: .zero 1
|
||||
; X64-NEXT: .cv_stringtable
|
||||
|
||||
; OBJ64: Section {
|
||||
; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
|
||||
; OBJ64: Characteristics [ (0x42100040)
|
||||
; OBJ64: Characteristics [ (0x42300040)
|
||||
; OBJ64: ]
|
||||
; OBJ64: Relocations [
|
||||
; OBJ64-NEXT: 0x2C IMAGE_REL_AMD64_SECREL f
|
||||
@ -233,7 +173,7 @@
|
||||
; OBJ64-NEXT: LineNumberStart: 4
|
||||
; OBJ64-NEXT: LineNumberEndDelta: 0
|
||||
; OBJ64-NEXT: IsStatement: Yes
|
||||
; OBJ64-NEXT: ColStart: 0
|
||||
; OBJ64-NEXT: ColStart: 2
|
||||
; OBJ64-NEXT: ColEnd: 0
|
||||
; OBJ64-NEXT: ]
|
||||
; OBJ64-NEXT: +0x9 [
|
||||
@ -274,5 +214,5 @@ attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "
|
||||
!9 = !{i32 2, !"CodeView", i32 1}
|
||||
!10 = !{i32 1, !"Debug Info Version", i32 3}
|
||||
!11 = !{!"clang version 3.5 "}
|
||||
!12 = !DILocation(line: 4, scope: !4)
|
||||
!12 = !DILocation(line: 4, column: 2, scope: !4)
|
||||
!13 = !DILocation(line: 5, scope: !4)
|
||||
|
@ -15,10 +15,10 @@
|
||||
; The bar function happens to have no lexical scopes, yet it has one instruction
|
||||
; with debug information available. This used to be PR19239.
|
||||
|
||||
; X86: .cv_file 1 "D:\\test.cpp"
|
||||
|
||||
; X86-LABEL: {{^}}"?bar@@YAXHZZ":
|
||||
; X86-NEXT: L{{.*}}:
|
||||
; X86-NEXT: # BB
|
||||
; X86-NEXT: [[JMP_LINE:^L.*]]:{{$}}
|
||||
; X86: .cv_loc 1 1 4 0
|
||||
; X86: jmp "?foo@@YAXXZ"
|
||||
; X86-NEXT: [[END_OF_BAR:^L.*]]:{{$}}
|
||||
; X86-NOT: ret
|
||||
@ -26,13 +26,9 @@
|
||||
; X86-LABEL: .section .debug$S,"dr"
|
||||
; X86: .secrel32 "?bar@@YAXHZZ"
|
||||
; X86-NEXT: .secidx "?bar@@YAXHZZ"
|
||||
; X86: .long 0
|
||||
; X86-NEXT: .long 1
|
||||
; X86-NEXT: .long {{.*}}
|
||||
; X86-NEXT: .long [[JMP_LINE]]-"?bar@@YAXHZZ"
|
||||
; X86-NEXT: .long -2147483644
|
||||
|
||||
; X86-LABEL: .long 244
|
||||
; X86: .cv_linetable 1, "?bar@@YAXHZZ", [[END_OF_BAR]]
|
||||
; X86: .cv_filechecksums
|
||||
; X86: .cv_stringtable
|
||||
|
||||
; ModuleID = 'test.cpp'
|
||||
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
|
||||
|
85
test/MC/COFF/cv-loc.s
Normal file
85
test/MC/COFF/cv-loc.s
Normal file
@ -0,0 +1,85 @@
|
||||
# RUN: llvm-mc < %s -triple=x86_64-pc-win32 -filetype=obj | llvm-readobj - -codeview | FileCheck %s
|
||||
|
||||
.section .debug$S
|
||||
.long 4
|
||||
.cv_stringtable
|
||||
|
||||
.cv_file 1 "a.c"
|
||||
.cv_file 2 "t.inc"
|
||||
|
||||
# Implements this C:
|
||||
# void f(volatile int *x) {
|
||||
# ++*x;
|
||||
# #include "t.h" // contains two ++*x; statements
|
||||
# ++*x;
|
||||
# }
|
||||
|
||||
.text
|
||||
.def f;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.text
|
||||
.globl f
|
||||
.align 16, 0x90
|
||||
f:
|
||||
.Lfunc_begin0:
|
||||
.cv_loc 0 1 5 2
|
||||
incl (%rdi)
|
||||
# #include "t.h" start
|
||||
.cv_loc 0 2 0 0
|
||||
incl (%rdi)
|
||||
.cv_loc 0 2 1 0
|
||||
incl (%rdi)
|
||||
# #include "t.h" end
|
||||
.cv_loc 0 1 6 2
|
||||
incl (%rdi)
|
||||
retq
|
||||
.Lfunc_end0:
|
||||
|
||||
.section .debug$S
|
||||
.cv_filechecksums
|
||||
.cv_linetable 0, f, .Lfunc_end0
|
||||
|
||||
# CHECK: FunctionLineTable [
|
||||
# CHECK: LinkageName: f
|
||||
# CHECK: Flags: 0x1
|
||||
# CHECK: CodeSize: 0x9
|
||||
# CHECK: FilenameSegment [
|
||||
# CHECK: Filename: a.c (0x0)
|
||||
# CHECK: +0x0 [
|
||||
# CHECK: LineNumberStart: 5
|
||||
# CHECK: LineNumberEndDelta: 0
|
||||
# CHECK: IsStatement: Yes
|
||||
# CHECK: ColStart: 2
|
||||
# CHECK: ColEnd: 0
|
||||
# CHECK: ]
|
||||
# CHECK: ]
|
||||
# CHECK: FilenameSegment [
|
||||
# CHECK: Filename: t.inc (0x8)
|
||||
# CHECK: +0x2 [
|
||||
# CHECK: LineNumberStart: 0
|
||||
# CHECK: LineNumberEndDelta: 0
|
||||
# CHECK: IsStatement: Yes
|
||||
# CHECK: ColStart: 0
|
||||
# CHECK: ColEnd: 0
|
||||
# CHECK: ]
|
||||
# CHECK: +0x4 [
|
||||
# CHECK: LineNumberStart: 1
|
||||
# CHECK: LineNumberEndDelta: 0
|
||||
# CHECK: IsStatement: Yes
|
||||
# CHECK: ColStart: 0
|
||||
# CHECK: ColEnd: 0
|
||||
# CHECK: ]
|
||||
# CHECK: ]
|
||||
# CHECK: FilenameSegment [
|
||||
# CHECK: Filename: a.c (0x0)
|
||||
# CHECK: +0x6 [
|
||||
# CHECK: LineNumberStart: 6
|
||||
# CHECK: LineNumberEndDelta: 0
|
||||
# CHECK: IsStatement: Yes
|
||||
# CHECK: ColStart: 2
|
||||
# CHECK: ColEnd: 0
|
||||
# CHECK: ]
|
||||
# CHECK: ]
|
||||
# CHECK: ]
|
@ -1116,8 +1116,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
|
||||
uint32_t Offset = 6; // Skip relocations.
|
||||
uint16_t Flags = DE.getU16(&Offset);
|
||||
W.printHex("Flags", Flags);
|
||||
bool HasColumnInformation =
|
||||
Flags & COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS;
|
||||
bool HasColumnInformation = Flags & codeview::LineFlags::HaveColumns;
|
||||
uint32_t FunctionSize = DE.getU32(&Offset);
|
||||
W.printHex("CodeSize", FunctionSize);
|
||||
while (DE.isValidOffset(Offset)) {
|
||||
@ -1151,11 +1150,11 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
|
||||
char Buffer[32];
|
||||
format("+0x%X", PC).snprint(Buffer, 32);
|
||||
ListScope PCScope(W, Buffer);
|
||||
uint32_t LineNumberStart = LineData & COFF::CVL_MaxLineNumber;
|
||||
uint32_t LineNumberStart = LineData & codeview::LineInfo::StartLineMask;
|
||||
uint32_t LineNumberEndDelta =
|
||||
(LineData >> COFF::CVL_LineNumberStartBits) &
|
||||
COFF::CVL_LineNumberEndDeltaMask;
|
||||
bool IsStatement = LineData & COFF::CVL_IsStatement;
|
||||
(LineData & codeview::LineInfo::EndLineDeltaMask) >>
|
||||
codeview::LineInfo::EndLineDeltaShift;
|
||||
bool IsStatement = codeview::LineInfo::StatementFlag;
|
||||
W.printNumber("LineNumberStart", LineNumberStart);
|
||||
W.printNumber("LineNumberEndDelta", LineNumberEndDelta);
|
||||
W.printBoolean("IsStatement", IsStatement);
|
||||
|
@ -68,4 +68,27 @@ TEST(StringTableBuilderTest, BasicWinCOFF) {
|
||||
EXPECT_EQ(23U, B.getOffset("river horse"));
|
||||
}
|
||||
|
||||
TEST(StringTableBuilderTest, ELFInOrder) {
|
||||
StringTableBuilder B(StringTableBuilder::ELF);
|
||||
EXPECT_EQ(1U, B.add("foo"));
|
||||
EXPECT_EQ(5U, B.add("bar"));
|
||||
EXPECT_EQ(9U, B.add("foobar"));
|
||||
|
||||
B.finalizeInOrder();
|
||||
|
||||
std::string Expected;
|
||||
Expected += '\x00';
|
||||
Expected += "foo";
|
||||
Expected += '\x00';
|
||||
Expected += "bar";
|
||||
Expected += '\x00';
|
||||
Expected += "foobar";
|
||||
Expected += '\x00';
|
||||
|
||||
EXPECT_EQ(Expected, B.data());
|
||||
EXPECT_EQ(1U, B.getOffset("foo"));
|
||||
EXPECT_EQ(5U, B.getOffset("bar"));
|
||||
EXPECT_EQ(9U, B.getOffset("foobar"));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user