Skip to content

Commit 11588ef

Browse files
committed
add failover to naive location assumptions
The current hacked together location API we added to drgn works extremely poorly with modern C++ compilers. It largely works with the clang-12 compiler on CircleCI, but works very poorly with clang 15/16/17/18 in Nix or when updating the CircleCI compiler to clang-15. This change adds a backup mechanism for locating arguments when drgn has failed. The mechanism is extremely naive and makes several assumptions which are often not correct. Currently, however, it drastically reduces the number of tests that must be skipped in the Nix CI. Test plan: - CI
1 parent b7b9ac1 commit 11588ef

File tree

8 files changed

+75
-206
lines changed

8 files changed

+75
-206
lines changed
Lines changed: 6 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -1,235 +1,42 @@
11
AddChildrenTest.InheritancePolymorphic
2-
ClangTypeParserTest.MemberAlignment
3-
ClangTypeParserTest.SimpleStruct
42
DrgnParserTest.ClassTemplateInt
3+
DrgnParserTest.ClassTemplateTwo
4+
DrgnParserTest.ClassTemplateValue
55
DrgnParserTest.Container
66
DrgnParserTest.TemplateEnumValue
77
DrgnParserTest.TemplateEnumValueGaps
88
DrgnParserTest.TemplateEnumValueNegative
9-
OidIntegration.alignment_wrapper_member_alignment
10-
OidIntegration.alignment_wrapper_member_lower
11-
OidIntegration.alignment_wrapper_member_override
12-
OidIntegration.alignment_wrapper_struct
13-
OidIntegration.alignment_wrapper_two_members
14-
OidIntegration.alignment_wrapper_union_member
15-
OidIntegration.anonymous_anon_struct
16-
OidIntegration.anonymous_anon_typedef
17-
OidIntegration.anonymous_anon_union
18-
OidIntegration.anonymous_nested_anon_struct
19-
OidIntegration.anonymous_regular_struct
20-
OidIntegration.arrays_member_int0
21-
OidIntegration.arrays_member_int10
22-
OidIntegration.arrays_multidim
23-
OidIntegration.arrays_multidim_legacy
24-
OidIntegration.bitfields_enum
25-
OidIntegration.bitfields_mixed
26-
OidIntegration.bitfields_single
27-
OidIntegration.bitfields_straddle_bytes
28-
OidIntegration.bitfields_within_bytes
29-
OidIntegration.bitfields_zero_bits
30-
OidIntegration.cycles_raw_ptr
31-
OidIntegration.cycles_raw_ptr_wrapped
32-
OidIntegration.cycles_shared_ptr
33-
OidIntegration.cycles_unique_ptr
34-
OidIntegration.enums_params_scoped_enum_val
35-
OidIntegration.enums_params_scoped_enum_val_cast
36-
OidIntegration.enums_params_scoped_enum_val_gaps
37-
OidIntegration.enums_params_scoped_enum_val_negative
38-
OidIntegration.enums_params_unscoped_enum_val_cast
39-
OidIntegration.fbstring_empty
40-
OidIntegration.fbstring_heap_allocated
41-
OidIntegration.fbstring_inline
42-
OidIntegration.fbstring_string_pooled_unique
43-
OidIntegration.folly_f14_fast_map_a
44-
OidIntegration.folly_f14_fast_set_a
45-
OidIntegration.folly_f14_node_map_a
46-
OidIntegration.folly_f14_node_set_a
47-
OidIntegration.folly_f14_value_map_a
48-
OidIntegration.folly_f14_value_set_a
49-
OidIntegration.folly_f14_vector_map_a
50-
OidIntegration.folly_f14_vector_set_a
51-
OidIntegration.folly_small_vector_int_always_heap
52-
OidIntegration.folly_small_vector_int_default_empty
53-
OidIntegration.folly_small_vector_int_default_inlined
54-
OidIntegration.folly_small_vector_int_default_overflow
55-
OidIntegration.folly_small_vector_vector_3_empty
56-
OidIntegration.folly_small_vector_vector_3_inlined
57-
OidIntegration.folly_small_vector_vector_3_overflow
58-
OidIntegration.folly_sorted_vector_map_int_int_empty
59-
OidIntegration.folly_sorted_vector_map_int_int_reserve
60-
OidIntegration.folly_sorted_vector_map_int_int_some
61-
OidIntegration.ignored_member
62-
OidIntegration.ignored_roottype
63-
OidIntegration.ignored_subtype
64-
OidIntegration.inheritance_access_private
65-
OidIntegration.inheritance_access_protected
66-
OidIntegration.inheritance_access_public
67-
OidIntegration.inheritance_access_public_as_base
68-
OidIntegration.inheritance_multiple_a
69-
OidIntegration.inheritance_polymorphic_a_as_a
9+
DrgnParserTest.Typedef
10+
DrgnParserTest.Using
7011
OidIntegration.inheritance_polymorphic_b_as_a
71-
OidIntegration.inheritance_polymorphic_b_as_b
7212
OidIntegration.inheritance_polymorphic_c_as_a
7313
OidIntegration.inheritance_polymorphic_c_as_b
74-
OidIntegration.inheritance_polymorphic_c_as_c
75-
OidIntegration.inheritance_polymorphic_diamond_child_as_child
7614
OidIntegration.inheritance_polymorphic_diamond_child_as_middle1
7715
OidIntegration.inheritance_polymorphic_diamond_child_as_middle1_root
7816
OidIntegration.inheritance_polymorphic_diamond_child_as_middle2
7917
OidIntegration.inheritance_polymorphic_diamond_child_as_middle2_root
80-
OidIntegration.inheritance_polymorphic_diamond_middle1_as_middle1
8118
OidIntegration.inheritance_polymorphic_diamond_middle1_as_root
82-
OidIntegration.inheritance_polymorphic_diamond_middle2_as_middle2
8319
OidIntegration.inheritance_polymorphic_diamond_middle2_as_root
84-
OidIntegration.inheritance_polymorphic_diamond_root_as_root
85-
OidIntegration.inheritance_polymorphic_non_dynamic_base_a_as_a
86-
OidIntegration.inheritance_polymorphic_non_dynamic_base_a_no_polymorphic
87-
OidIntegration.inheritance_polymorphic_non_dynamic_base_b_as_a
8820
OidIntegration.inheritance_polymorphic_non_dynamic_base_b_as_b
8921
OidIntegration.inheritance_polymorphic_non_dynamic_base_b_no_polymorphic
90-
OidIntegration.inheritance_polymorphic_non_dynamic_base_c_as_a
9122
OidIntegration.inheritance_polymorphic_non_dynamic_base_c_as_b
9223
OidIntegration.inheritance_polymorphic_non_dynamic_base_c_as_c
9324
OidIntegration.inheritance_polymorphic_non_dynamic_base_c_no_polymorphic
94-
OidIntegration.multi_arg_tb_all_fail_crashes
95-
OidIntegration.multi_arg_tb_fail_first_arg
96-
OidIntegration.namespaces_queue
97-
OidIntegration.namespaces_stack
98-
OidIntegration.packed_a
99-
OidIntegration.padding_bool_padding
100-
OidIntegration.padding_nested_padding
101-
OidIntegration.pointers_feature_config
102-
OidIntegration.pointers_feature_flag_disabled
103-
OidIntegration.pointers_incomplete_containing_struct
104-
OidIntegration.pointers_incomplete_containing_struct_no_follow
105-
OidIntegration.pointers_incomplete_shared_ptr
106-
OidIntegration.pointers_incomplete_shared_ptr_null
107-
OidIntegration.pointers_incomplete_unique_ptr
108-
OidIntegration.pointers_incomplete_unique_ptr_null
109-
OidIntegration.pointers_struct_primitive_ptrs
110-
OidIntegration.pointers_struct_primitive_ptrs_no_follow
111-
OidIntegration.pointers_struct_primitive_ptrs_null
112-
OidIntegration.pointers_struct_vector_ptr
113-
OidIntegration.pointers_struct_vector_ptr_no_follow
114-
OidIntegration.pointers_struct_vector_ptr_null
115-
OidIntegration.pointers_vector_of_pointers
116-
OidIntegration.primitives_long_double
117-
OidIntegration.simple_class
118-
OidIntegration.simple_struct
119-
OidIntegration.simple_union
120-
OidIntegration.sorted_vector_set_no_ints
121-
OidIntegration.sorted_vector_set_some_ints
122-
OidIntegration.std_array_uint64_length_0
123-
OidIntegration.std_array_uint64_length_1
124-
OidIntegration.std_array_uint64_length_8
125-
OidIntegration.std_array_vector_length_1
126-
OidIntegration.std_array_vector_length_2
127-
OidIntegration.std_conditional_a
128-
OidIntegration.std_deque_del_allocator_a
129-
OidIntegration.std_deque_deque_int_empty
130-
OidIntegration.std_deque_deque_int_some
131-
OidIntegration.std_deque_int_empty
132-
OidIntegration.std_deque_int_some
133-
OidIntegration.std_list_del_allocator_a
134-
OidIntegration.std_list_int_empty
135-
OidIntegration.std_list_int_some
136-
OidIntegration.std_list_list_int_empty
137-
OidIntegration.std_list_list_int_some
138-
OidIntegration.std_list_struct_some
139-
OidIntegration.std_map_custom_comparator_a
140-
OidIntegration.std_multimap_custom_comparator_a
141-
OidIntegration.std_multiset_custom_comparator_a
142-
OidIntegration.std_optional_uint64_empty
143-
OidIntegration.std_optional_uint64_present
144-
OidIntegration.std_optional_vector_empty
145-
OidIntegration.std_optional_vector_present
146-
OidIntegration.std_pair_uint64_uint32
147-
OidIntegration.std_pair_uint64_uint64
148-
OidIntegration.std_pair_vector_vector
149-
OidIntegration.std_priority_queue_adapter_deque_empty
150-
OidIntegration.std_priority_queue_adapter_deque_some
151-
OidIntegration.std_priority_queue_int_empty
152-
OidIntegration.std_priority_queue_int_some
153-
OidIntegration.std_queue_adapter_vector_empty
154-
OidIntegration.std_queue_adapter_vector_some
155-
OidIntegration.std_queue_int_empty
156-
OidIntegration.std_queue_int_some
157-
OidIntegration.std_queue_queue_int_empty
158-
OidIntegration.std_queue_queue_int_some
159-
OidIntegration.std_reference_wrapper_int
160-
OidIntegration.std_reference_wrapper_vector
161-
OidIntegration.std_set_custom_comparator_a
162-
OidIntegration.std_smart_ptr_shared_ptr_const_uint64_empty
163-
OidIntegration.std_smart_ptr_shared_ptr_const_vector_empty
164-
OidIntegration.std_smart_ptr_shared_ptr_uint64_empty
165-
OidIntegration.std_smart_ptr_shared_ptr_uint64_present
166-
OidIntegration.std_smart_ptr_shared_ptr_vector_empty
167-
OidIntegration.std_smart_ptr_shared_ptr_vector_present
168-
OidIntegration.std_smart_ptr_shared_ptr_void_empty
169-
OidIntegration.std_smart_ptr_shared_ptr_void_present
170-
OidIntegration.std_smart_ptr_unique_ptr_const_uint64_empty
171-
OidIntegration.std_smart_ptr_unique_ptr_const_vector_empty
172-
OidIntegration.std_smart_ptr_unique_ptr_uint64_empty
173-
OidIntegration.std_smart_ptr_unique_ptr_uint64_present
174-
OidIntegration.std_smart_ptr_unique_ptr_vector_empty
175-
OidIntegration.std_smart_ptr_unique_ptr_vector_present
176-
OidIntegration.std_smart_ptr_unique_ptr_void_empty
177-
OidIntegration.std_smart_ptr_unique_ptr_void_present
178-
OidIntegration.std_smart_ptr_weak_ptr_int64_empty
179-
OidIntegration.std_smart_ptr_weak_ptr_int64_expired
180-
OidIntegration.std_smart_ptr_weak_ptr_int64_expired_chase
181-
OidIntegration.std_smart_ptr_weak_ptr_int64_present
182-
OidIntegration.std_smart_ptr_weak_ptr_int64_present_chase
183-
OidIntegration.std_smart_ptr_weak_ptr_int64_void_empty
184-
OidIntegration.std_stack_adapter_vector_empty
185-
OidIntegration.std_stack_adapter_vector_some
186-
OidIntegration.std_stack_int_empty
187-
OidIntegration.std_stack_int_some
188-
OidIntegration.std_stack_stack_int_empty
189-
OidIntegration.std_stack_stack_int_some
190-
OidIntegration.std_string_empty
191-
OidIntegration.std_string_heap_allocated
192-
OidIntegration.std_string_sso
193-
OidIntegration.std_tuple_uint64_uint64
194-
OidIntegration.std_unordered_map_custom_operator_a
195-
OidIntegration.std_unordered_multimap_custom_operator_a
196-
OidIntegration.std_unordered_multiset_custom_operator_a
197-
OidIntegration.std_unordered_set_custom_operator_a
198-
OidIntegration.std_variant_256_params_256
199-
OidIntegration.std_variant_256_params_empty
200-
OidIntegration.std_variant_char_int64_1
201-
OidIntegration.std_variant_char_int64_2
202-
OidIntegration.std_variant_empty
203-
OidIntegration.std_variant_optional
204-
OidIntegration.std_variant_vector_int_1
205-
OidIntegration.std_variant_vector_int_2
20625
OidIntegration.std_vector_del_allocator_a
207-
OidIntegration.std_vector_int_empty
208-
OidIntegration.std_vector_int_some
209-
OidIntegration.std_vector_reserve
210-
OidIntegration.std_vector_struct_some
211-
OidIntegration.std_vector_vector_int_empty
212-
OidIntegration.std_vector_vector_int_some
21326
OidIntegration.templates_int
21427
OidIntegration.templates_two
21528
OidIntegration.templates_value
21629
OidIntegration.templates_vector
21730
OidIntegration.typedefed_parent_multilevel_typedef_parent
21831
OidIntegration.typedefed_parent_simple_typedef_parent
21932
OidIntegration.typedefs_anonymous
33+
OidIntegration.typedefs_c_style
22034
OidIntegration.typedefs_container
35+
OidIntegration.typedefs_using
22136
OidIntegration.unions_alignment
22237
OidIntegration.unions_int
22338
OidIntegration.unions_tagged_int
22439
OidIntegration.unions_tagged_unordered_map
22540
OidIntegration.unions_tagged_vector
22641
OidIntegration.unions_unordered_map
22742
OidIntegration.unions_vector
228-
OilIntegration.folly_f14_fast_map_a
229-
OilIntegration.folly_f14_fast_set_a
230-
OilIntegration.folly_f14_node_map_a
231-
OilIntegration.folly_f14_node_set_a
232-
OilIntegration.folly_f14_value_map_a
233-
OilIntegration.folly_f14_value_set_a
234-
OilIntegration.folly_f14_vector_map_a
235-
OilIntegration.folly_f14_vector_set_a

flake.nix

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
mkOidPackage =
3535
llvmPackages:
3636
with pkgs;
37-
pkgs.llvmPackages.stdenv.mkDerivation rec {
37+
llvmPackages.stdenv.mkDerivation rec {
3838
name = "oid";
3939

4040
src = self;
@@ -60,6 +60,7 @@
6060
buildInputs = [
6161
llvmPackages.libclang
6262
llvmPackages.llvm
63+
llvmPackages.openmp
6364

6465
boost
6566
bzip2
@@ -85,8 +86,6 @@
8586
sqlite
8687
tomlplusplus
8788
zstd
88-
89-
llvmPackages.openmp # should match the stdenv clang version, see: https://github.com/NixOS/nixpkgs/issues/79818
9089
];
9190

9291
cmakeFlags = [

oi/Descs.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,13 @@ std::optional<uintptr_t> FuncDesc::Arg::findAddress(
5050
if (auto* err = drgn_object_locate(&locator, &modifiedRegs, &object)) {
5151
LOG(ERROR) << "Error while finding address of argument: " << err->message;
5252
drgn_error_destroy(err);
53-
return std::nullopt;
53+
} else {
54+
return object.address;
5455
}
5556

56-
return object.address;
57+
LOG(WARNING) << "failed to locate argument with drgn! failing over to naive "
58+
"argument location";
59+
return oi::detail::arch::naiveReadArgument(*regs, index);
5760
}
5861

5962
std::optional<uint8_t> FuncDesc::getArgumentIndex(const std::string& arg,

oi/Descs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ struct FuncDesc {
110110
};
111111

112112
struct Arg final : virtual TargetObject {
113-
struct drgn_object_locator locator;
113+
uint8_t index;
114+
drgn_object_locator locator;
114115

115116
~Arg() final {
116117
drgn_object_locator_deinit(&locator);

oi/Serialize.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
DEFINE_TYPE_VERSION(PaddingInfo, 120, 3)
4141
DEFINE_TYPE_VERSION(struct drgn_location_description, 32, 2)
4242
DEFINE_TYPE_VERSION(struct drgn_object_locator, 72, 2)
43-
DEFINE_TYPE_VERSION(FuncDesc::Arg, 128, 2)
43+
DEFINE_TYPE_VERSION(FuncDesc::Arg, 136, 3)
4444
DEFINE_TYPE_VERSION(FuncDesc::Retval, 56, 2)
4545
DEFINE_TYPE_VERSION(FuncDesc::Range, 16, 2)
4646
DEFINE_TYPE_VERSION(FuncDesc, 104, 4)

oi/arch/Arch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,7 @@ void setProgramCounter(user_regs_struct& regs, uintptr_t pc);
2626

2727
std::optional<uintptr_t> getReturnValueAddress(const user_regs_struct&);
2828

29+
std::optional<uintptr_t> naiveReadArgument(const user_regs_struct&,
30+
uint8_t idx);
31+
2932
} // namespace oi::detail::arch

oi/arch/aarch64.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,35 @@ void setProgramCounter(user_regs_struct& regs, uintptr_t pc) {
3131
regs.pc = pc;
3232
}
3333

34+
std::optional<uintptr_t> naiveReadArgument(const user_regs_struct&,
35+
uint8_t idx) {
36+
/*
37+
* The ARM64 argument passing practices are surprisingly well documented. The
38+
* PDF I am using here is
39+
* https://github.com/ARM-software/abi-aa/releases/download/2023Q3/aapcs32.pdf
40+
* from https://github.com/ARM-software/abi-aa/releases/tag/2023Q3. Relevant
41+
* information appears to be in §6.8.2.
42+
*
43+
* This is an extremely naïve estimation of register placement. It is expected
44+
* to work when all preceding arguments (this, arg0, arg.., argIdx) are:
45+
* - Pointers. Pointers are all placed in general purpose registers
46+
* incrementing as expected.
47+
* - >16 byte by-value structures. These are defined to be placed on the stack
48+
* and have a pointer placed in a general purpose registers, so increment in
49+
* the same way.
50+
* - <=8 byte integers. Also placed in general purpose registers.
51+
*
52+
* Any other types, including floats, will mess up our indexing. Looking at
53+
* the types of all the preceding arguments could get us a lot closer. For
54+
* now, we rely on OID correctly restoring the process if we get this wrong,
55+
* and might produce garbage data.
56+
*/
57+
if (idx < 8)
58+
return regs.regs[idx];
59+
60+
return std::nullopt;
61+
}
62+
3463
} // namespace oi::detail::arch
3564

3665
#endif

oi/arch/x86_64.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,33 @@ void setProgramCounter(user_regs_struct& regs, uintptr_t pc) {
3131
regs.rip = pc;
3232
}
3333

34+
std::optional<uintptr_t> naiveReadArgument(const user_regs_struct& regs,
35+
uint8_t idx) {
36+
/*
37+
* This function is based on the information available at
38+
* http://6.s081.scripts.mit.edu/sp18/x86-64-architecture-guide.html. I have
39+
* no idea under which conditions these registers are selected. We rely on the
40+
* fact that OID will safely exit if incorrect, potentially producing some
41+
* incorrect data but otherwise leaving the process unharmed.
42+
*/
43+
switch (idx) {
44+
case 0:
45+
return regs.rdi;
46+
case 1:
47+
return regs.rsi;
48+
case 2:
49+
return regs.rdx;
50+
case 3:
51+
return regs.rcx;
52+
case 4:
53+
return regs.r8;
54+
case 5:
55+
return regs.r9;
56+
default:
57+
return std::nullopt;
58+
}
59+
}
60+
3461
} // namespace oi::detail::arch
3562

3663
#endif

0 commit comments

Comments
 (0)