mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
Reland "[CodeView] Use assembler directives for line tables"
This reverts commit r259126 and relands r259117. This time with updated library dependencies. llvm-svn: 259130
This commit is contained in:
parent
7db00a0614
commit
52a5e5edf7
@ -21,16 +21,19 @@ 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 };
|
||||
|
||||
enum : uint32_t {
|
||||
StartLineMask = 0x00ffffff,
|
||||
EndLineDeltaMask = 0x7f000000,
|
||||
StatementFlag = 0x80000000u
|
||||
};
|
||||
|
||||
public:
|
||||
LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement);
|
||||
|
||||
uint32_t getStartLine() const { return LineData & StartLineMask; }
|
||||
@ -151,6 +154,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);
|
||||
|
@ -19,4 +19,4 @@
|
||||
type = Library
|
||||
name = AsmPrinter
|
||||
parent = Libraries
|
||||
required_libraries = Analysis CodeGen Core MC MCParser Support Target TransformUtils
|
||||
required_libraries = Analysis CodeGen Core DebugInfoCodeView MC MCParser Support Target TransformUtils
|
||||
|
@ -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 ? int(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