Skip to content

Commit 7c06f50

Browse files
authored
Hotfixes (#69)
* Hotfixes: - Fix for reading correct ref_addr in dwarf v2. - Workaround for only reading partial decl_files list. * Added tests and fix issue where a a test compilation fails but is not recognized because the failure output goes to stderr, which wasn't being read before. * Fix typo. * Put declaration back into die_hash.
1 parent ae35fce commit 7c06f50

File tree

8 files changed

+68
-19
lines changed

8 files changed

+68
-19
lines changed

include/orc/dwarf_structs.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ struct attribute_value {
8181
return _string.hash();
8282
}
8383

84-
void reference(std::uint32_t offset) {
84+
void reference(std::uint64_t offset) {
8585
_type |= type::reference;
8686
_uint = offset;
8787
}

src/dwarf.cpp

+39-16
Original file line numberDiff line numberDiff line change
@@ -198,22 +198,33 @@ bool has_flag_attribute(const attribute_sequence& attributes, dw::at name) {
198198

199199
std::size_t die_hash(const die& d, const attribute_sequence& attributes) {
200200
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; }
206215
//
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.
210218
//
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;
213222

214223
// clang-tidy off
215224
return orc::hash_combine(0,
216225
static_cast<std::size_t>(d._arch),
226+
static_cast<std::size_t>(tag),
227+
has_flag_attribute(attributes, dw::at::declaration),
217228
d._path.hash());
218229
// clang-tidy on
219230
};
@@ -440,6 +451,7 @@ struct dwarf::implementation {
440451
std::vector<pool_string> _decl_files;
441452
std::unordered_map<std::size_t, pool_string> _type_cache;
442453
std::unordered_map<std::size_t, pool_string> _debug_str_cache;
454+
cu_header _cu_header;
443455
std::size_t _cu_address{0};
444456
std::uint32_t _ofd_index{0}; // index to the obj_registry in macho.cpp
445457
section _debug_abbrev;
@@ -661,8 +673,17 @@ attribute dwarf::implementation::process_attribute(const attribute& attr,
661673
// decl_file comes back as a uint, but that's a debug_str offset that needs to be resolved.
662674
if (result._name == dw::at::decl_file) {
663675
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+
}
666687
} else if (result._name == dw::at::calling_convention) {
667688
auto convention = result._value.uint();
668689
assert(convention > 0 && convention <= 0xff);
@@ -1099,7 +1120,11 @@ attribute_value dwarf::implementation::process_form(const attribute& attr,
10991120
result.uint(read64());
11001121
} break;
11011122
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+
}
11031128
} break;
11041129
case dw::form::ref1: {
11051130
handle_reference(read8());
@@ -1375,11 +1400,9 @@ void dwarf::implementation::process_all_dies() {
13751400
dies dies;
13761401

13771402
while (_s.tellg() < section_end) {
1378-
cu_header header;
1379-
13801403
_cu_address = _s.tellg();
13811404

1382-
header.read(_s, _details._needs_byteswap);
1405+
_cu_header.read(_s, _details._needs_byteswap);
13831406

13841407
// process dies one at a time, recording things like addresses along the way.
13851408
while (true) {

test/battery/class_struct/class.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class object {
2+
bool _x;
3+
bool _y;
4+
};
5+
6+
void f(const object& o) { }
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[[source]]
2+
path = "class.cpp"
3+
4+
[[source]]
5+
path = "struct.cpp"
6+
7+
[[odrv]]
8+
category = "structure:byte_size"

test/battery/class_struct/struct.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
struct object {
2+
bool _x;
3+
};
4+
5+
void f(const object& o) { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[[source]]
2+
path = "src.cpp"

test/battery/typedef_struct/src.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
typedef struct S {int _i;} S;
2+
3+
// Required so the compiler generates a symbol.
4+
int get(S s) { return s._i; }

test/src/main.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,9 @@ auto object_file_path(const std::filesystem::path& battery_path, const compilati
172172

173173
/**************************************************************************************************/
174174

175-
std::string exec(const char* cmd) {
176-
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
175+
std::string exec(std::string cmd) {
176+
cmd += " 2>&1";
177+
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
177178

178179
if (!pipe) {
179180
throw std::runtime_error("popen() failed!");

0 commit comments

Comments
 (0)