File: debug_info.h

package info (click to toggle)
drgn 0.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 7,852 kB
  • sloc: python: 74,992; ansic: 54,589; awk: 423; makefile: 351; sh: 99
file content (428 lines) | stat: -rw-r--r-- 12,942 bytes parent folder | download
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
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later

/**
 * @file
 *
 * Debugging information handling.
 *
 * See @ref DebugInfo.
 */

#ifndef DRGN_DEBUG_INFO_H
#define DRGN_DEBUG_INFO_H

#if WITH_DEBUGINFOD
#include <elfutils/debuginfod.h>
#endif
#include <elfutils/libdw.h>
#include <libelf.h>

#include "binary_search_tree.h"
#include "cfi.h"
#include "debug_info_options.h"
#include "drgn_internal.h"
#include "dwarf_info.h"
#include "elf_symtab.h"
#include "hash_table.h"
#include "object.h"
#include "orc_info.h"
#include "string_builder.h"
#include "symbol.h"
#include "type.h"
#include "vector.h"

struct drgn_elf_file;

/**
 * @ingroup Internals
 *
 * @defgroup DebugInfo Debugging information
 *
 * Caching of debugging information.
 *
 * @ref drgn_debug_info caches debugging information (currently DWARF and ORC).
 * It translates the debugging information to types and objects.
 *
 * @{
 */

#if WITH_DEBUGINFOD
#if ENABLE_DLOPEN_DEBUGINFOD
bool drgn_have_debuginfod(void);
#else
static inline bool drgn_have_debuginfod(void)
{
	return true;
}
#endif
#else
static inline bool drgn_have_debuginfod(void)
{
	return false;
}
#endif

DEFINE_HASH_TABLE_TYPE(drgn_elf_file_dwarf_table, struct drgn_elf_file *);
DEFINE_HASH_TABLE_TYPE(drgn_module_table, struct drgn_module *);
DEFINE_BINARY_SEARCH_TREE_TYPE(drgn_module_address_tree,
			       struct drgn_module_address_range);

struct drgn_debug_info_finder {
	struct drgn_handler handler;
	struct drgn_debug_info_finder_ops ops;
	void *arg;
};

/** Cache of debugging information. */
struct drgn_debug_info {
	/** Program owning this cache. */
	struct drgn_program *prog;

	struct drgn_type_finder type_finder;
	struct drgn_object_finder object_finder;
	struct drgn_symbol_finder symbol_finder;

	/** Main module. @c NULL if not created yet. */
	struct drgn_module *main_module;
	/**
	 * Table of all modules indexed by name.
	 *
	 * Modules with the same name (which should be rare) are on a
	 * singly-linked list (@ref drgn_module::next_same_name).
	 */
	struct drgn_module_table modules;
	/**
	 * Counter used to detect when @ref modules is modified during iteration
	 * of a @ref drgn_created_module_iterator.
	 */
	uint64_t modules_generation;
	/** Tree of modules sorted by start address. */
	struct drgn_module_address_tree modules_by_address;
	/**
	 * Singly-linked list of modules that need to have their DWARF
	 * information indexed.
	 */
	struct drgn_module *modules_pending_indexing;
	/** DWARF debugging information. */
	struct drgn_dwarf_info dwarf;

	struct drgn_handler_list debug_info_finders;
	struct drgn_debug_info_finder standard_debug_info_finder;
	struct drgn_debug_info_options options;
	/**
	 * Counter used to detect when loading debugging information is
	 * attempted.
	 *
	 * @sa drgn_module::load_debug_info_generation
	 */
	uint64_t load_debug_info_generation;
	/**
	 * Counter used to detect when the wanted supplementary file for a
	 * module has changed.
	 *
	 * @sa drgn_module_wanted_supplementary_file::generation
	 */
	uint64_t supplementary_file_generation;

#if WITH_DEBUGINFOD
	struct drgn_debug_info_finder debuginfod_debug_info_finder;
	/** debuginfod-client session. */
	debuginfod_client *debuginfod_client;
	const char *debuginfod_current_name;
	const char *debuginfod_current_type;
	unsigned int debuginfod_spinner_position;
	bool debuginfod_have_url;
	bool logged_debuginfod_progress;
#endif
	bool logged_no_debuginfod;

	/**
	 * Cache of entries in /proc/$pid/map_files used for finding loaded
	 * files. Populated the first time we need it or opportunistically when
	 * we parse /proc/$pid/maps. Rebuilt whenever we try to open an entry
	 * that no longer exists.
	 */
	struct drgn_map_files_segment *map_files_segments;
	/** Number of segments in @ref map_files_segments. */
	size_t num_map_files_segments;
};

/** Initialize a @ref drgn_debug_info. */
void drgn_debug_info_init(struct drgn_debug_info *dbinfo,
			  struct drgn_program *prog);

/** Deinitialize a @ref drgn_debug_info. */
void drgn_debug_info_deinit(struct drgn_debug_info *dbinfo);

typedef void drgn_module_iterator_destroy_fn(struct drgn_module_iterator *);
typedef struct drgn_error *
drgn_module_iterator_next_fn(struct drgn_module_iterator *,
			     struct drgn_module **, bool *);

struct drgn_module_iterator {
	struct drgn_program *prog;
	drgn_module_iterator_destroy_fn *destroy;
	drgn_module_iterator_next_fn *next;
	bool for_load_debug_info;
};

static inline void
drgn_module_iterator_init(struct drgn_module_iterator *it,
			  struct drgn_program *prog,
			  drgn_module_iterator_destroy_fn *destroy,
			  drgn_module_iterator_next_fn *next)
{
	it->prog = prog;
	it->destroy = destroy;
	it->next = next;
	it->for_load_debug_info = false;
}

/** Bitmask of files in a @ref drgn_module. */
enum drgn_module_file_mask {
	DRGN_MODULE_FILE_MASK_LOADED = 1 << 0,
	DRGN_MODULE_FILE_MASK_DEBUG = 1 << 1,
} __attribute__((__packed__));

DEFINE_HASH_MAP_TYPE(drgn_module_section_address_map, char *, uint64_t);

struct drgn_module_address_range {
	/** Node in @ref drgn_debug_info::modules_by_address. */
	struct binary_tree_node node;
	/** Address range. */
	uint64_t start, end;
	/** Module owning this range. */
	struct drgn_module *module;
};

struct drgn_module {
	struct drgn_program *prog;
	enum drgn_module_kind kind;

	/** Module name. */
	char *name;
	/** Kind-specific info. */
	uint64_t info;

	/** Next module with the same name in @ref drgn_debug_info::modules. */
	struct drgn_module *next_same_name;

	/**
	 * Raw binary build ID. @c NULL if the module does not have a build ID.
	 */
	void *build_id;
	/**
	 * Length of @ref drgn_module::build_id in bytes. Zero if the module
	 * does not have a build ID.
	 */
	size_t build_id_len;
	/**
	 * Build ID as a null-terminated hexadecimal string. @c NULL if the
	 * module does not have a build ID.
	 *
	 * Used for logging and finding debugging information.
	 *
	 * This is allocated together with @ref drgn_module::build_id.
	 */
	char *build_id_str;
	/** Load address ranges. @c NULL if not known yet. */
	struct drgn_module_address_range *address_ranges;
	/** Number of ranges in @ref address_ranges. */
	size_t num_address_ranges;
	/**
	 * Placeholder assigned to @ref address_ranges in two cases:
	 *
	 * 1. If @ref num_address_ranges is 1. This lets us avoid allocating the
	 *    address ranges separately. This is a minor optimization for the
	 *    common case, but more importantly,
	 *    `drgn_module_maybe_use_elf_file()` can't handle @ref
	 *    drgn_module_set_address_range() failing.
	 * 2. If the address range is known to be empty. This allows us to
	 *    distinguish between that and the unknown case.
	 */
	struct drgn_module_address_range single_address_range;

	struct drgn_elf_file *loaded_file;
	struct drgn_elf_file *debug_file;
	struct drgn_elf_file *supplementary_debug_file;
	struct drgn_elf_file *gnu_debugdata_file;
	/** Table mapping libdw handle to corresponding @ref drgn_elf_file. */
	struct drgn_elf_file_dwarf_table split_dwarf_files;
	uint64_t loaded_file_bias;
	uint64_t debug_file_bias;
	enum drgn_module_file_status loaded_file_status;
	enum drgn_module_file_status debug_file_status;
	enum drgn_supplementary_file_kind supplementary_debug_file_kind;

	/** DWARF debugging information. */
	struct drgn_module_dwarf_info dwarf;
	/** ORC unwinder information. */
	struct drgn_module_orc_info orc;
	/** ELF symbol table. */
	struct drgn_elf_symbol_table elf_symtab;
	/** Symbol table from the gnu_debugdata_file */
	struct drgn_elf_symbol_table gnu_debugdata_symtab;

	/** Whether .debug_frame has been parsed. */
	bool parsed_debug_frame;
	/** Whether .eh_frame has been parsed. */
	bool parsed_eh_frame;
	/** Whether ORC unwinder data has been parsed. */
	bool parsed_orc;
	/** Which files need to be checked for an ELF symbol table. */
	enum drgn_module_file_mask elf_symtab_pending_files;
	/**
	 * Whether a full symbol table has been found (as opposed to a dynamic
	 * symbol table, which only contains a subset of symbols).
	 */
	bool have_full_symtab;

	/** Mapping from section name to address. */
	struct drgn_module_section_address_map section_addresses;
	/**
	 * Counter used to detect when @ref section_addresses is modified during
	 * iteration of a @ref drgn_module_section_address_iterator.
	 */
	uint64_t section_addresses_generation;

	/**
	 * Counter used to detect when loading debugging information is
	 * attempted.
	 *
	 * @sa drgn_debug_info::load_debug_info_generation
	 */
	uint64_t load_debug_info_generation;
	struct drgn_module_wanted_supplementary_file *wanted_supplementary_debug_file;
	/** Node in @ref drgn_debug_info::modules_pending_indexing. */
	struct drgn_module *pending_indexing_next;
	/** Object the module was created from */
	struct drgn_object object;
};

/**
 * Delete a partially-initialized module. This can only be called before the
 * module is returned from public API.
 */
void drgn_module_delete(struct drgn_module *module);

static inline void drgn_module_deletep(struct drgn_module **modulep)
{
	if (*modulep)
		drgn_module_delete(*modulep);
}

// Binary index file generated by depmod(8).
struct depmod_index {
	char *path;
	void *addr;
	size_t len;
};

DEFINE_VECTOR_TYPE(char_p_vector, char *);

DEFINE_HASH_MAP_TYPE(drgn_kmod_walk_module_map, const char *,
		     struct char_p_vector);

DEFINE_VECTOR_TYPE(drgn_kmod_walk_stack,
		   struct drgn_kmod_walk_stack_entry);

struct drgn_kmod_walk_inode {
	dev_t dev;
	ino_t ino;
};

DEFINE_HASH_SET_TYPE(drgn_kmod_walk_inode_set, struct drgn_kmod_walk_inode);

struct drgn_kmod_walk_state {
	struct drgn_kmod_walk_module_map modules;
	struct drgn_kmod_walk_stack stack;
	struct string_builder path;
	struct drgn_kmod_walk_inode_set visited_dirs;
	const char * const *next_kernel_dir;
	const char * const *next_debug_dir;
};

// State kept by standard debug info finder for all modules it's working on.
// Currently it's only used to cache locations of Linux kernel loadable modules.
struct drgn_standard_debug_info_find_state {
	struct drgn_module * const *modules;
	size_t num_modules;
	struct depmod_index modules_dep;
	struct drgn_kmod_walk_state kmod_walk;
};

void
drgn_standard_debug_info_find_state_deinit(struct drgn_standard_debug_info_find_state *state);

// Always takes ownership of fd. Attempts to resolve the real path of path.
struct drgn_error *
drgn_module_try_standard_file(struct drgn_module *module,
			      const struct drgn_debug_info_options *options,
			      const char *path, int fd, bool check_build_id,
			      const uint32_t *expected_crc);

static inline bool drgn_module_wants_file(struct drgn_module *module)
{
	return drgn_module_wants_loaded_file(module)
	       || drgn_module_wants_debug_file(module);
}

/**
 * Get the language of the program's `main` function or `NULL` if it could not
 * be found.
 */
const struct drgn_language *
drgn_debug_info_main_language(struct drgn_debug_info *dbinfo);

/** @ref drgn_type_finder_ops::find() that uses debugging information. */
struct drgn_error *drgn_debug_info_find_type(uint64_t kinds, const char *name,
					     size_t name_len,
					     const char *filename, void *arg,
					     struct drgn_qualified_type *ret);

/** @ref drgn_object_finder_ops::find() that uses debugging information. */
struct drgn_error *
drgn_debug_info_find_object(const char *name, size_t name_len,
			    const char *filename,
			    enum drgn_find_object_flags flags, void *arg,
			    struct drgn_object *ret);

struct drgn_elf_file *drgn_module_find_dwarf_file(struct drgn_module *module,
						  Dwarf *dwarf);

struct drgn_error *
drgn_module_create_split_dwarf_file(struct drgn_module *module,
				    const char *name, Dwarf *dwarf,
				    struct drgn_elf_file **ret);

/**
 * Get the Call Frame Information in a @ref drgn_module at a given program
 * counter.
 *
 * @param[in] module Module containing @p pc.
 * @param[in] pc Program counter.
 * @param[out] file_ret Returned file containing CFI.
 * @param[in,out] row_ret Returned CFI row.
 * @param[out] interrupted_ret Whether the found frame interrupted its caller.
 * @param[out] ret_addr_regno_ret Returned return address register number.
 * @return @c NULL on success, non-@c NULL on error. In particular, &@ref
 * drgn_not_found if CFI wasn't found.
 */
struct drgn_error *
drgn_module_find_cfi(struct drgn_program *prog, struct drgn_module *module,
		     uint64_t pc, struct drgn_elf_file **file_ret,
		     struct drgn_cfi_row **row_ret, bool *interrupted_ret,
		     drgn_register_number *ret_addr_regno_ret);

struct drgn_error *open_elf_file(const char *path, int *fd_ret, Elf **elf_ret);

struct drgn_error *find_elf_file(char **path_ret, int *fd_ret, Elf **elf_ret,
				 const char * const *path_formats, ...);

struct drgn_error *elf_address_range(Elf *elf, uint64_t bias,
				     uint64_t *start_ret, uint64_t *end_ret);

/** @} */

#endif /* DRGN_DEBUG_INFO_H */