@@ -198,22 +198,33 @@ bool has_flag_attribute(const attribute_sequence& attributes, dw::at name) {
198
198
199
199
std::size_t die_hash (const die& d, const attribute_sequence& attributes) {
200
200
ZoneScoped;
201
-
202
- // Tag used to be a part of the fatal hash computation. Unfortunately it causes `class` and
203
- // `struct` definitions to be considered different, when they should not be. As a general
204
- // rule, I think _all_ symbols regardless of tag should be uniquely defined, so pulling the tag
205
- // from the hash below should catch more issues without adding any false positives.
201
+
202
+ // Ideally, tag would not be part of this hash and all symbols, regardless of tag, would be
203
+ // unique. However, that fails in at least one case:
204
+ //
205
+ // typedef struct S {} S;
206
+ //
207
+ // This results in both a `typedef` element and a `struct` element, with the same symbol path,
208
+ // but which is not an ODRV.
209
+ //
210
+ // On the other hand, including tag in the hash results in missed ODRVs in cases like:
211
+ //
212
+ // struct S1 {}
213
+ // ...
214
+ // class S1 { int i; }
206
215
//
207
- // The `declaration` attribute used to be a part of this hash, too. Given that a declaration
208
- // is not a definition, they cannot contribute to an ODRV, so were instead added to the
209
- // `skip_die` logic, and removed from this hash.
216
+ // which results in a `struct` element and a `class` element with the same symbol path, but
217
+ // differing definitions, which _is_ an ODRV.
210
218
//
211
- // Thus, the only two things that contribute to the ODR hash of a die are its architecture and
212
- // symbol path.
219
+ // So, we will include the tag in the hash, but combine the tag values for `struct` and `class`
220
+ // into a single value.
221
+ auto tag = d._tag == dw::tag::structure_type ? dw::tag::class_type : d._tag ;
213
222
214
223
// clang-tidy off
215
224
return orc::hash_combine (0 ,
216
225
static_cast <std::size_t >(d._arch ),
226
+ static_cast <std::size_t >(tag),
227
+ has_flag_attribute (attributes, dw::at::declaration),
217
228
d._path .hash ());
218
229
// clang-tidy on
219
230
};
@@ -440,6 +451,7 @@ struct dwarf::implementation {
440
451
std::vector<pool_string> _decl_files;
441
452
std::unordered_map<std::size_t , pool_string> _type_cache;
442
453
std::unordered_map<std::size_t , pool_string> _debug_str_cache;
454
+ cu_header _cu_header;
443
455
std::size_t _cu_address{0 };
444
456
std::uint32_t _ofd_index{0 }; // index to the obj_registry in macho.cpp
445
457
section _debug_abbrev;
@@ -661,8 +673,17 @@ attribute dwarf::implementation::process_attribute(const attribute& attr,
661
673
// decl_file comes back as a uint, but that's a debug_str offset that needs to be resolved.
662
674
if (result._name == dw::at::decl_file) {
663
675
auto decl_file_index = result._value .uint ();
664
- assert (decl_file_index < _decl_files.size ());
665
- result._value .string (_decl_files[decl_file_index]);
676
+ // We currently only process the `file_names` part of the `debug_line` section header to
677
+ // determine the decl_files list. However, this is only a partial list as the line number
678
+ // program can also contain DW_LNE_define_file ops, which we don't currently process.
679
+ // See https://github.com/adobe/orc/issues/67
680
+ // For now, we will ignore file indexes too large for our list.
681
+ // assert(decl_file_index < _decl_files.size());
682
+ if (decl_file_index < _decl_files.size ()) {
683
+ result._value .string (_decl_files[decl_file_index]);
684
+ } else {
685
+ result._value .string (empool (" <unsupported file index>" ));
686
+ }
666
687
} else if (result._name == dw::at::calling_convention) {
667
688
auto convention = result._value .uint ();
668
689
assert (convention > 0 && convention <= 0xff );
@@ -1099,7 +1120,11 @@ attribute_value dwarf::implementation::process_form(const attribute& attr,
1099
1120
result.uint (read64 ());
1100
1121
} break ;
1101
1122
case dw::form::ref_addr: {
1102
- result.reference (read32 ());
1123
+ if (_cu_header._version == 2 ) {
1124
+ result.reference (read64 ());
1125
+ } else {
1126
+ result.reference (read32 ());
1127
+ }
1103
1128
} break ;
1104
1129
case dw::form::ref1: {
1105
1130
handle_reference (read8 ());
@@ -1375,11 +1400,9 @@ void dwarf::implementation::process_all_dies() {
1375
1400
dies dies;
1376
1401
1377
1402
while (_s.tellg () < section_end) {
1378
- cu_header header;
1379
-
1380
1403
_cu_address = _s.tellg ();
1381
1404
1382
- header .read (_s, _details._needs_byteswap );
1405
+ _cu_header .read (_s, _details._needs_byteswap );
1383
1406
1384
1407
// process dies one at a time, recording things like addresses along the way.
1385
1408
while (true ) {
0 commit comments