@@ -4156,3 +4156,172 @@ TEST(GSYMTest, TestEmptyLinkageName) {
4156
4156
// Make sure we don't see spurious errors in the output:
4157
4157
EXPECT_TRUE (errors.find (" error:" ) == std::string::npos);
4158
4158
}
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