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 */
|