@@ -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