Skip to content

[MC] Add .loc_label instruction #99710

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions llvm/include/llvm/MC/MCDwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,23 @@ class MCDwarfLineEntry : public MCDwarfLoc {

public:
// Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc.
MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc)
: MCDwarfLoc(loc), Label(label) {}
MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc,
MCSymbol *lineStreamLabel = nullptr,
SMLoc streamLabelDefLoc = {})
: MCDwarfLoc(loc), Label(label), LineStreamLabel(lineStreamLabel),
StreamLabelDefLoc(streamLabelDefLoc) {}

MCSymbol *getLabel() const { return Label; }

// This is the label that is to be emitted into the line stream. If this is
// non-null and we need to emit a label, also make sure to restart the current
// line sequence.
MCSymbol *LineStreamLabel;

// Location where LineStreamLabel was defined. If there is an error emitting
// LineStreamLabel, we can use the SMLoc to report an error.
SMLoc StreamLabelDefLoc;

// This indicates the line entry is synthesized for an end entry.
bool IsEndEntry = false;

Expand Down Expand Up @@ -365,6 +377,9 @@ class MCDwarfLineTable {
emitOne(MCStreamer *MCOS, MCSection *Section,
const MCLineSection::MCDwarfLineEntryCollection &LineEntries);

void endCurrentSeqAndEmitLineStreamLabel(MCStreamer *MCOS, SMLoc DefLoc,
StringRef Name);

Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
std::optional<MD5::MD5Result> Checksum,
std::optional<StringRef> Source,
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/MC/MCObjectStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ class MCObjectStreamer : public MCStreamer {
void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,
const MCSymbol *Label,
unsigned PointerSize) override;
void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) override;
void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel,
MCSymbol *EndLabel = nullptr) override;
void emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
const MCSymbol *Label, SMLoc Loc);
void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
Expand Down
6 changes: 5 additions & 1 deletion llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,9 @@ class MCStreamer {
unsigned Isa, unsigned Discriminator,
StringRef FileName);

/// This implements the '.loc_label Name' directive.
virtual void emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name);

/// Associate a filename with a specified logical file number, and also
/// specify that file's checksum information. This implements the '.cv_file 4
/// "foo.c"' assembler directive. Returns true on success.
Expand Down Expand Up @@ -1119,7 +1122,8 @@ class MCStreamer {
virtual void emitDwarfLineStartLabel(MCSymbol *StartSym);

/// Emit the debug line end entry.
virtual void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) {}
virtual void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel,
MCSymbol *EndLabel = nullptr) {}

/// If targets does not support representing debug line section by .loc/.file
/// directives in assembly output, we need to populate debug line section with
Expand Down
19 changes: 15 additions & 4 deletions llvm/lib/MC/MCAsmStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ class MCAsmStreamer final : public MCStreamer {
unsigned Flags, unsigned Isa,
unsigned Discriminator,
StringRef FileName) override;
virtual void emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) override;

MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;

bool emitCVFileDirective(unsigned FileNo, StringRef Filename,
Expand Down Expand Up @@ -429,7 +431,8 @@ class MCAsmStreamer final : public MCStreamer {

void emitDwarfLineStartLabel(MCSymbol *StartSym) override;

void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) override;
void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel,
MCSymbol *EndLabel = nullptr) override;

void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,
const MCSymbol *Label,
Expand Down Expand Up @@ -1767,6 +1770,12 @@ void MCAsmStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
Discriminator, FileName);
}

void MCAsmStreamer::emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) {
MCStreamer::emitDwarfLocLabelDirective(Loc, Name);
OS << ".loc_label\t" << Name;
EmitEOL();
}

MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
// Always use the zeroth line table, since asm syntax only supports one line
// table for now.
Expand Down Expand Up @@ -2579,7 +2588,8 @@ void MCAsmStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) {
}

void MCAsmStreamer::emitDwarfLineEndEntry(MCSection *Section,
MCSymbol *LastLabel) {
MCSymbol *LastLabel,
MCSymbol *EndLabel) {
// If the targets write the raw debug line data for assembly output (We can
// not switch to Section and add the end symbol there for assembly output)
// we currently use the .text end label as any section end. This will not
Expand All @@ -2596,9 +2606,10 @@ void MCAsmStreamer::emitDwarfLineEndEntry(MCSection *Section,
MCSection *TextSection = Ctx.getObjectFileInfo()->getTextSection();
assert(TextSection->hasEnded() && ".text section is not end!");

MCSymbol *SectionEnd = TextSection->getEndSymbol(Ctx);
if (!EndLabel)
EndLabel = TextSection->getEndSymbol(Ctx);
const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, EndLabel,
AsmInfo->getCodePointerSize());
}

Expand Down
32 changes: 31 additions & 1 deletion llvm/lib/MC/MCDwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ void MCDwarfLineTable::emitOne(
const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {

unsigned FileNum, LastLine, Column, Flags, Isa, Discriminator;
bool IsAtStartSeq;
MCSymbol *LastLabel;
auto init = [&]() {
FileNum = 1;
Expand All @@ -181,6 +182,7 @@ void MCDwarfLineTable::emitOne(
Isa = 0;
Discriminator = 0;
LastLabel = nullptr;
IsAtStartSeq = true;
};
init();

Expand All @@ -189,6 +191,17 @@ void MCDwarfLineTable::emitOne(
for (const MCDwarfLineEntry &LineEntry : LineEntries) {
MCSymbol *Label = LineEntry.getLabel();
const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo();

if (LineEntry.LineStreamLabel) {
if (!IsAtStartSeq) {
MCOS->emitDwarfLineEndEntry(Section, LastLabel,
/*EndLabel =*/LastLabel);
init();
}
MCOS->emitLabel(LineEntry.LineStreamLabel, LineEntry.StreamLabelDefLoc);
continue;
}

if (LineEntry.IsEndEntry) {
MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, Label,
asmInfo->getCodePointerSize());
Expand Down Expand Up @@ -243,17 +256,34 @@ void MCDwarfLineTable::emitOne(
Discriminator = 0;
LastLine = LineEntry.getLine();
LastLabel = Label;
IsAtStartSeq = false;
}

// Generate DWARF line end entry.
// We do not need this for DwarfDebug that explicitly terminates the line
// table using ranges whenever CU or section changes. However, the MC path
// does not track ranges nor terminate the line table. In that case,
// conservatively use the section end symbol to end the line table.
if (!EndEntryEmitted)
if (!EndEntryEmitted && !IsAtStartSeq)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage: the test doesn't fail if I remove && !IsAtStartSeq

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added coverage.

MCOS->emitDwarfLineEndEntry(Section, LastLabel);
}

void MCDwarfLineTable::endCurrentSeqAndEmitLineStreamLabel(MCStreamer *MCOS,
SMLoc DefLoc,
StringRef Name) {
auto &ctx = MCOS->getContext();
auto *LineStreamLabel = ctx.getOrCreateSymbol(Name);
auto *LineSym = ctx.createTempSymbol();
MCOS->emitLabel(LineSym);
const MCDwarfLoc &DwarfLoc = ctx.getCurrentDwarfLoc();

// Create a 'fake' line entry by having LineStreamLabel be non-null. This
// won't actually emit any line information, it will reset the line table
// sequence and emit a label at the start of the new line table sequence.
MCDwarfLineEntry LineEntry(LineSym, DwarfLoc, LineStreamLabel, DefLoc);
getMCLineSections().addLineEntry(LineEntry, MCOS->getCurrentSectionOnly());
}

//
// This emits the Dwarf file and the line tables.
//
Expand Down
16 changes: 10 additions & 6 deletions llvm/lib/MC/MCObjectStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,20 +467,24 @@ void MCObjectStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
}

void MCObjectStreamer::emitDwarfLineEndEntry(MCSection *Section,
MCSymbol *LastLabel) {
// Emit a DW_LNE_end_sequence for the end of the section.
// Use the section end label to compute the address delta and use INT64_MAX
// as the line delta which is the signal that this is actually a
MCSymbol *LastLabel,
MCSymbol *EndLabel) {
// Emit a DW_LNE_end_sequence into the line table. When EndLabel is null, it
// means we should emit the entry for the end of the section and therefore we
// use the section end label for the reference label. After having the
// appropriate reference label, we emit the address delta and use INT64_MAX as
// the line delta which is the signal that this is actually a
// DW_LNE_end_sequence.
MCSymbol *SectionEnd = endSection(Section);
if (!EndLabel)
EndLabel = endSection(Section);

// Switch back the dwarf line section, in case endSection had to switch the
// section.
MCContext &Ctx = getContext();
switchSection(Ctx.getObjectFileInfo()->getDwarfLineSection());

const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, EndLabel,
AsmInfo->getCodePointerSize());
}

Expand Down
20 changes: 19 additions & 1 deletion llvm/lib/MC/MCParser/AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ class AsmParser : public MCAsmParser {
DK_FILE,
DK_LINE,
DK_LOC,
DK_LOC_LABEL,
DK_STABS,
DK_CV_FILE,
DK_CV_FUNC_ID,
Expand Down Expand Up @@ -580,10 +581,11 @@ class AsmParser : public MCAsmParser {
// ".align{,32}", ".p2align{,w,l}"
bool parseDirectiveAlign(bool IsPow2, unsigned ValueSize);

// ".file", ".line", ".loc", ".stabs"
// ".file", ".line", ".loc", ".loc_label", ".stabs"
bool parseDirectiveFile(SMLoc DirectiveLoc);
bool parseDirectiveLine();
bool parseDirectiveLoc();
bool parseDirectiveLocLabel(SMLoc DirectiveLoc);
bool parseDirectiveStabs();

// ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable",
Expand Down Expand Up @@ -2156,6 +2158,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveLine();
case DK_LOC:
return parseDirectiveLoc();
case DK_LOC_LABEL:
return parseDirectiveLocLabel(IDLoc);
case DK_STABS:
return parseDirectiveStabs();
case DK_CV_FILE:
Expand Down Expand Up @@ -3733,6 +3737,19 @@ bool AsmParser::parseDirectiveLoc() {
return false;
}

/// parseDirectiveLoc
/// ::= .loc_label label
bool AsmParser::parseDirectiveLocLabel(SMLoc DirectiveLoc) {
StringRef Name;
DirectiveLoc = Lexer.getLoc();
if (parseIdentifier(Name))
return TokError("expected identifier");
if (parseEOL())
return true;
getStreamer().emitDwarfLocLabelDirective(DirectiveLoc, Name);
return false;
}

/// parseDirectiveStabs
/// ::= .stabs string, number, number, number
bool AsmParser::parseDirectiveStabs() {
Expand Down Expand Up @@ -5541,6 +5558,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".file"] = DK_FILE;
DirectiveKindMap[".line"] = DK_LINE;
DirectiveKindMap[".loc"] = DK_LOC;
DirectiveKindMap[".loc_label"] = DK_LOC_LABEL;
DirectiveKindMap[".stabs"] = DK_STABS;
DirectiveKindMap[".cv_file"] = DK_CV_FILE;
DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ void MCStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
Discriminator);
}

void MCStreamer::emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) {
getContext()
.getMCDwarfLineTable(getContext().getDwarfCompileUnitID())
.endCurrentSeqAndEmitLineStreamLabel(this, Loc, Name);
}

MCSymbol *MCStreamer::getDwarfLineTableSymbol(unsigned CUID) {
MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);
if (!Table.getLabel()) {
Expand Down
101 changes: 101 additions & 0 deletions llvm/test/MC/ELF/debug-loc-label.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Verify that the .loc_label instruction resets the line sequence and generates
// the requested label at the correct position in the line stream

// RUN: llvm-mc -filetype obj -triple x86_64 %s -o %t.o
// RUN: llvm-dwarfdump -v --debug-line %t.o | FileCheck %s --check-prefix=CHECK-LINE-TABLE
// RUN: llvm-readelf -s %t.o | FileCheck %s --check-prefix=CHECK-SYM
// RUN: llvm-objdump -s -j .offsets %t.o | FileCheck %s --check-prefix=CHECK-OFFSETS

// RUN: not llvm-mc -filetype obj -triple x86_64 --defsym ERR=1 %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
// RUN: not llvm-mc -filetype obj -triple x86_64 --defsym ERR2=1 %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2 --implicit-check-not=error:



# CHECK-LINE-TABLE: Address Line Column File ISA Discriminator OpIndex Flags
# CHECK-LINE-TABLE-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
# CHECK-LINE-TABLE-NEXT: 0x00000028: 05 DW_LNS_set_column (1)
# CHECK-LINE-TABLE-NEXT: 0x0000002a: 00 DW_LNE_set_address (0x0000000000000000)
# CHECK-LINE-TABLE-NEXT: 0x00000035: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000000 1 1 1 0 0 0 is_stmt
# CHECK-LINE-TABLE-NEXT: 0x00000036: 00 DW_LNE_end_sequence
# CHECK-LINE-TABLE-NEXT: 0x0000000000000000 1 1 1 0 0 0 is_stmt end_sequence
# CHECK-LINE-TABLE-NEXT: 0x00000039: 05 DW_LNS_set_column (2)
# CHECK-LINE-TABLE-NEXT: 0x0000003b: 00 DW_LNE_set_address (0x0000000000000008)
# CHECK-LINE-TABLE-NEXT: 0x00000046: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000008 1 2 1 0 0 0 is_stmt
# CHECK-LINE-TABLE-NEXT: 0x00000047: 00 DW_LNE_end_sequence
# CHECK-LINE-TABLE-NEXT: 0x0000000000000008 1 2 1 0 0 0 is_stmt end_sequence
# CHECK-LINE-TABLE-NEXT: 0x0000004a: 05 DW_LNS_set_column (3)
# CHECK-LINE-TABLE-NEXT: 0x0000004c: 00 DW_LNE_set_address (0x0000000000000010)
# CHECK-LINE-TABLE-NEXT: 0x00000057: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000010 1 3 1 0 0 0 is_stmt
# CHECK-LINE-TABLE-NEXT: 0x00000058: 00 DW_LNE_end_sequence
# CHECK-LINE-TABLE-NEXT: 0x0000000000000010 1 3 1 0 0 0 is_stmt end_sequence
# CHECK-LINE-TABLE-NEXT: 0x0000005b: 05 DW_LNS_set_column (4)
# CHECK-LINE-TABLE-NEXT: 0x0000005d: 00 DW_LNE_set_address (0x0000000000000018)
# CHECK-LINE-TABLE-NEXT: 0x00000068: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000018 1 4 1 0 0 0 is_stmt
# CHECK-LINE-TABLE-NEXT: 0x00000069: 05 DW_LNS_set_column (5)
# CHECK-LINE-TABLE-NEXT: 0x0000006b: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000018 1 5 1 0 0 0 is_stmt
# CHECK-LINE-TABLE-NEXT: 0x0000006c: 00 DW_LNE_end_sequence
# CHECK-LINE-TABLE-NEXT: 0x0000000000000018 1 5 1 0 0 0 is_stmt end_sequence

# CHECK-SYM: Symbol table '.symtab' contains 9 entries:
# CHECK-SYM-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-SYM-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
# CHECK-SYM-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c
# CHECK-SYM-NEXT: 2: 0000000000000000 0 SECTION LOCAL DEFAULT 2 .text
# CHECK-SYM-NEXT: 3: 0000000000000039 0 NOTYPE LOCAL DEFAULT 3 my_label_02
# CHECK-SYM-NEXT: 4: 000000000000004a 0 NOTYPE LOCAL DEFAULT 3 my_label_03
# CHECK-SYM-NEXT: 5: 000000000000005b 0 NOTYPE LOCAL DEFAULT 3 my_label_04
# CHECK-SYM-NEXT: 6: 000000000000004a 0 NOTYPE LOCAL DEFAULT 3 my_label_03.1
# CHECK-SYM-NEXT: 7: 000000000000006f 0 NOTYPE LOCAL DEFAULT 3 my_label_05
# CHECK-SYM-NEXT: 8: 0000000000000000 0 FUNC GLOBAL DEFAULT 2 foo

# CHECK-OFFSETS: 0000 39000000 4a000000 5b000000

.text
.file "test.c"
.globl foo
.align 16, 0x90
.type foo,@function
foo:
.Lfunc_begin0:
.file 1 "test.c"
.cfi_startproc
.loc 1 1 1
mov %rax, 0x01
.loc_label my_label_02
.loc 1 1 2
mov %rax, 0x02
.loc 1 1 3
.loc_label my_label_03
.loc_label my_label_03.1
mov %rax, 0x03
.loc 1 1 4
.loc_label my_label_04
.loc 1 1 5
.ifdef ERR
.loc_label my_label_04
# ERR: [[#@LINE+1]]:13: error: expected identifier
.loc_label
# ERR: [[#@LINE+1]]:19: error: expected newline
.loc_label aaaa bbbb
.endif
.ifdef ERR2
# ERR2: [[#@LINE+1]]:14: error: symbol 'my_label_04' is already defined
.loc_label my_label_04
.endif
mov %rax, 0x04
.loc_label my_label_05
ret
.cfi_endproc

.section .debug_line,"",@progbits
.Lline_table_start0:

.section .offsets,"",@progbits
.long my_label_02-.Lline_table_start0
.long my_label_03-.Lline_table_start0
.long my_label_04-.Lline_table_start0
Loading