forked from osandov/drgn
-
Notifications
You must be signed in to change notification settings - Fork 6
/
dwarf_info.h
359 lines (322 loc) · 11.6 KB
/
dwarf_info.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later
/**
* @file
*
* DWARF and .eh_frame support.
*
* See @ref DebugInfo.
*/
#ifndef DRGN_DEBUG_INFO_DWARF_H
#define DRGN_DEBUG_INFO_DWARF_H
/**
* @ingroup DebugInfo
*
* @{
*/
#include <elfutils/libdw.h>
#include "cfi.h"
#include "drgn_internal.h"
#include "hash_table.h"
#include "vector.h"
struct drgn_debug_info;
struct drgn_elf_file;
struct drgn_module;
struct drgn_register_state;
/** DWARF Frame Description Entry. */
struct drgn_dwarf_fde {
uint64_t initial_location;
uint64_t address_range;
/* CIE for this FDE as an index into drgn_dwarf_cfi::cies. */
size_t cie;
const char *instructions;
size_t instructions_size;
};
/** DWARF Call Frame Information. */
struct drgn_dwarf_cfi {
/** Array of DWARF Common Information Entries. */
struct drgn_dwarf_cie *cies;
/**
* Array of DWARF Frame Description Entries sorted by initial_location.
*/
struct drgn_dwarf_fde *fdes;
/** Number of elements in @ref drgn_dwarf_cfi::fdes. */
size_t num_fdes;
};
/** DWARF debugging information for a @ref drgn_module. */
struct drgn_module_dwarf_info {
/** Call Frame Information from .debug_frame. */
struct drgn_dwarf_cfi debug_frame;
/** Call Frame Information from .eh_frame. */
struct drgn_dwarf_cfi eh_frame;
/** Base for `DW_EH_PE_pcrel`. */
uint64_t pcrel_base;
/** Base for `DW_EH_PE_textrel`. */
uint64_t textrel_base;
/** Base for `DW_EH_PE_datarel`. */
uint64_t datarel_base;
};
void drgn_module_dwarf_info_deinit(struct drgn_module *module);
DEFINE_VECTOR_TYPE(drgn_dwarf_index_die_vector, uintptr_t,
vector_inline_minimal, uint32_t);
DEFINE_HASH_MAP_TYPE(drgn_dwarf_index_die_map, struct nstring,
struct drgn_dwarf_index_die_vector);
DEFINE_HASH_TABLE_TYPE(drgn_namespace_table,
struct drgn_namespace_dwarf_index *);
/* DWARF tags that act as namespaces. */
#define DRGN_DWARF_INDEX_NAMESPACE_TAGS \
X(structure_type) \
X(class_type) \
X(union_type) \
X(namespace)
/* DWARF tags that we index. */
#define DRGN_DWARF_INDEX_TAGS \
/* \
* These must be first for a few places where we only care about \
* namespace-like tags (e.g., drgn_namespace_dwarf_index::dies_indexed).\
*/ \
DRGN_DWARF_INDEX_NAMESPACE_TAGS \
X(enumeration_type) \
X(typedef) \
X(enumerator) \
X(subprogram) \
X(variable) \
X(base_type)
enum drgn_dwarf_index_tag {
#define X(name) DRGN_DWARF_INDEX_##name,
DRGN_DWARF_INDEX_TAGS
#undef X
};
#define X(_) + 1
enum { DRGN_DWARF_INDEX_NUM_NAMESPACE_TAGS = DRGN_DWARF_INDEX_NAMESPACE_TAGS };
enum { DRGN_DWARF_INDEX_NUM_TAGS = DRGN_DWARF_INDEX_TAGS };
#undef X
_Static_assert(DRGN_DWARF_INDEX_base_type == DRGN_DWARF_INDEX_NUM_TAGS - 1,
"base_type must be last");
enum { DRGN_DWARF_INDEX_MAP_SIZE = DRGN_DWARF_INDEX_NUM_TAGS - 1 };
/**
* DWARF information for a namespace or nested definitions in a class, struct,
* or union.
*/
struct drgn_namespace_dwarf_index {
/** Debugging information cache that owns this index. */
struct drgn_debug_info *dbinfo;
/** (Null-terminated) name of this namespace. */
const char *name;
/** Length of @ref name. */
size_t name_len;
/** Parent namespace, or @c NULL if it is the global namespace. */
struct drgn_namespace_dwarf_index *parent;
/** Children namespaces indexed by name. */
struct drgn_namespace_table children;
/**
* Mapping for each @ref drgn_dwarf_index_tag from name to a list of
* matching DIE addresses.
*
* This has a few quirks:
*
* - `base_type` DIEs are in @ref drgn_dwarf_info::base_types, not here.
* - `enumerator` entries store the addresses of the parent
* `enumeration_type` DIEs instead.
* - `namespace` entries also include the addresses of `class_type`,
* `structure_type`, and `union_type` DIEs that have children and
* `DW_AT_declaration`. This is because class, struct, and union
* declaration DIEs can contain nested definitions, so we want to
* index the children of those declarations, but we don't want to
* encounter the declarations when looking for the actual type.
* - Otherwise, this does not include DIEs with `DW_AT_declaration`.
*/
struct drgn_dwarf_index_die_map map[DRGN_DWARF_INDEX_MAP_SIZE];
/**
* Number of CUs that were indexed the last time that this namespace was
* indexed.
*/
size_t cus_indexed;
/**
* Number of DIEs for each namespace-like tag in the parent's index that
* were indexed the last time that this namespace was indexed.
*/
uint32_t dies_indexed[DRGN_DWARF_INDEX_NUM_NAMESPACE_TAGS];
/** Saved error from a previous index. */
struct drgn_error *saved_err;
};
/** Cached type in a @ref drgn_debug_info. */
struct drgn_dwarf_type {
struct drgn_type *type;
enum drgn_qualifiers qualifiers;
/**
* Whether this is an incomplete array type or a typedef of one.
*
* This is used to work around a GCC bug; see @ref
* drgn_type_from_dwarf_internal().
*/
bool is_incomplete_array;
};
DEFINE_HASH_MAP_TYPE(drgn_dwarf_base_type_map, struct nstring, uintptr_t);
DEFINE_HASH_MAP_TYPE(drgn_dwarf_specification_map, uintptr_t, uintptr_t);
DEFINE_VECTOR_TYPE(drgn_dwarf_index_cu_vector, struct drgn_dwarf_index_cu);
DEFINE_HASH_MAP_TYPE(drgn_dwarf_type_map, const void *, struct drgn_dwarf_type);
/** DWARF debugging information for a program/@ref drgn_debug_info. */
struct drgn_dwarf_info {
/** Global namespace index. */
struct drgn_namespace_dwarf_index global;
/**
* Mapping from name to `DW_TAG_base_type` DIE address with that name.
*
* Unlike user-defined types and variables, there can only be one base
* type with a given name in the entire program, so we don't store them
* in a @ref drgn_dwarf_index_die_map.
*/
struct drgn_dwarf_base_type_map base_types;
/**
* Map from the address of a DIE to the address of a top-level DIE with
* a `DW_AT_specification` or `DW_AT_abstract_origin` attribute that
* refers to it.
*/
struct drgn_dwarf_specification_map specifications;
/** Indexed compilation units. */
struct drgn_dwarf_index_cu_vector index_cus;
/**
* Cache of parsed types.
*
* The key is the address of the DIE (@c Dwarf_Die::addr). The value is
* a @ref drgn_dwarf_type.
*/
struct drgn_dwarf_type_map types;
/**
* Cache of parsed types which appear to be incomplete array types but
* can't be.
*
* See @ref drgn_type_from_dwarf_internal().
*/
struct drgn_dwarf_type_map cant_be_incomplete_array_types;
};
void drgn_dwarf_info_init(struct drgn_debug_info *dbinfo);
void drgn_dwarf_info_deinit(struct drgn_debug_info *dbinfo);
/**
* State tracked while indexing new DWARF information in a @ref drgn_dwarf_info.
*/
struct drgn_dwarf_index_state {
struct drgn_debug_info *dbinfo;
/** Per-thread arrays of CUs to be indexed. */
struct drgn_dwarf_index_cu_vector *cus;
};
/**
* Initialize state for indexing new DWARF information.
*
* @return @c true on success, @c false on failure to allocate memory.
*/
bool drgn_dwarf_index_state_init(struct drgn_dwarf_index_state *state,
struct drgn_debug_info *dbinfo);
/** Deinitialize state for indexing new DWARF information. */
void drgn_dwarf_index_state_deinit(struct drgn_dwarf_index_state *state);
/** Read a @ref drgn_elf_file to index its DWARF information. */
struct drgn_error *
drgn_dwarf_index_read_file(struct drgn_dwarf_index_state *state,
struct drgn_elf_file *file);
/**
* Index new DWARF information.
*
* This should be called once all files have been read with @ref
* drgn_dwarf_index_read_file() to finish indexing those files.
*/
struct drgn_error *
drgn_dwarf_info_update_index(struct drgn_dwarf_index_state *state);
/**
* Find the DWARF DIEs in a @ref drgn_module for the scope containing a given
* program counter.
*
* @param[in] module Module containing @p pc.
* @param[in] pc Program counter.
* @param[out] bias_ret Returned difference between addresses in the loaded
* module and addresses in the returned DIEs.
* @param[out] dies_ret Returned DIEs. `(*dies_ret)[*length_ret - 1]` is the
* innermost DIE containing @p pc, `(*dies_ret)[*length_ret - 2]` is its parent
* (which may not contain @p pc itself), `(*dies_ret)[*length_ret - 3]` is its
* grandparent, etc. Must be freed with @c free().
* @param[out] length_ret Returned length of @p dies_ret.
*/
struct drgn_error *drgn_module_find_dwarf_scopes(struct drgn_module *module,
uint64_t pc,
uint64_t *bias_ret,
Dwarf_Die **dies_ret,
size_t *length_ret)
__attribute__((__nonnull__(1, 3, 4, 5)));
/**
* Find the ancestors of a DWARF DIE.
*
* This finds the parent, grandparent, etc., of a DWARF DIE in the tree of DIEs.
*
* @param[in] module Module containing @p die.
* @param[in] die DIE to find.
* @param[out] dies_ret Returned DIEs. `(*dies_ret)[*length_ret]` is the DIE,
* `(*dies_ret)[*length_ret - 1]` is its parent, `(*dies_ret)[*length_ret - 2]`
* is its grandparent, etc., and `(*dies_ret)[0]` is the top-level unit DIE.
* @param[out] length_ret Returned number of ancestors in @p dies_ret.
*/
struct drgn_error *drgn_find_die_ancestors(Dwarf_Die *die, Dwarf_Die **dies_ret,
size_t *length_ret)
__attribute__((__nonnull__(2, 3)));
/**
* Get an array of names of `DW_TAG_variable` and `DW_TAG_formal_parameter` DIEs
* in local scopes.
*
* @param[out] names_ret Returned array of names. On success, must be freed with
* @c free(). The individual strings should not be freed.
* @param[out] count_ret Returned number of names in @p names_ret.
*/
struct drgn_error *drgn_dwarf_scopes_names(Dwarf_Die *scopes,
size_t num_scopes,
const char ***names_ret,
size_t *count_ret);
/**
* Find an object DIE in an array of DWARF scopes.
*
* @param[in] scopes Array of scopes, from outermost to innermost.
* @param[in] num_scopes Number of scopes in @p scopes.
* @param[out] die_ret Returned object DIE.
* @param[out] type_ret If @p die_ret is a `DW_TAG_enumerator` DIE, its parent.
* Otherwise, undefined.
*/
struct drgn_error *drgn_find_in_dwarf_scopes(Dwarf_Die *scopes,
size_t num_scopes,
const char *name,
Dwarf_Die *die_ret,
Dwarf_Die *type_ret);
/**
* Create a @ref drgn_object from a `Dwarf_Die`.
*
* @param[in] die Object DIE (e.g., `DW_TAG_subprogram`, `DW_TAG_variable`,
* `DW_TAG_formal_parameter`, `DW_TAG_enumerator`,
* `DW_TAG_template_value_parameter`).
* @param[in] type_die DIE of object's type. If @c NULL, use the `DW_AT_type`
* attribute of @p die. If @p die is a `DW_TAG_enumerator` DIE, this should be
* its parent.
* @param[in] function_die DIE of current function. @c NULL if not in function
* context.
* @param[in] regs Registers of current stack frame. @c NULL if not in stack
* frame context.
* @param[out] ret Returned object.
*/
struct drgn_error *
drgn_object_from_dwarf(struct drgn_debug_info *dbinfo,
struct drgn_elf_file *file, Dwarf_Die *die,
Dwarf_Die *type_die, Dwarf_Die *function_die,
const struct drgn_register_state *regs,
struct drgn_object *ret);
struct drgn_error *
drgn_module_find_dwarf_cfi(struct drgn_module *module, uint64_t pc,
struct drgn_cfi_row **row_ret, bool *interrupted_ret,
drgn_register_number *ret_addr_regno_ret);
struct drgn_error *
drgn_module_find_eh_cfi(struct drgn_module *module, uint64_t pc,
struct drgn_cfi_row **row_ret, bool *interrupted_ret,
drgn_register_number *ret_addr_regno_ret);
struct drgn_error *
drgn_eval_cfi_dwarf_expression(struct drgn_program *prog,
struct drgn_elf_file *file,
const struct drgn_cfi_rule *rule,
const struct drgn_register_state *regs,
void *buf, size_t size);
/** @} */
#endif /* DRGN_DEBUG_INFO_DWARF_H */