diff options
Diffstat (limited to 'src/libdwfl/libdwflP.h')
-rw-r--r-- | src/libdwfl/libdwflP.h | 356 |
1 files changed, 302 insertions, 54 deletions
diff --git a/src/libdwfl/libdwflP.h b/src/libdwfl/libdwflP.h index bca82d2e..12ee116e 100644 --- a/src/libdwfl/libdwflP.h +++ b/src/libdwfl/libdwflP.h @@ -1,51 +1,30 @@ /* Internal definitions for libdwfl. - Copyright (C) 2005-2011 Red Hat, Inc. - This file is part of Red Hat elfutils. + Copyright (C) 2005-2014 Red Hat, Inc. + This file is part of elfutils. - Red Hat elfutils is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by the - Free Software Foundation; version 2 of the License. + This file is free software; you can redistribute it and/or modify + it under the terms of either - Red Hat elfutils is distributed in the hope that it will be useful, but + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with Red Hat elfutils; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. - - In addition, as a special exception, Red Hat, Inc. gives You the - additional right to link the code of Red Hat elfutils with code licensed - under any Open Source Initiative certified open source license - (http://www.opensource.org/licenses/index.php) which requires the - distribution of source code with any binary distribution and to - distribute linked combinations of the two. Non-GPL Code permitted under - this exception must only link to the code of Red Hat elfutils through - those well defined interfaces identified in the file named EXCEPTION - found in the source code files (the "Approved Interfaces"). The files - of Non-GPL Code may instantiate templates or use macros or inline - functions from the Approved Interfaces without causing the resulting - work to be covered by the GNU General Public License. Only Red Hat, - Inc. may make changes or additions to the list of Approved Interfaces. - Red Hat's grant of this exception is conditioned upon your not adding - any new exceptions. If you wish to add a new Approved Interface or - exception, please contact Red Hat. You must obey the GNU General Public - License in all respects for all of the Red Hat elfutils code and other - code used in conjunction with Red Hat elfutils except the Non-GPL Code - covered by this exception. If you modify this file, you may extend this - exception to your version of the file, but you are not obligated to do - so. If you do not wish to provide this exception without modification, - you must delete this exception statement from your version and license - this file solely under the GPL without exception. - - Red Hat elfutils is an included package of the Open Invention Network. - An included package of the Open Invention Network is a package for which - Open Invention Network licensees cross-license their patents. No patent - license is granted, either expressly or impliedly, by designation as an - included package. Should you wish to participate in the Open Invention - Network licensing program, please visit www.openinventionnetwork.com - <http://www.openinventionnetwork.com>. */ + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ #ifndef _LIBDWFLP_H #define _LIBDWFLP_H 1 @@ -56,12 +35,16 @@ #include <libdwfl.h> #include <libebl.h> #include <assert.h> +#include <dirent.h> #include <errno.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include "../libdw/libdwP.h" /* We need its INTDECLs. */ +#include "../libdwelf/libdwelfP.h" + +typedef struct Dwfl_Process Dwfl_Process; /* gettext helper macros. */ #define _(Str) dgettext ("elfutils", Str) @@ -95,7 +78,21 @@ DWFL_ERROR (BADELF, N_("not a valid ELF file")) \ DWFL_ERROR (WEIRD_TYPE, N_("cannot handle DWARF type description")) \ DWFL_ERROR (WRONG_ID_ELF, N_("ELF file does not match build ID")) \ - DWFL_ERROR (BAD_PRELINK, N_("corrupt .gnu.prelink_undo section data")) + DWFL_ERROR (BAD_PRELINK, N_("corrupt .gnu.prelink_undo section data")) \ + DWFL_ERROR (LIBEBL_BAD, N_("Internal error due to ebl")) \ + DWFL_ERROR (CORE_MISSING, N_("Missing data in core file")) \ + DWFL_ERROR (INVALID_REGISTER, N_("Invalid register")) \ + DWFL_ERROR (PROCESS_MEMORY_READ, N_("Error reading process memory")) \ + DWFL_ERROR (PROCESS_NO_ARCH, N_("Couldn't find architecture of any ELF")) \ + DWFL_ERROR (PARSE_PROC, N_("Error parsing /proc filesystem")) \ + DWFL_ERROR (INVALID_DWARF, N_("Invalid DWARF")) \ + DWFL_ERROR (UNSUPPORTED_DWARF, N_("Unsupported DWARF")) \ + DWFL_ERROR (NEXT_THREAD_FAIL, N_("Unable to find more threads")) \ + DWFL_ERROR (ATTACH_STATE_CONFLICT, N_("Dwfl already has attached state")) \ + DWFL_ERROR (NO_ATTACH_STATE, N_("Dwfl has no attached state")) \ + DWFL_ERROR (NO_UNWIND, N_("Unwinding not supported for this architecture")) \ + DWFL_ERROR (INVALID_ARGUMENT, N_("Invalid argument")) \ + DWFL_ERROR (NO_CORE_FILE, N_("Not an ET_CORE ELF file")) #define DWFL_ERROR(name, text) DWFL_E_##name, typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error; @@ -113,6 +110,9 @@ struct Dwfl Dwfl_Module *modulelist; /* List in order used by full traversals. */ + Dwfl_Process *process; + Dwfl_Error attacherr; /* Previous error attaching process. */ + GElf_Addr offline_next_address; GElf_Addr segment_align; /* Smallest granularity of segments. */ @@ -129,6 +129,8 @@ struct Dwfl GElf_Off lookup_tail_vaddr; GElf_Off lookup_tail_offset; int lookup_tail_ndx; + + char *executable_for_core; /* --executable if --core was specified. */ }; #define OFFLINE_REDZONE 0x10000 @@ -161,7 +163,7 @@ struct Dwfl_Module char *name; /* Iterator name for this module. */ GElf_Addr low_addr, high_addr; - struct dwfl_file main, debug; + struct dwfl_file main, debug, aux_sym; GElf_Addr main_bias; Ebl *ebl; GElf_Half e_type; /* GElf_Ehdr.e_type cache. */ @@ -171,12 +173,20 @@ struct Dwfl_Module struct dwfl_file *symfile; /* Either main or debug. */ Elf_Data *symdata; /* Data in the ELF symbol table section. */ + Elf_Data *aux_symdata; /* Data in the auxiliary ELF symbol table. */ size_t syments; /* sh_size / sh_entsize of that section. */ + size_t aux_syments; /* sh_size / sh_entsize of aux_sym section. */ int first_global; /* Index of first global symbol of table. */ + int aux_first_global; /* Index of first global of aux_sym table. */ Elf_Data *symstrdata; /* Data for its string table. */ + Elf_Data *aux_symstrdata; /* Data for aux_sym string table. */ Elf_Data *symxndxdata; /* Data in the extended section index table. */ + Elf_Data *aux_symxndxdata; /* Data in the extended auxiliary table. */ Dwarf *dw; /* libdw handle for its debugging info. */ + Dwarf *alt; /* Dwarf used for dwarf_setalt, or NULL. */ + int alt_fd; /* descriptor, only valid when alt != NULL. */ + Elf *alt_elf; /* Elf for alt Dwarf. */ Dwfl_Error symerr; /* Previous failure to load symbols. */ Dwfl_Error dwerr; /* Previous failure to load DWARF. */ @@ -201,9 +211,75 @@ struct Dwfl_Module int segment; /* Index of first segment table entry. */ bool gc; /* Mark/sweep flag. */ + bool is_executable; /* Use Dwfl::executable_for_core? */ +}; + +/* This holds information common for all the threads/tasks/TIDs of one process + for backtraces. */ + +struct Dwfl_Process +{ + struct Dwfl *dwfl; + pid_t pid; + const Dwfl_Thread_Callbacks *callbacks; + void *callbacks_arg; + struct ebl *ebl; + bool ebl_close:1; +}; + +/* See its typedef in libdwfl.h. */ + +struct Dwfl_Thread +{ + Dwfl_Process *process; + pid_t tid; + /* The current frame being unwound. Initially it is the bottom frame. + Later the processed frames get freed and this pointer is updated. */ + Dwfl_Frame *unwound; + void *callbacks_arg; +}; + +/* See its typedef in libdwfl.h. */ + +struct Dwfl_Frame +{ + Dwfl_Thread *thread; + /* Previous (outer) frame. */ + Dwfl_Frame *unwound; + bool signal_frame : 1; + bool initial_frame : 1; + enum + { + /* This structure is still being initialized or there was an error + initializing it. */ + DWFL_FRAME_STATE_ERROR, + /* PC field is valid. */ + DWFL_FRAME_STATE_PC_SET, + /* PC field is undefined, this means the next (inner) frame was the + outermost frame. */ + DWFL_FRAME_STATE_PC_UNDEFINED + } pc_state; + /* Either initialized from appropriate REGS element or on some archs + initialized separately as the return address has no DWARF register. */ + Dwarf_Addr pc; + /* (1 << X) bitmask where 0 <= X < ebl_frame_nregs. */ + uint64_t regs_set[3]; + /* REGS array size is ebl_frame_nregs. + REGS_SET tells which of the REGS are valid. */ + Dwarf_Addr regs[]; }; +/* Fetch value from Dwfl_Frame->regs indexed by DWARF REGNO. + No error code is set if the function returns FALSE. */ +bool __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, + Dwarf_Addr *val) + internal_function; +/* Store value to Dwfl_Frame->regs indexed by DWARF REGNO. + No error code is set if the function returns FALSE. */ +bool __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, + Dwarf_Addr val) + internal_function; /* Information cached about each CU in Dwfl_Module.dw. */ struct dwfl_cu @@ -274,20 +350,40 @@ dwfl_deadjust_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr) + mod->debug.address_sync); } +static inline Dwarf_Addr +dwfl_adjusted_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr) +{ + return dwfl_adjusted_address (mod, (addr + - mod->aux_sym.address_sync + + mod->main.address_sync)); +} + +static inline Dwarf_Addr +dwfl_deadjust_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr) +{ + return (dwfl_deadjust_address (mod, addr) + - mod->main.address_sync + + mod->aux_sym.address_sync); +} + static inline GElf_Addr -dwfl_adjusted_st_value (Dwfl_Module *mod, GElf_Addr addr) +dwfl_adjusted_st_value (Dwfl_Module *mod, Elf *symelf, GElf_Addr addr) { - if (mod->symfile == &mod->main) + if (symelf == mod->main.elf) return dwfl_adjusted_address (mod, addr); - return dwfl_adjusted_dwarf_addr (mod, addr); + if (symelf == mod->debug.elf) + return dwfl_adjusted_dwarf_addr (mod, addr); + return dwfl_adjusted_aux_sym_addr (mod, addr); } static inline GElf_Addr -dwfl_deadjust_st_value (Dwfl_Module *mod, GElf_Addr addr) +dwfl_deadjust_st_value (Dwfl_Module *mod, Elf *symelf, GElf_Addr addr) { - if (mod->symfile == &mod->main) + if (symelf == mod->main.elf) return dwfl_deadjust_address (mod, addr); - return dwfl_deadjust_dwarf_addr (mod, addr); + if (symelf == mod->debug.elf) + return dwfl_deadjust_dwarf_addr (mod, addr); + return dwfl_deadjust_aux_sym_addr (mod, addr); } /* This describes a contiguous address range that lies in a single CU. @@ -299,6 +395,56 @@ struct dwfl_arange }; +/* Structure used for keeping track of ptrace attaching a thread. + Shared by linux-pid-attach and linux-proc-maps. If it has been setup + then get the instance through __libdwfl_get_pid_arg. */ +struct __libdwfl_pid_arg +{ + DIR *dir; + /* It is 0 if not used. */ + pid_t tid_attached; + /* Valid only if TID_ATTACHED is not zero. */ + bool tid_was_stopped; + /* True if threads are ptrace stopped by caller. */ + bool assume_ptrace_stopped; +}; + +/* If DWfl is not NULL and a Dwfl_Process has been setup that has + Dwfl_Thread_Callbacks set to pid_thread_callbacks, then return the + callbacks_arg, which will be a struct __libdwfl_pid_arg. Otherwise + returns NULL. */ +extern struct __libdwfl_pid_arg *__libdwfl_get_pid_arg (Dwfl *dwfl) + internal_function; + +/* Makes sure the given tid is attached. On success returns true and + sets tid_was_stopped. */ +extern bool __libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp) + internal_function; + +/* Detaches a tid that was attached through + __libdwfl_ptrace_attach. Must be given the tid_was_stopped as set + by __libdwfl_ptrace_attach. */ +extern void __libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped) + internal_function; + + +/* Internal wrapper for old dwfl_module_getsym and new dwfl_module_getsym_info. + adjust_st_value set to true returns adjusted SYM st_value, set to false + it will not adjust SYM at all, but does match against resolved *ADDR. */ +extern const char *__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, + GElf_Addr *addr, GElf_Word *shndxp, + Elf **elfp, Dwarf_Addr *biasp, + bool *resolved, bool adjust_st_value) + internal_function; + +/* Internal wrapper for old dwfl_module_addrsym and new dwfl_module_addrinfo. + adjust_st_value set to true returns adjusted SYM st_value, set to false + it will not adjust SYM at all, but does match against resolved values. */ +extern const char *__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, + GElf_Off *off, GElf_Sym *sym, + GElf_Word *shndxp, Elf **elfp, + Dwarf_Addr *bias, + bool adjust_st_value) internal_function; extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function; @@ -315,6 +461,12 @@ extern void __libdwfl_getelf (Dwfl_Module *mod) internal_function; extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug) internal_function; +/* Find the section index in mod->main.elf that contains the given + *ADDR. Adjusts *ADDR to be section relative on success, returns + SHN_UNDEF on failure. */ +extern size_t __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr) + internal_function; + /* Process (simple) relocations in arbitrary section TSCN of an ET_REL file. RELOCSCN is SHT_REL or SHT_RELA and TSCN is its sh_info target section. */ extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated, @@ -331,7 +483,6 @@ extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, GElf_Addr *value) internal_function; - /* Ensure that MOD->ebl is set up. */ extern Dwfl_Error __libdwfl_module_getebl (Dwfl_Module *mod) internal_function; @@ -354,6 +505,17 @@ extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu) internal_function; +/* Look in ELF for an NT_GNU_BUILD_ID note. Store it to BUILD_ID_BITS, + its vaddr in ELF to BUILD_ID_VADDR (it is unrelocated, even if MOD is not + NULL) and store length to BUILD_ID_LEN. Returns -1 for errors, 1 if it was + stored and 0 if no note is found. MOD may be NULL, MOD must be non-NULL + only if ELF is ET_REL. */ +extern int __libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf, + const void **build_id_bits, + GElf_Addr *build_id_elfaddr, + int *build_id_len) + internal_function; + /* Look in ELF for an NT_GNU_BUILD_ID note. If SET is true, store it in MOD and return its length. If SET is false, instead compare it to that stored in MOD and return 2 if they match, 1 if they do not. @@ -362,19 +524,35 @@ extern int __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) internal_function; /* Open a main or debuginfo file by its build ID, returns the fd. */ +extern int __libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, + char **file_name) internal_function; + +/* Same, but takes an explicit build_id, can also be used for alt debug. */ extern int __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, - char **file_name) internal_function; + char **file_name, const size_t id_len, + const uint8_t *id) internal_function; extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len) attribute_hidden; extern int __libdwfl_crc32_file (int fd, uint32_t *resp) attribute_hidden; +/* Given ELF and some parameters return TRUE if the *P return value parameters + have been successfully filled in. Any of the *P parameters can be NULL. */ +extern bool __libdwfl_elf_address_range (Elf *elf, GElf_Addr base, + bool add_p_vaddr, bool sanity, + GElf_Addr *vaddrp, + GElf_Addr *address_syncp, + GElf_Addr *startp, GElf_Addr *endp, + GElf_Addr *biasp, GElf_Half *e_typep) + internal_function; + /* Meat of dwfl_report_elf, given elf_begin just called. Consumes ELF on success, not on failure. */ extern Dwfl_Module *__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd, - Elf *elf, GElf_Addr base, bool sanity) + Elf *elf, GElf_Addr base, + bool add_p_vaddr, bool sanity) internal_function; /* Meat of dwfl_report_offline. */ @@ -385,6 +563,25 @@ extern Dwfl_Module *__libdwfl_report_offline (Dwfl *dwfl, const char *name, const char *)) internal_function; +/* Free PROCESS. Unlink and free also any structures it references. */ +extern void __libdwfl_process_free (Dwfl_Process *process) + internal_function; + +/* Update STATE->unwound for the unwound frame. + On error STATE->unwound == NULL + or STATE->unwound->pc_state == DWFL_FRAME_STATE_ERROR; + in such case dwfl_errno () is set. + If STATE->unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED + then STATE was the last valid frame. */ +extern void __libdwfl_frame_unwind (Dwfl_Frame *state) + internal_function; + +/* Align segment START downwards or END upwards addresses according to DWFL. */ +extern GElf_Addr __libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start) + internal_function; +extern GElf_Addr __libdwfl_segment_end (Dwfl *dwfl, GElf_Addr end) + internal_function; + /* Decompression wrappers: decompress whole file into memory. */ extern Dwfl_Error __libdw_gunzip (int fd, off64_t start_offset, void *mapped, size_t mapped_size, @@ -412,6 +609,11 @@ extern Dwfl_Error __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) internal_function; +/* Fetch PT_DYNAMIC P_VADDR from ELF and store it to *VADDRP. Return success. + *VADDRP is not modified if the function fails. */ +extern bool __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp) + internal_function; + /* These are working nicely for --core, but are not ready to be exported interfaces quite yet. */ @@ -430,13 +632,37 @@ typedef bool Dwfl_Module_Callback (Dwfl_Module *mod, void **userdata, GElf_Off whole, GElf_Off contiguous, void *arg, Elf **elfp); +/* One shared library (or executable) info from DT_DEBUG link map. */ +struct r_debug_info_module +{ + struct r_debug_info_module *next; + /* FD is -1 iff ELF is NULL. */ + int fd; + Elf *elf; + GElf_Addr l_ld; + /* START and END are both zero if not valid. */ + GElf_Addr start, end; + bool disk_file_has_build_id; + char name[0]; +}; + +/* Information gathered from DT_DEBUG by dwfl_link_map_report hinted to + dwfl_segment_report_module. */ +struct r_debug_info +{ + struct r_debug_info_module *module; +}; + /* ... */ extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, Dwfl_Memory_Callback *memory_callback, void *memory_callback_arg, Dwfl_Module_Callback *read_eagerly, - void *read_eagerly_arg); + void *read_eagerly_arg, + const void *note_file, + size_t note_file_size, + const struct r_debug_info *r_debug_info); /* Report a module for entry in the dynamic linker's struct link_map list. For each link_map entry, if an existing module resides at its address, @@ -450,10 +676,16 @@ extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, only find where to begin if the correct executable file was previously reported and preloaded as with dwfl_report_elf. + Fill in R_DEBUG_INFO if it is not NULL. It should be cleared by the + caller, this function does not touch fields it does not need to modify. + If R_DEBUG_INFO is not NULL then no modules get added to DWFL, caller + has to add them from filled in R_DEBUG_INFO. + Returns the number of modules found, or -1 for errors. */ extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, Dwfl_Memory_Callback *memory_callback, - void *memory_callback_arg); + void *memory_callback_arg, + struct r_debug_info *r_debug_info); /* Avoid PLT entries. */ @@ -464,16 +696,20 @@ INTDECL (dwfl_addrmodule) INTDECL (dwfl_addrsegment) INTDECL (dwfl_addrdwarf) INTDECL (dwfl_addrdie) +INTDECL (dwfl_core_file_attach) INTDECL (dwfl_core_file_report) INTDECL (dwfl_getmodules) INTDECL (dwfl_module_addrdie) INTDECL (dwfl_module_address_section) +INTDECL (dwfl_module_addrinfo) INTDECL (dwfl_module_addrsym) INTDECL (dwfl_module_build_id) INTDECL (dwfl_module_getdwarf) INTDECL (dwfl_module_getelf) INTDECL (dwfl_module_getsym) +INTDECL (dwfl_module_getsym_info) INTDECL (dwfl_module_getsymtab) +INTDECL (dwfl_module_getsymtab_first_global) INTDECL (dwfl_module_getsrc) INTDECL (dwfl_module_report_build_id) INTDECL (dwfl_report_elf) @@ -489,6 +725,7 @@ INTDECL (dwfl_standard_find_debuginfo) INTDECL (dwfl_link_map_report) INTDECL (dwfl_linux_kernel_find_elf) INTDECL (dwfl_linux_kernel_module_section_address) +INTDECL (dwfl_linux_proc_attach) INTDECL (dwfl_linux_proc_report) INTDECL (dwfl_linux_proc_maps_report) INTDECL (dwfl_linux_proc_find_elf) @@ -499,6 +736,17 @@ INTDECL (dwfl_offline_section_address) INTDECL (dwfl_module_relocate_address) INTDECL (dwfl_module_dwarf_cfi) INTDECL (dwfl_module_eh_cfi) +INTDECL (dwfl_attach_state) +INTDECL (dwfl_pid) +INTDECL (dwfl_thread_dwfl) +INTDECL (dwfl_thread_tid) +INTDECL (dwfl_frame_thread) +INTDECL (dwfl_thread_state_registers) +INTDECL (dwfl_thread_state_register_pc) +INTDECL (dwfl_getthread_frames) +INTDECL (dwfl_getthreads) +INTDECL (dwfl_thread_getframes) +INTDECL (dwfl_frame_pc) /* Leading arguments standard to callbacks passed a Dwfl_Module. */ #define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr |