Skip to content

Commit 27033cc

Browse files
authored
Fix line table lookups in line tables with multiple lines with the sa… (#70879)
Fix line table lookups in line tables with multiple lines with the same address. Compilers emit line tables that have multiple line table entries with the same address. When doing lookups, we always need to use the last line entry if a lookup address matches the address of one or more line entries. This is because the size of an address range for a line uses the next line entry to figure out how big the current line entry is. If the next line entry has the same address, that means the current line entry has a size of zero, so no bytes correspond to the line entry. This patch ensures that lookups will always pick the last matching line entry when the lookup address matches more than one line entry.
1 parent d6b69a1 commit 27033cc

File tree

2 files changed

+169
-5
lines changed

2 files changed

+169
-5
lines changed

llvm/lib/DebugInfo/GSYM/LineTable.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,6 @@ Expected<LineEntry> LineTable::lookup(DataExtractor &Data, uint64_t BaseAddr, ui
270270
if (Addr < Row.Addr)
271271
return false; // Stop parsing, result contains the line table row!
272272
Result = Row;
273-
if (Addr == Row.Addr) {
274-
// Stop parsing, this is the row we are looking for since the address
275-
// matches.
276-
return false;
277-
}
278273
return true; // Keep parsing till we find the right row.
279274
});
280275
if (Err)

llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4156,3 +4156,172 @@ TEST(GSYMTest, TestEmptyLinkageName) {
41564156
// Make sure we don't see spurious errors in the output:
41574157
EXPECT_TRUE(errors.find("error:") == std::string::npos);
41584158
}
4159+
4160+
TEST(GSYMTest, TestLineTablesWithEmptyRanges) {
4161+
// Test that lookups find the right line table entry when there are multiple
4162+
// line entries with the same address. When we have multiple line table
4163+
// entries with the same address, we need to pick the last one in the line
4164+
// table. We do this because a line entry's start address in the defined by
4165+
// the line table entry's address and the size is determined by the
4166+
// subtracting the next line table's address. If the current line table
4167+
// entry's address is the same as the next one, then there is no code
4168+
// assiciated with the current line table entry and it should be ignored.
4169+
//
4170+
// 0x0000000b: DW_TAG_compile_unit
4171+
// DW_AT_name ("/tmp/main.cpp")
4172+
// DW_AT_language (DW_LANG_C)
4173+
// DW_AT_stmt_list (0x00000000)
4174+
//
4175+
// 0x00000015: DW_TAG_subprogram
4176+
// DW_AT_name ("foo")
4177+
// DW_AT_low_pc (0x0000000000001000)
4178+
// DW_AT_high_pc (0x0000000000001050)
4179+
//
4180+
// 0x0000002a: NULL
4181+
//
4182+
// The line table has a duplicate entry at 0x1010:
4183+
//
4184+
// Address Line Column File ISA Discriminator Flags
4185+
// ---------- ------ ------ ------ --- ------------- -------------
4186+
// 0x00001000 10 0 1 0 0 is_stmt
4187+
// 0x00001010 11 0 1 0 0 is_stmt
4188+
// 0x00001010 12 0 1 0 0 is_stmt
4189+
// 0x00001050 13 0 1 0 0 is_stmt end_sequence
4190+
4191+
StringRef yamldata = R"(
4192+
debug_str:
4193+
- ''
4194+
- '/tmp/main.cpp'
4195+
- foo
4196+
debug_abbrev:
4197+
- ID: 0
4198+
Table:
4199+
- Code: 0x1
4200+
Tag: DW_TAG_compile_unit
4201+
Children: DW_CHILDREN_yes
4202+
Attributes:
4203+
- Attribute: DW_AT_name
4204+
Form: DW_FORM_strp
4205+
- Attribute: DW_AT_language
4206+
Form: DW_FORM_udata
4207+
- Attribute: DW_AT_stmt_list
4208+
Form: DW_FORM_sec_offset
4209+
- Code: 0x2
4210+
Tag: DW_TAG_subprogram
4211+
Children: DW_CHILDREN_no
4212+
Attributes:
4213+
- Attribute: DW_AT_name
4214+
Form: DW_FORM_strp
4215+
- Attribute: DW_AT_low_pc
4216+
Form: DW_FORM_addr
4217+
- Attribute: DW_AT_high_pc
4218+
Form: DW_FORM_addr
4219+
debug_info:
4220+
- Length: 0x27
4221+
Version: 4
4222+
AbbrevTableID: 0
4223+
AbbrOffset: 0x0
4224+
AddrSize: 8
4225+
Entries:
4226+
- AbbrCode: 0x1
4227+
Values:
4228+
- Value: 0x1
4229+
- Value: 0x2
4230+
- Value: 0x0
4231+
- AbbrCode: 0x2
4232+
Values:
4233+
- Value: 0xF
4234+
- Value: 0x1000
4235+
- Value: 0x1050
4236+
- AbbrCode: 0x0
4237+
debug_line:
4238+
- Length: 71
4239+
Version: 2
4240+
PrologueLength: 36
4241+
MinInstLength: 1
4242+
DefaultIsStmt: 1
4243+
LineBase: 251
4244+
LineRange: 14
4245+
OpcodeBase: 13
4246+
StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
4247+
IncludeDirs:
4248+
- '/tmp'
4249+
Files:
4250+
- Name: main.cpp
4251+
DirIdx: 1
4252+
ModTime: 0
4253+
Length: 0
4254+
Opcodes:
4255+
- Opcode: DW_LNS_extended_op
4256+
ExtLen: 9
4257+
SubOpcode: DW_LNE_set_address
4258+
Data: 4096
4259+
- Opcode: DW_LNS_advance_line
4260+
SData: 9
4261+
Data: 0
4262+
- Opcode: DW_LNS_copy
4263+
Data: 0
4264+
- Opcode: DW_LNS_advance_pc
4265+
Data: 16
4266+
- Opcode: DW_LNS_advance_line
4267+
SData: 1
4268+
Data: 0
4269+
- Opcode: DW_LNS_copy
4270+
Data: 0
4271+
- Opcode: DW_LNS_advance_line
4272+
SData: 1
4273+
Data: 0
4274+
- Opcode: DW_LNS_copy
4275+
Data: 0
4276+
- Opcode: DW_LNS_advance_pc
4277+
Data: 64
4278+
- Opcode: DW_LNS_advance_line
4279+
SData: 1
4280+
Data: 0
4281+
- Opcode: DW_LNS_extended_op
4282+
ExtLen: 1
4283+
SubOpcode: DW_LNE_end_sequence
4284+
Data: 0
4285+
)";
4286+
auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
4287+
ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
4288+
std::unique_ptr<DWARFContext> DwarfContext =
4289+
DWARFContext::create(*ErrOrSections, 8);
4290+
ASSERT_TRUE(DwarfContext.get() != nullptr);
4291+
std::string errors;
4292+
raw_string_ostream OS(errors);
4293+
GsymCreator GC;
4294+
DwarfTransformer DT(*DwarfContext, GC);
4295+
const uint32_t ThreadCount = 1;
4296+
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
4297+
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
4298+
OS.flush();
4299+
SmallString<512> Str;
4300+
raw_svector_ostream OutStrm(Str);
4301+
const auto ByteOrder = llvm::endianness::native;
4302+
FileWriter FW(OutStrm, ByteOrder);
4303+
ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
4304+
Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
4305+
ASSERT_THAT_EXPECTED(GR, Succeeded());
4306+
// There should be one function in our GSYM.
4307+
EXPECT_EQ(GR->getNumAddresses(), 1u);
4308+
// Verify "foo" is present and has a line table and no inline info.
4309+
auto ExpFI = GR->getFunctionInfo(0x1000);
4310+
ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
4311+
ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050));
4312+
EXPECT_TRUE(ExpFI->OptLineTable.has_value());
4313+
EXPECT_FALSE(ExpFI->Inline.has_value());
4314+
StringRef FuncName = GR->getString(ExpFI->Name);
4315+
EXPECT_EQ(FuncName, "foo");
4316+
4317+
// Make sure we don't see spurious errors in the output:
4318+
EXPECT_TRUE(errors.find("error:") == std::string::npos);
4319+
4320+
// Make sure that when we lookup address 0x1010, that we get the entry that
4321+
// matches line 12, the second line entry that also has the address of
4322+
// 0x1010.
4323+
auto LR = GR->lookup(0x1010);
4324+
ASSERT_THAT_EXPECTED(LR, Succeeded());
4325+
SourceLocation src_loc = {"foo", "/tmp", "main.cpp", 12, 16};
4326+
EXPECT_THAT(LR->Locations, testing::ElementsAre(src_loc));
4327+
git}

0 commit comments

Comments
 (0)