Brian Silverman | 8649792 | 2018-02-10 19:28:39 -0500 | [diff] [blame] | 1 | /* Internal definitions for libdwfl. |
| 2 | Copyright (C) 2005-2015 Red Hat, Inc. |
| 3 | This file is part of elfutils. |
| 4 | |
| 5 | This file is free software; you can redistribute it and/or modify |
| 6 | it under the terms of either |
| 7 | |
| 8 | * the GNU Lesser General Public License as published by the Free |
| 9 | Software Foundation; either version 3 of the License, or (at |
| 10 | your option) any later version |
| 11 | |
| 12 | or |
| 13 | |
| 14 | * the GNU General Public License as published by the Free |
| 15 | Software Foundation; either version 2 of the License, or (at |
| 16 | your option) any later version |
| 17 | |
| 18 | or both in parallel, as here. |
| 19 | |
| 20 | elfutils is distributed in the hope that it will be useful, but |
| 21 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 23 | General Public License for more details. |
| 24 | |
| 25 | You should have received copies of the GNU General Public License and |
| 26 | the GNU Lesser General Public License along with this program. If |
| 27 | not, see <http://www.gnu.org/licenses/>. */ |
| 28 | |
| 29 | #ifndef _LIBDWFLP_H |
| 30 | #define _LIBDWFLP_H 1 |
| 31 | |
| 32 | #include <libdwfl.h> |
| 33 | #include <libebl.h> |
| 34 | #include <assert.h> |
| 35 | #include <dirent.h> |
| 36 | #include <errno.h> |
| 37 | #include <stdbool.h> |
| 38 | #include <stdlib.h> |
| 39 | #include <string.h> |
| 40 | |
| 41 | #include "../libdw/libdwP.h" /* We need its INTDECLs. */ |
| 42 | #include "../libdwelf/libdwelfP.h" |
| 43 | |
| 44 | typedef struct Dwfl_Process Dwfl_Process; |
| 45 | |
| 46 | /* gettext helper macros. */ |
| 47 | #define _(Str) dgettext ("elfutils", Str) |
| 48 | |
| 49 | #define DWFL_ERRORS \ |
| 50 | DWFL_ERROR (NOERROR, N_("no error")) \ |
| 51 | DWFL_ERROR (UNKNOWN_ERROR, N_("unknown error")) \ |
| 52 | DWFL_ERROR (NOMEM, N_("out of memory")) \ |
| 53 | DWFL_ERROR (ERRNO, N_("See errno")) \ |
| 54 | DWFL_ERROR (LIBELF, N_("See elf_errno")) \ |
| 55 | DWFL_ERROR (LIBDW, N_("See dwarf_errno")) \ |
| 56 | DWFL_ERROR (LIBEBL, N_("See ebl_errno (XXX missing)")) \ |
| 57 | DWFL_ERROR (ZLIB, N_("gzip decompression failed")) \ |
| 58 | DWFL_ERROR (BZLIB, N_("bzip2 decompression failed")) \ |
| 59 | DWFL_ERROR (LZMA, N_("LZMA decompression failed")) \ |
| 60 | DWFL_ERROR (UNKNOWN_MACHINE, N_("no support library found for machine")) \ |
| 61 | DWFL_ERROR (NOREL, N_("Callbacks missing for ET_REL file")) \ |
| 62 | DWFL_ERROR (BADRELTYPE, N_("Unsupported relocation type")) \ |
| 63 | DWFL_ERROR (BADRELOFF, N_("r_offset is bogus")) \ |
| 64 | DWFL_ERROR (BADSTROFF, N_("offset out of range")) \ |
| 65 | DWFL_ERROR (RELUNDEF, N_("relocation refers to undefined symbol")) \ |
| 66 | DWFL_ERROR (CB, N_("Callback returned failure")) \ |
| 67 | DWFL_ERROR (NO_DWARF, N_("No DWARF information found")) \ |
| 68 | DWFL_ERROR (NO_SYMTAB, N_("No symbol table found")) \ |
| 69 | DWFL_ERROR (NO_PHDR, N_("No ELF program headers")) \ |
| 70 | DWFL_ERROR (OVERLAP, N_("address range overlaps an existing module")) \ |
| 71 | DWFL_ERROR (ADDR_OUTOFRANGE, N_("address out of range")) \ |
| 72 | DWFL_ERROR (NO_MATCH, N_("no matching address range")) \ |
| 73 | DWFL_ERROR (TRUNCATED, N_("image truncated")) \ |
| 74 | DWFL_ERROR (ALREADY_ELF, N_("ELF file opened")) \ |
| 75 | DWFL_ERROR (BADELF, N_("not a valid ELF file")) \ |
| 76 | DWFL_ERROR (WEIRD_TYPE, N_("cannot handle DWARF type description")) \ |
| 77 | DWFL_ERROR (WRONG_ID_ELF, N_("ELF file does not match build ID")) \ |
| 78 | DWFL_ERROR (BAD_PRELINK, N_("corrupt .gnu.prelink_undo section data")) \ |
| 79 | DWFL_ERROR (LIBEBL_BAD, N_("Internal error due to ebl")) \ |
| 80 | DWFL_ERROR (CORE_MISSING, N_("Missing data in core file")) \ |
| 81 | DWFL_ERROR (INVALID_REGISTER, N_("Invalid register")) \ |
| 82 | DWFL_ERROR (PROCESS_MEMORY_READ, N_("Error reading process memory")) \ |
| 83 | DWFL_ERROR (PROCESS_NO_ARCH, N_("Couldn't find architecture of any ELF")) \ |
| 84 | DWFL_ERROR (PARSE_PROC, N_("Error parsing /proc filesystem")) \ |
| 85 | DWFL_ERROR (INVALID_DWARF, N_("Invalid DWARF")) \ |
| 86 | DWFL_ERROR (UNSUPPORTED_DWARF, N_("Unsupported DWARF")) \ |
| 87 | DWFL_ERROR (NEXT_THREAD_FAIL, N_("Unable to find more threads")) \ |
| 88 | DWFL_ERROR (ATTACH_STATE_CONFLICT, N_("Dwfl already has attached state")) \ |
| 89 | DWFL_ERROR (NO_ATTACH_STATE, N_("Dwfl has no attached state")) \ |
| 90 | DWFL_ERROR (NO_UNWIND, N_("Unwinding not supported for this architecture")) \ |
| 91 | DWFL_ERROR (INVALID_ARGUMENT, N_("Invalid argument")) \ |
| 92 | DWFL_ERROR (NO_CORE_FILE, N_("Not an ET_CORE ELF file")) |
| 93 | |
| 94 | #define DWFL_ERROR(name, text) DWFL_E_##name, |
| 95 | typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error; |
| 96 | #undef DWFL_ERROR |
| 97 | |
| 98 | #define OTHER_ERROR(name) ((unsigned int) DWFL_E_##name << 16) |
| 99 | #define DWFL_E(name, errno) (OTHER_ERROR (name) | (errno)) |
| 100 | |
| 101 | extern int __libdwfl_canon_error (Dwfl_Error) internal_function; |
| 102 | extern void __libdwfl_seterrno (Dwfl_Error) internal_function; |
| 103 | |
| 104 | /* Resources we might keep for the user about the core file that the |
| 105 | Dwfl might have been created from. Can currently only be set |
| 106 | through std-argp. */ |
| 107 | struct Dwfl_User_Core |
| 108 | { |
| 109 | char *executable_for_core; /* --executable if --core was specified. */ |
| 110 | Elf *core; /* non-NULL if we need to free it. */ |
| 111 | int fd; /* close if >= 0. */ |
| 112 | }; |
| 113 | |
| 114 | struct Dwfl |
| 115 | { |
| 116 | const Dwfl_Callbacks *callbacks; |
| 117 | |
| 118 | Dwfl_Module *modulelist; /* List in order used by full traversals. */ |
| 119 | |
| 120 | Dwfl_Process *process; |
| 121 | Dwfl_Error attacherr; /* Previous error attaching process. */ |
| 122 | |
| 123 | GElf_Addr offline_next_address; |
| 124 | |
| 125 | GElf_Addr segment_align; /* Smallest granularity of segments. */ |
| 126 | |
| 127 | /* Binary search table in three parallel malloc'd arrays. */ |
| 128 | size_t lookup_elts; /* Elements in use. */ |
| 129 | size_t lookup_alloc; /* Elements allococated. */ |
| 130 | GElf_Addr *lookup_addr; /* Start address of segment. */ |
| 131 | Dwfl_Module **lookup_module; /* Module associated with segment, or null. */ |
| 132 | int *lookup_segndx; /* User segment index, or -1. */ |
| 133 | |
| 134 | /* Cache from last dwfl_report_segment call. */ |
| 135 | const void *lookup_tail_ident; |
| 136 | GElf_Off lookup_tail_vaddr; |
| 137 | GElf_Off lookup_tail_offset; |
| 138 | int lookup_tail_ndx; |
| 139 | |
| 140 | struct Dwfl_User_Core *user_core; |
| 141 | }; |
| 142 | |
| 143 | #define OFFLINE_REDZONE 0x10000 |
| 144 | |
| 145 | struct dwfl_file |
| 146 | { |
| 147 | char *name; |
| 148 | int fd; |
| 149 | bool valid; /* The build ID note has been matched. */ |
| 150 | bool relocated; /* Partial relocation of all sections done. */ |
| 151 | |
| 152 | Elf *elf; |
| 153 | |
| 154 | /* This is the lowest p_vaddr in this ELF file, aligned to p_align. |
| 155 | For a file without phdrs, this is zero. */ |
| 156 | GElf_Addr vaddr; |
| 157 | |
| 158 | /* This is an address chosen for synchronization between the main file |
| 159 | and the debug file. See dwfl_module_getdwarf.c for how it's chosen. */ |
| 160 | GElf_Addr address_sync; |
| 161 | }; |
| 162 | |
| 163 | struct Dwfl_Module |
| 164 | { |
| 165 | Dwfl *dwfl; |
| 166 | struct Dwfl_Module *next; /* Link on Dwfl.modulelist. */ |
| 167 | |
| 168 | void *userdata; |
| 169 | |
| 170 | char *name; /* Iterator name for this module. */ |
| 171 | GElf_Addr low_addr, high_addr; |
| 172 | |
| 173 | struct dwfl_file main, debug, aux_sym; |
| 174 | GElf_Addr main_bias; |
| 175 | Ebl *ebl; |
| 176 | GElf_Half e_type; /* GElf_Ehdr.e_type cache. */ |
| 177 | Dwfl_Error elferr; /* Previous failure to open main file. */ |
| 178 | |
| 179 | struct dwfl_relocation *reloc_info; /* Relocatable sections. */ |
| 180 | |
| 181 | struct dwfl_file *symfile; /* Either main or debug. */ |
| 182 | Elf_Data *symdata; /* Data in the ELF symbol table section. */ |
| 183 | Elf_Data *aux_symdata; /* Data in the auxiliary ELF symbol table. */ |
| 184 | size_t syments; /* sh_size / sh_entsize of that section. */ |
| 185 | size_t aux_syments; /* sh_size / sh_entsize of aux_sym section. */ |
| 186 | int first_global; /* Index of first global symbol of table. */ |
| 187 | int aux_first_global; /* Index of first global of aux_sym table. */ |
| 188 | Elf_Data *symstrdata; /* Data for its string table. */ |
| 189 | Elf_Data *aux_symstrdata; /* Data for aux_sym string table. */ |
| 190 | Elf_Data *symxndxdata; /* Data in the extended section index table. */ |
| 191 | Elf_Data *aux_symxndxdata; /* Data in the extended auxiliary table. */ |
| 192 | |
| 193 | Dwarf *dw; /* libdw handle for its debugging info. */ |
| 194 | Dwarf *alt; /* Dwarf used for dwarf_setalt, or NULL. */ |
| 195 | int alt_fd; /* descriptor, only valid when alt != NULL. */ |
| 196 | Elf *alt_elf; /* Elf for alt Dwarf. */ |
| 197 | |
| 198 | Dwfl_Error symerr; /* Previous failure to load symbols. */ |
| 199 | Dwfl_Error dwerr; /* Previous failure to load DWARF. */ |
| 200 | |
| 201 | /* Known CU's in this module. */ |
| 202 | struct dwfl_cu *first_cu, **cu; |
| 203 | |
| 204 | void *lazy_cu_root; /* Table indexed by Dwarf_Off of CU. */ |
| 205 | |
| 206 | struct dwfl_arange *aranges; /* Mapping of addresses in module to CUs. */ |
| 207 | |
| 208 | void *build_id_bits; /* malloc'd copy of build ID bits. */ |
| 209 | GElf_Addr build_id_vaddr; /* Address where they reside, 0 if unknown. */ |
| 210 | int build_id_len; /* -1 for prior failure, 0 if unset. */ |
| 211 | |
| 212 | unsigned int ncu; |
| 213 | unsigned int lazycu; /* Possible users, deleted when none left. */ |
| 214 | unsigned int naranges; |
| 215 | |
| 216 | Dwarf_CFI *dwarf_cfi; /* Cached DWARF CFI for this module. */ |
| 217 | Dwarf_CFI *eh_cfi; /* Cached EH CFI for this module. */ |
| 218 | |
| 219 | int segment; /* Index of first segment table entry. */ |
| 220 | bool gc; /* Mark/sweep flag. */ |
| 221 | bool is_executable; /* Use Dwfl::executable_for_core? */ |
| 222 | }; |
| 223 | |
| 224 | /* This holds information common for all the threads/tasks/TIDs of one process |
| 225 | for backtraces. */ |
| 226 | |
| 227 | struct Dwfl_Process |
| 228 | { |
| 229 | struct Dwfl *dwfl; |
| 230 | pid_t pid; |
| 231 | const Dwfl_Thread_Callbacks *callbacks; |
| 232 | void *callbacks_arg; |
| 233 | struct ebl *ebl; |
| 234 | bool ebl_close:1; |
| 235 | }; |
| 236 | |
| 237 | /* See its typedef in libdwfl.h. */ |
| 238 | |
| 239 | struct Dwfl_Thread |
| 240 | { |
| 241 | Dwfl_Process *process; |
| 242 | pid_t tid; |
| 243 | /* The current frame being unwound. Initially it is the bottom frame. |
| 244 | Later the processed frames get freed and this pointer is updated. */ |
| 245 | Dwfl_Frame *unwound; |
| 246 | void *callbacks_arg; |
| 247 | }; |
| 248 | |
| 249 | /* See its typedef in libdwfl.h. */ |
| 250 | |
| 251 | struct Dwfl_Frame |
| 252 | { |
| 253 | Dwfl_Thread *thread; |
| 254 | /* Previous (outer) frame. */ |
| 255 | Dwfl_Frame *unwound; |
| 256 | bool signal_frame : 1; |
| 257 | bool initial_frame : 1; |
| 258 | enum |
| 259 | { |
| 260 | /* This structure is still being initialized or there was an error |
| 261 | initializing it. */ |
| 262 | DWFL_FRAME_STATE_ERROR, |
| 263 | /* PC field is valid. */ |
| 264 | DWFL_FRAME_STATE_PC_SET, |
| 265 | /* PC field is undefined, this means the next (inner) frame was the |
| 266 | outermost frame. */ |
| 267 | DWFL_FRAME_STATE_PC_UNDEFINED |
| 268 | } pc_state; |
| 269 | /* Either initialized from appropriate REGS element or on some archs |
| 270 | initialized separately as the return address has no DWARF register. */ |
| 271 | Dwarf_Addr pc; |
| 272 | /* (1 << X) bitmask where 0 <= X < ebl_frame_nregs. */ |
| 273 | uint64_t regs_set[3]; |
| 274 | /* REGS array size is ebl_frame_nregs. |
| 275 | REGS_SET tells which of the REGS are valid. */ |
| 276 | Dwarf_Addr regs[]; |
| 277 | }; |
| 278 | |
| 279 | /* Fetch value from Dwfl_Frame->regs indexed by DWARF REGNO. |
| 280 | No error code is set if the function returns FALSE. */ |
| 281 | bool __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, |
| 282 | Dwarf_Addr *val) |
| 283 | internal_function; |
| 284 | |
| 285 | /* Store value to Dwfl_Frame->regs indexed by DWARF REGNO. |
| 286 | No error code is set if the function returns FALSE. */ |
| 287 | bool __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, |
| 288 | Dwarf_Addr val) |
| 289 | internal_function; |
| 290 | |
| 291 | /* Information cached about each CU in Dwfl_Module.dw. */ |
| 292 | struct dwfl_cu |
| 293 | { |
| 294 | /* This caches libdw information about the CU. It's also the |
| 295 | address passed back to users, so we take advantage of the |
| 296 | fact that it's placed first to cast back. */ |
| 297 | Dwarf_Die die; |
| 298 | |
| 299 | Dwfl_Module *mod; /* Pointer back to containing module. */ |
| 300 | |
| 301 | struct dwfl_cu *next; /* CU immediately following in the file. */ |
| 302 | |
| 303 | struct Dwfl_Lines *lines; |
| 304 | }; |
| 305 | |
| 306 | struct Dwfl_Lines |
| 307 | { |
| 308 | struct dwfl_cu *cu; |
| 309 | |
| 310 | /* This is what the opaque Dwfl_Line * pointers we pass to users are. |
| 311 | We need to recover pointers to our struct dwfl_cu and a record in |
| 312 | libdw's Dwarf_Line table. To minimize the memory used in addition |
| 313 | to libdw's Dwarf_Lines buffer, we just point to our own index in |
| 314 | this table, and have one pointer back to the CU. The indices here |
| 315 | match those in libdw's Dwarf_CU.lines->info table. */ |
| 316 | struct Dwfl_Line |
| 317 | { |
| 318 | unsigned int idx; /* My index in the dwfl_cu.lines table. */ |
| 319 | } idx[0]; |
| 320 | }; |
| 321 | |
| 322 | static inline struct dwfl_cu * |
| 323 | dwfl_linecu_inline (const Dwfl_Line *line) |
| 324 | { |
| 325 | const struct Dwfl_Lines *lines = ((const void *) line |
| 326 | - offsetof (struct Dwfl_Lines, |
| 327 | idx[line->idx])); |
| 328 | return lines->cu; |
| 329 | } |
| 330 | #define dwfl_linecu dwfl_linecu_inline |
| 331 | |
| 332 | static inline GElf_Addr |
| 333 | dwfl_adjusted_address (Dwfl_Module *mod, GElf_Addr addr) |
| 334 | { |
| 335 | return addr + mod->main_bias; |
| 336 | } |
| 337 | |
| 338 | static inline GElf_Addr |
| 339 | dwfl_deadjust_address (Dwfl_Module *mod, GElf_Addr addr) |
| 340 | { |
| 341 | return addr - mod->main_bias; |
| 342 | } |
| 343 | |
| 344 | static inline Dwarf_Addr |
| 345 | dwfl_adjusted_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr) |
| 346 | { |
| 347 | return dwfl_adjusted_address (mod, (addr |
| 348 | - mod->debug.address_sync |
| 349 | + mod->main.address_sync)); |
| 350 | } |
| 351 | |
| 352 | static inline Dwarf_Addr |
| 353 | dwfl_deadjust_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr) |
| 354 | { |
| 355 | return (dwfl_deadjust_address (mod, addr) |
| 356 | - mod->main.address_sync |
| 357 | + mod->debug.address_sync); |
| 358 | } |
| 359 | |
| 360 | static inline Dwarf_Addr |
| 361 | dwfl_adjusted_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr) |
| 362 | { |
| 363 | return dwfl_adjusted_address (mod, (addr |
| 364 | - mod->aux_sym.address_sync |
| 365 | + mod->main.address_sync)); |
| 366 | } |
| 367 | |
| 368 | static inline Dwarf_Addr |
| 369 | dwfl_deadjust_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr) |
| 370 | { |
| 371 | return (dwfl_deadjust_address (mod, addr) |
| 372 | - mod->main.address_sync |
| 373 | + mod->aux_sym.address_sync); |
| 374 | } |
| 375 | |
| 376 | static inline GElf_Addr |
| 377 | dwfl_adjusted_st_value (Dwfl_Module *mod, Elf *symelf, GElf_Addr addr) |
| 378 | { |
| 379 | if (symelf == mod->main.elf) |
| 380 | return dwfl_adjusted_address (mod, addr); |
| 381 | if (symelf == mod->debug.elf) |
| 382 | return dwfl_adjusted_dwarf_addr (mod, addr); |
| 383 | return dwfl_adjusted_aux_sym_addr (mod, addr); |
| 384 | } |
| 385 | |
| 386 | static inline GElf_Addr |
| 387 | dwfl_deadjust_st_value (Dwfl_Module *mod, Elf *symelf, GElf_Addr addr) |
| 388 | { |
| 389 | if (symelf == mod->main.elf) |
| 390 | return dwfl_deadjust_address (mod, addr); |
| 391 | if (symelf == mod->debug.elf) |
| 392 | return dwfl_deadjust_dwarf_addr (mod, addr); |
| 393 | return dwfl_deadjust_aux_sym_addr (mod, addr); |
| 394 | } |
| 395 | |
| 396 | /* This describes a contiguous address range that lies in a single CU. |
| 397 | We condense runs of Dwarf_Arange entries for the same CU into this. */ |
| 398 | struct dwfl_arange |
| 399 | { |
| 400 | struct dwfl_cu *cu; |
| 401 | size_t arange; /* Index in Dwarf_Aranges. */ |
| 402 | }; |
| 403 | |
| 404 | |
| 405 | /* Structure used for keeping track of ptrace attaching a thread. |
| 406 | Shared by linux-pid-attach and linux-proc-maps. If it has been setup |
| 407 | then get the instance through __libdwfl_get_pid_arg. */ |
| 408 | struct __libdwfl_pid_arg |
| 409 | { |
| 410 | /* /proc/PID/task/. */ |
| 411 | DIR *dir; |
| 412 | /* Elf for /proc/PID/exe. Set to NULL if it couldn't be opened. */ |
| 413 | Elf *elf; |
| 414 | /* fd for /proc/PID/exe. Set to -1 if it couldn't be opened. */ |
| 415 | int elf_fd; |
| 416 | /* It is 0 if not used. */ |
| 417 | pid_t tid_attached; |
| 418 | /* Valid only if TID_ATTACHED is not zero. */ |
| 419 | bool tid_was_stopped; |
| 420 | /* True if threads are ptrace stopped by caller. */ |
| 421 | bool assume_ptrace_stopped; |
| 422 | }; |
| 423 | |
| 424 | /* If DWfl is not NULL and a Dwfl_Process has been setup that has |
| 425 | Dwfl_Thread_Callbacks set to pid_thread_callbacks, then return the |
| 426 | callbacks_arg, which will be a struct __libdwfl_pid_arg. Otherwise |
| 427 | returns NULL. */ |
| 428 | extern struct __libdwfl_pid_arg *__libdwfl_get_pid_arg (Dwfl *dwfl) |
| 429 | internal_function; |
| 430 | |
| 431 | /* Makes sure the given tid is attached. On success returns true and |
| 432 | sets tid_was_stopped. */ |
| 433 | extern bool __libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp) |
| 434 | internal_function; |
| 435 | |
| 436 | /* Detaches a tid that was attached through |
| 437 | __libdwfl_ptrace_attach. Must be given the tid_was_stopped as set |
| 438 | by __libdwfl_ptrace_attach. */ |
| 439 | extern void __libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped) |
| 440 | internal_function; |
| 441 | |
| 442 | |
| 443 | /* Internal wrapper for old dwfl_module_getsym and new dwfl_module_getsym_info. |
| 444 | adjust_st_value set to true returns adjusted SYM st_value, set to false |
| 445 | it will not adjust SYM at all, but does match against resolved *ADDR. */ |
| 446 | extern const char *__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, |
| 447 | GElf_Addr *addr, GElf_Word *shndxp, |
| 448 | Elf **elfp, Dwarf_Addr *biasp, |
| 449 | bool *resolved, bool adjust_st_value) |
| 450 | internal_function; |
| 451 | |
| 452 | /* Internal wrapper for old dwfl_module_addrsym and new dwfl_module_addrinfo. |
| 453 | adjust_st_value set to true returns adjusted SYM st_value, set to false |
| 454 | it will not adjust SYM at all, but does match against resolved values. */ |
| 455 | extern const char *__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, |
| 456 | GElf_Off *off, GElf_Sym *sym, |
| 457 | GElf_Word *shndxp, Elf **elfp, |
| 458 | Dwarf_Addr *bias, |
| 459 | bool adjust_st_value) internal_function; |
| 460 | |
| 461 | extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function; |
| 462 | |
| 463 | /* Find the main ELF file, update MOD->elferr and/or MOD->main.elf. */ |
| 464 | extern void __libdwfl_getelf (Dwfl_Module *mod) internal_function; |
| 465 | |
| 466 | /* Process relocations in debugging sections in an ET_REL file. |
| 467 | FILE must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ, |
| 468 | to make it possible to relocate the data in place (or ELF_C_RDWR or |
| 469 | ELF_C_RDWR_MMAP if you intend to modify the Elf file on disk). After |
| 470 | this, dwarf_begin_elf on FILE will read the relocated data. |
| 471 | |
| 472 | When DEBUG is false, apply partial relocation to all sections. */ |
| 473 | extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug) |
| 474 | internal_function; |
| 475 | |
| 476 | /* Find the section index in mod->main.elf that contains the given |
| 477 | *ADDR. Adjusts *ADDR to be section relative on success, returns |
| 478 | SHN_UNDEF on failure. */ |
| 479 | extern size_t __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr) |
| 480 | internal_function; |
| 481 | |
| 482 | /* Process (simple) relocations in arbitrary section TSCN of an ET_REL file. |
| 483 | RELOCSCN is SHT_REL or SHT_RELA and TSCN is its sh_info target section. */ |
| 484 | extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated, |
| 485 | Elf_Scn *relocscn, Elf_Scn *tscn, |
| 486 | bool partial) |
| 487 | internal_function; |
| 488 | |
| 489 | /* Adjust *VALUE from section-relative to absolute. |
| 490 | MOD->dwfl->callbacks->section_address is called to determine the actual |
| 491 | address of a loaded section. */ |
| 492 | extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, |
| 493 | size_t *shstrndx_cache, |
| 494 | Elf32_Word shndx, |
| 495 | GElf_Addr *value) |
| 496 | internal_function; |
| 497 | |
| 498 | /* Ensure that MOD->ebl is set up. */ |
| 499 | extern Dwfl_Error __libdwfl_module_getebl (Dwfl_Module *mod) internal_function; |
| 500 | |
| 501 | /* Install a new Dwarf_CFI in *SLOT (MOD->eh_cfi or MOD->dwarf_cfi). */ |
| 502 | extern Dwarf_CFI *__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot, |
| 503 | Dwarf_CFI *cfi) |
| 504 | internal_function; |
| 505 | |
| 506 | /* Iterate through all the CU's in the module. Start by passing a null |
| 507 | LASTCU, and then pass the last *CU returned. Success return with null |
| 508 | *CU no more CUs. */ |
| 509 | extern Dwfl_Error __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu, |
| 510 | struct dwfl_cu **cu) internal_function; |
| 511 | |
| 512 | /* Find the CU by address. */ |
| 513 | extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, |
| 514 | struct dwfl_cu **cu) internal_function; |
| 515 | |
| 516 | /* Ensure that CU->lines (and CU->cu->lines) is set up. */ |
| 517 | extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu) |
| 518 | internal_function; |
| 519 | |
| 520 | /* Look in ELF for an NT_GNU_BUILD_ID note. Store it to BUILD_ID_BITS, |
| 521 | its vaddr in ELF to BUILD_ID_VADDR (it is unrelocated, even if MOD is not |
| 522 | NULL) and store length to BUILD_ID_LEN. Returns -1 for errors, 1 if it was |
| 523 | stored and 0 if no note is found. MOD may be NULL, MOD must be non-NULL |
| 524 | only if ELF is ET_REL. */ |
| 525 | extern int __libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf, |
| 526 | const void **build_id_bits, |
| 527 | GElf_Addr *build_id_elfaddr, |
| 528 | int *build_id_len) |
| 529 | internal_function; |
| 530 | |
| 531 | /* Look in ELF for an NT_GNU_BUILD_ID note. If SET is true, store it |
| 532 | in MOD and return its length. If SET is false, instead compare it |
| 533 | to that stored in MOD and return 2 if they match, 1 if they do not. |
| 534 | Returns -1 for errors, 0 if no note is found. */ |
| 535 | extern int __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) |
| 536 | internal_function; |
| 537 | |
| 538 | /* Open a main or debuginfo file by its build ID, returns the fd. */ |
| 539 | extern int __libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, |
| 540 | char **file_name) internal_function; |
| 541 | |
| 542 | /* Same, but takes an explicit build_id, can also be used for alt debug. */ |
| 543 | extern int __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, |
| 544 | char **file_name, const size_t id_len, |
| 545 | const uint8_t *id) internal_function; |
| 546 | |
| 547 | extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len) |
| 548 | attribute_hidden; |
| 549 | extern int __libdwfl_crc32_file (int fd, uint32_t *resp) attribute_hidden; |
| 550 | |
| 551 | |
| 552 | /* Given ELF and some parameters return TRUE if the *P return value parameters |
| 553 | have been successfully filled in. Any of the *P parameters can be NULL. */ |
| 554 | extern bool __libdwfl_elf_address_range (Elf *elf, GElf_Addr base, |
| 555 | bool add_p_vaddr, bool sanity, |
| 556 | GElf_Addr *vaddrp, |
| 557 | GElf_Addr *address_syncp, |
| 558 | GElf_Addr *startp, GElf_Addr *endp, |
| 559 | GElf_Addr *biasp, GElf_Half *e_typep) |
| 560 | internal_function; |
| 561 | |
| 562 | /* Meat of dwfl_report_elf, given elf_begin just called. |
| 563 | Consumes ELF on success, not on failure. */ |
| 564 | extern Dwfl_Module *__libdwfl_report_elf (Dwfl *dwfl, const char *name, |
| 565 | const char *file_name, int fd, |
| 566 | Elf *elf, GElf_Addr base, |
| 567 | bool add_p_vaddr, bool sanity) |
| 568 | internal_function; |
| 569 | |
| 570 | /* Meat of dwfl_report_offline. */ |
| 571 | extern Dwfl_Module *__libdwfl_report_offline (Dwfl *dwfl, const char *name, |
| 572 | const char *file_name, |
| 573 | int fd, bool closefd, |
| 574 | int (*predicate) (const char *, |
| 575 | const char *)) |
| 576 | internal_function; |
| 577 | |
| 578 | /* Free PROCESS. Unlink and free also any structures it references. */ |
| 579 | extern void __libdwfl_process_free (Dwfl_Process *process) |
| 580 | internal_function; |
| 581 | |
| 582 | /* Update STATE->unwound for the unwound frame. |
| 583 | On error STATE->unwound == NULL |
| 584 | or STATE->unwound->pc_state == DWFL_FRAME_STATE_ERROR; |
| 585 | in such case dwfl_errno () is set. |
| 586 | If STATE->unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED |
| 587 | then STATE was the last valid frame. */ |
| 588 | extern void __libdwfl_frame_unwind (Dwfl_Frame *state) |
| 589 | internal_function; |
| 590 | |
| 591 | /* Align segment START downwards or END upwards addresses according to DWFL. */ |
| 592 | extern GElf_Addr __libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start) |
| 593 | internal_function; |
| 594 | extern GElf_Addr __libdwfl_segment_end (Dwfl *dwfl, GElf_Addr end) |
| 595 | internal_function; |
| 596 | |
| 597 | /* Decompression wrappers: decompress whole file into memory. */ |
| 598 | extern Dwfl_Error __libdw_gunzip (int fd, off_t start_offset, |
| 599 | void *mapped, size_t mapped_size, |
| 600 | void **whole, size_t *whole_size) |
| 601 | internal_function; |
| 602 | extern Dwfl_Error __libdw_bunzip2 (int fd, off_t start_offset, |
| 603 | void *mapped, size_t mapped_size, |
| 604 | void **whole, size_t *whole_size) |
| 605 | internal_function; |
| 606 | extern Dwfl_Error __libdw_unlzma (int fd, off_t start_offset, |
| 607 | void *mapped, size_t mapped_size, |
| 608 | void **whole, size_t *whole_size) |
| 609 | internal_function; |
| 610 | |
| 611 | /* Skip the image header before a file image: updates *START_OFFSET. */ |
| 612 | extern Dwfl_Error __libdw_image_header (int fd, off_t *start_offset, |
| 613 | void *mapped, size_t mapped_size) |
| 614 | internal_function; |
| 615 | |
| 616 | /* Open Elf handle on *FDP. This handles decompression and checks |
| 617 | elf_kind. Succeed only for ELF_K_ELF, or also ELF_K_AR if ARCHIVE_OK. |
| 618 | Returns DWFL_E_NOERROR and sets *ELFP on success, resets *FDP to -1 if |
| 619 | it's no longer used. Resets *FDP on failure too iff CLOSE_ON_FAIL. */ |
| 620 | extern Dwfl_Error __libdw_open_file (int *fdp, Elf **elfp, |
| 621 | bool close_on_fail, bool archive_ok) |
| 622 | internal_function; |
| 623 | |
| 624 | /* Fetch PT_DYNAMIC P_VADDR from ELF and store it to *VADDRP. Return success. |
| 625 | *VADDRP is not modified if the function fails. */ |
| 626 | extern bool __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp) |
| 627 | internal_function; |
| 628 | |
| 629 | /* These are working nicely for --core, but are not ready to be |
| 630 | exported interfaces quite yet. */ |
| 631 | |
| 632 | /* Type of callback function ... |
| 633 | */ |
| 634 | typedef bool Dwfl_Memory_Callback (Dwfl *dwfl, int segndx, |
| 635 | void **buffer, size_t *buffer_available, |
| 636 | GElf_Addr vaddr, size_t minread, void *arg); |
| 637 | |
| 638 | /* Type of callback function ... |
| 639 | */ |
| 640 | typedef bool Dwfl_Module_Callback (Dwfl_Module *mod, void **userdata, |
| 641 | const char *name, Dwarf_Addr base, |
| 642 | void **buffer, size_t *buffer_available, |
| 643 | GElf_Off cost, GElf_Off worthwhile, |
| 644 | GElf_Off whole, GElf_Off contiguous, |
| 645 | void *arg, Elf **elfp); |
| 646 | |
| 647 | /* One shared library (or executable) info from DT_DEBUG link map. */ |
| 648 | struct r_debug_info_module |
| 649 | { |
| 650 | struct r_debug_info_module *next; |
| 651 | /* FD is -1 iff ELF is NULL. */ |
| 652 | int fd; |
| 653 | Elf *elf; |
| 654 | GElf_Addr l_ld; |
| 655 | /* START and END are both zero if not valid. */ |
| 656 | GElf_Addr start, end; |
| 657 | bool disk_file_has_build_id; |
| 658 | char name[0]; |
| 659 | }; |
| 660 | |
| 661 | /* Information gathered from DT_DEBUG by dwfl_link_map_report hinted to |
| 662 | dwfl_segment_report_module. */ |
| 663 | struct r_debug_info |
| 664 | { |
| 665 | struct r_debug_info_module *module; |
| 666 | }; |
| 667 | |
| 668 | /* ... |
| 669 | */ |
| 670 | extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, |
| 671 | Dwfl_Memory_Callback *memory_callback, |
| 672 | void *memory_callback_arg, |
| 673 | Dwfl_Module_Callback *read_eagerly, |
| 674 | void *read_eagerly_arg, |
| 675 | const void *note_file, |
| 676 | size_t note_file_size, |
| 677 | const struct r_debug_info *r_debug_info); |
| 678 | |
| 679 | /* Report a module for entry in the dynamic linker's struct link_map list. |
| 680 | For each link_map entry, if an existing module resides at its address, |
| 681 | this just modifies that module's name and suggested file name. If |
| 682 | no such module exists, this calls dwfl_report_elf on the l_name string. |
| 683 | |
| 684 | If AUXV is not null, it points to AUXV_SIZE bytes of auxiliary vector |
| 685 | data as contained in an NT_AUXV note or read from a /proc/pid/auxv |
| 686 | file. When this is available, it guides the search. If AUXV is null |
| 687 | or the memory it points to is not accessible, then this search can |
| 688 | only find where to begin if the correct executable file was |
| 689 | previously reported and preloaded as with dwfl_report_elf. |
| 690 | |
| 691 | Fill in R_DEBUG_INFO if it is not NULL. It should be cleared by the |
| 692 | caller, this function does not touch fields it does not need to modify. |
| 693 | If R_DEBUG_INFO is not NULL then no modules get added to DWFL, caller |
| 694 | has to add them from filled in R_DEBUG_INFO. |
| 695 | |
| 696 | Returns the number of modules found, or -1 for errors. */ |
| 697 | extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, |
| 698 | Dwfl_Memory_Callback *memory_callback, |
| 699 | void *memory_callback_arg, |
| 700 | struct r_debug_info *r_debug_info); |
| 701 | |
| 702 | |
| 703 | /* Avoid PLT entries. */ |
| 704 | INTDECL (dwfl_begin) |
| 705 | INTDECL (dwfl_errmsg) |
| 706 | INTDECL (dwfl_errno) |
| 707 | INTDECL (dwfl_addrmodule) |
| 708 | INTDECL (dwfl_addrsegment) |
| 709 | INTDECL (dwfl_addrdwarf) |
| 710 | INTDECL (dwfl_addrdie) |
| 711 | INTDECL (dwfl_core_file_attach) |
| 712 | INTDECL (dwfl_core_file_report) |
| 713 | INTDECL (dwfl_getmodules) |
| 714 | INTDECL (dwfl_module_addrdie) |
| 715 | INTDECL (dwfl_module_address_section) |
| 716 | INTDECL (dwfl_module_addrinfo) |
| 717 | INTDECL (dwfl_module_addrsym) |
| 718 | INTDECL (dwfl_module_build_id) |
| 719 | INTDECL (dwfl_module_getdwarf) |
| 720 | INTDECL (dwfl_module_getelf) |
| 721 | INTDECL (dwfl_module_getsym) |
| 722 | INTDECL (dwfl_module_getsym_info) |
| 723 | INTDECL (dwfl_module_getsymtab) |
| 724 | INTDECL (dwfl_module_getsymtab_first_global) |
| 725 | INTDECL (dwfl_module_getsrc) |
| 726 | INTDECL (dwfl_module_report_build_id) |
| 727 | INTDECL (dwfl_report_elf) |
| 728 | INTDECL (dwfl_report_begin) |
| 729 | INTDECL (dwfl_report_begin_add) |
| 730 | INTDECL (dwfl_report_module) |
| 731 | INTDECL (dwfl_report_segment) |
| 732 | INTDECL (dwfl_report_offline) |
| 733 | INTDECL (dwfl_report_end) |
| 734 | INTDECL (dwfl_build_id_find_elf) |
| 735 | INTDECL (dwfl_build_id_find_debuginfo) |
| 736 | INTDECL (dwfl_standard_find_debuginfo) |
| 737 | INTDECL (dwfl_link_map_report) |
| 738 | INTDECL (dwfl_linux_kernel_find_elf) |
| 739 | INTDECL (dwfl_linux_kernel_module_section_address) |
| 740 | INTDECL (dwfl_linux_proc_attach) |
| 741 | INTDECL (dwfl_linux_proc_report) |
| 742 | INTDECL (dwfl_linux_proc_maps_report) |
| 743 | INTDECL (dwfl_linux_proc_find_elf) |
| 744 | INTDECL (dwfl_linux_kernel_report_kernel) |
| 745 | INTDECL (dwfl_linux_kernel_report_modules) |
| 746 | INTDECL (dwfl_linux_kernel_report_offline) |
| 747 | INTDECL (dwfl_offline_section_address) |
| 748 | INTDECL (dwfl_module_relocate_address) |
| 749 | INTDECL (dwfl_module_dwarf_cfi) |
| 750 | INTDECL (dwfl_module_eh_cfi) |
| 751 | INTDECL (dwfl_attach_state) |
| 752 | INTDECL (dwfl_pid) |
| 753 | INTDECL (dwfl_thread_dwfl) |
| 754 | INTDECL (dwfl_thread_tid) |
| 755 | INTDECL (dwfl_frame_thread) |
| 756 | INTDECL (dwfl_thread_state_registers) |
| 757 | INTDECL (dwfl_thread_state_register_pc) |
| 758 | INTDECL (dwfl_getthread_frames) |
| 759 | INTDECL (dwfl_getthreads) |
| 760 | INTDECL (dwfl_thread_getframes) |
| 761 | INTDECL (dwfl_frame_pc) |
| 762 | |
| 763 | /* Leading arguments standard to callbacks passed a Dwfl_Module. */ |
| 764 | #define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr |
| 765 | #define CBFAIL (errno ? DWFL_E (ERRNO, errno) : DWFL_E_CB); |
| 766 | |
| 767 | |
| 768 | /* The default used by dwfl_standard_find_debuginfo. */ |
| 769 | #define DEFAULT_DEBUGINFO_PATH ":.debug:/usr/lib/debug" |
| 770 | |
| 771 | |
| 772 | #endif /* libdwflP.h */ |