diff options
Diffstat (limited to 'backend.h')
-rw-r--r-- | backend.h | 253 |
1 files changed, 184 insertions, 69 deletions
@@ -1,6 +1,6 @@ /* * This file is part of ltrace. - * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -27,12 +27,12 @@ #include <gelf.h> enum process_status { - ps_invalid, /* Failure. */ - ps_stop, /* Job-control stop. */ - ps_tracing_stop, - ps_sleeping, - ps_zombie, - ps_other, /* Necessary other states can be added as needed. */ + PS_INVALID, /* Failure. */ + PS_STOP, /* Job-control stop. */ + PS_TRACING_STOP, + PS_SLEEPING, + PS_ZOMBIE, + PS_OTHER, /* Necessary other states can be added as needed. */ }; /* @@ -70,7 +70,7 @@ int wait_for_proc(pid_t pid); int task_kill(pid_t pid, int sig); /* Called after PID is attached, but before it is continued. */ -void trace_set_options(struct Process *proc); +void trace_set_options(struct process *proc); /* Called after ltrace forks. Should attach the newly created child, * in whose context this function is called. */ @@ -86,7 +86,7 @@ void untrace_pid(pid_t pid); /* The back end may need to store arbitrary data to a process. This * is a place where it can initialize PROC->arch_dep. XXX this should * be dropped in favor of arhc_process_init on pmachata/libs. */ -void get_arch_dep(struct Process *proc); +void get_arch_dep(struct process *proc); /* Return current instruction pointer of PROC. * @@ -95,34 +95,30 @@ void get_arch_dep(struct Process *proc); * that would otherwise support this. Above we have a definition of * arch_addr_t. This should be converted to an integral type and * used for target addresses throughout. */ -void *get_instruction_pointer(struct Process *proc); +void *get_instruction_pointer(struct process *proc); /* Set instruction pointer of PROC to ADDR. XXX see above. */ -void set_instruction_pointer(struct Process *proc, void *addr); +void set_instruction_pointer(struct process *proc, void *addr); /* Return current stack pointer of PROC. XXX see above. */ -void *get_stack_pointer(struct Process *proc); +void *get_stack_pointer(struct process *proc); /* Find and return caller address, i.e. the address where the current * function returns. */ -void *get_return_addr(struct Process *proc, void *stack_pointer); - -/* Adjust PROC so that when the current function returns, it returns - * to ADDR. */ -void set_return_addr(struct Process *proc, void *addr); +void *get_return_addr(struct process *proc, void *stack_pointer); /* Enable breakpoint SBP in process PROC. */ -void enable_breakpoint(struct Process *proc, struct breakpoint *sbp); +void enable_breakpoint(struct process *proc, struct breakpoint *sbp); /* Disable breakpoint SBP in process PROC. */ -void disable_breakpoint(struct Process *proc, struct breakpoint *sbp); +void disable_breakpoint(struct process *proc, struct breakpoint *sbp); /* Determine whether the event that we have just seen (and that is * recorded in STATUS) was a syscall. If it was, return 1. If it was * a return from syscall, return 2. In both cases, set *SYSNUM to the * number of said syscall. If it wasn't a syscall, return 0. If * there was an error, return -1. */ -int syscall_p(struct Process *proc, int status, int *sysnum); +int syscall_p(struct process *proc, int status, int *sysnum); /* Continue execution of the process with given PID. */ void continue_process(pid_t pid); @@ -136,17 +132,21 @@ void continue_after_signal(pid_t pid, int signum); * is system call, otherwise it's return from a system call. The * callback should do whatever book-keeping is necessary and continue * the process if necessary. */ -void continue_after_syscall(struct Process *proc, int sysnum, int ret_p); +void continue_after_syscall(struct process *proc, int sysnum, int ret_p); /* Called after we hit a breakpoint SBP. Should do whatever * book-keeping is necessary and then continue the process. */ -void continue_after_breakpoint(struct Process *proc, struct breakpoint *sbp); +void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp); /* Called after we received a vfork. Should do whatever book-keeping * is necessary and continue the process if necessary. N.B. right * now, with Linux/GNU the only back end, this is not necessary. I * imagine other systems may be different. */ -void continue_after_vfork(struct Process *proc); +void continue_after_vfork(struct process *proc); + +/* Called after the process exec's. Should do whatever book-keeping + * is necessary and then continue the process. */ +void continue_after_exec(struct process *proc); /* Called when trace_me or primary trace_pid fail. This may plug in * any platform-specific knowledge of why it could be so. */ @@ -171,14 +171,15 @@ void os_ltrace_exiting(void); /* Should copy COUNT bytes from address ADDR of process PROC to local * buffer BUF. */ -size_t umovebytes (struct Process *proc, void *addr, void *buf, size_t count); +size_t umovebytes(struct process *proc, arch_addr_t addr, + void *buf, size_t count); /* Find out an address of symbol SYM in process PROC, and return. * Returning NULL delays breakpoint insertion and enables heaps of * arch-specific black magic that we should clean up some day. * * XXX the same points as for get_instruction_pointer apply. */ -void *sym2addr(struct Process *proc, struct library_symbol *sym); +void *sym2addr(struct process *proc, struct library_symbol *sym); /* Obtain address of PLT entry corresponding to relocation RELA in * file LTE. This is NDX-th PLT entry in the file. @@ -189,7 +190,7 @@ GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela); /* Called at some point after we have attached to PROC. This callback * should insert an introspection breakpoint for handling dynamic * linker library loads. */ -int linkmap_init(struct Process *proc, arch_addr_t dyn_addr); +int linkmap_init(struct process *proc, arch_addr_t dyn_addr); /* This should produce and return the next event of one of the traced * processes. The returned pointer will not be freed by the core and @@ -198,14 +199,14 @@ int linkmap_init(struct Process *proc, arch_addr_t dyn_addr); struct Event *next_event(void); /* Called when process PROC was removed. */ -void process_removed(struct Process *proc); +void process_removed(struct process *proc); /* This should extract entry point address and interpreter (dynamic * linker) bias if possible. Returns 0 if there were no errors, -1 * otherwise. Sets *ENTRYP and *INTERP_BIASP to non-zero values if * the corresponding value is known, or zero otherwise; this is not * done for pointers that are NULL. */ -int process_get_entry(struct Process *proc, +int process_get_entry(struct process *proc, arch_addr_t *entryp, arch_addr_t *interp_biasp); @@ -227,21 +228,49 @@ int process_get_entry(struct Process *proc, int arch_elf_init(struct ltelf *lte, struct library *lib); void arch_elf_destroy(struct ltelf *lte); +/* The following callbacks have to be implemented in OS backend if + * os.h defines OS_HAVE_BREAKPOINT_DATA. Those are used to init, + * destroy, and clone SBP->os. os_breakpoint_init and + * os_breakpoint_clone return 0 on success or a negative value on + * failure. */ +int os_breakpoint_init(struct process *proc, struct breakpoint *sbp); +void os_breakpoint_destroy(struct breakpoint *sbp); +int os_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp); + /* The following callbacks have to be implemented in backend if arch.h * defines ARCH_HAVE_BREAKPOINT_DATA. Those are used to init, * destroy, and clone SBP->arch. arch_breakpoint_init and * arch_breakpoint_clone return 0 on success or a negative value on * failure. */ -int arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp); +int arch_breakpoint_init(struct process *proc, struct breakpoint *sbp); void arch_breakpoint_destroy(struct breakpoint *sbp); int arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp); +/* The following callbacks have to be implemented in OS backend if + * os.h defines OS_HAVE_LIBRARY_DATA. Those are used to init, destroy + * and clone LIB->os. os_library_init and os_library_clone return 0 + * on success or a negative value on failure. */ +int os_library_init(struct library *lib); +void os_library_destroy(struct library *lib); +int os_library_clone(struct library *retp, struct library *lib); + /* The following callbacks have to be implemented in backend if arch.h * defines ARCH_HAVE_LIBRARY_DATA. Those are used to init, destroy - * and clone LIB->arch. */ -void arch_library_init(struct library *lib); + * and clone LIB->arch. arch_library_init and arch_library_clone + * return 0 on success or a negative value on failure. */ +int arch_library_init(struct library *lib); void arch_library_destroy(struct library *lib); -void arch_library_clone(struct library *retp, struct library *lib); +int arch_library_clone(struct library *retp, struct library *lib); + +/* The following callbacks have to be implemented in OS backend if + * os.h defines OS_HAVE_LIBRARY_SYMBOL_DATA. Those are used to init, + * destroy and clone LIBSYM->os. os_library_symbol_init and + * os_library_symbol_clone return 0 on success or a negative value on + * failure. */ +int os_library_symbol_init(struct library_symbol *libsym); +void os_library_symbol_destroy(struct library_symbol *libsym); +int os_library_symbol_clone(struct library_symbol *retp, + struct library_symbol *libsym); /* The following callbacks have to be implemented in backend if arch.h * defines ARCH_HAVE_LIBRARY_SYMBOL_DATA. Those are used to init, @@ -253,71 +282,100 @@ void arch_library_symbol_destroy(struct library_symbol *libsym); int arch_library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym); +/* The following callbacks have to be implemented in OS backend if + * os.h defines OS_HAVE_PROCESS_DATA. The protocol is same as for, + * respectively, arch_process_init, arch_process_destroy, + * arch_process_clone and arch_process_exec. */ +int os_process_init(struct process *proc); +void os_process_destroy(struct process *proc); +int os_process_clone(struct process *retp, struct process *proc); +int os_process_exec(struct process *proc); + /* The following callbacks have to be implemented in backend if arch.h * defines ARCH_HAVE_PROCESS_DATA. Those are used to init, destroy * and clone PROC->arch. arch_process_exec is called to update * PROC->arch in case that PROC underwent an exec. See notes at * process_init, process_destroy, process_clone and process_exec in * proc.h. */ -int arch_process_init(struct Process *proc); -void arch_process_destroy(struct Process *proc); -int arch_process_clone(struct Process *retp, struct Process *proc); -int arch_process_exec(struct Process *proc); - -/* The following callbacks have to be implemented in OS backend if - * os.h defines OS_HAVE_PROCESS_DATA. The protocol is same as for, - * respectively, arch_process_init, arch_process_destroy, - * arch_process_clone and arch_process_exec. */ -int os_process_init(struct Process *proc); -void os_process_destroy(struct Process *proc); -int os_process_clone(struct Process *retp, struct Process *proc); -int os_process_exec(struct Process *proc); +int arch_process_init(struct process *proc); +void arch_process_destroy(struct process *proc); +int arch_process_clone(struct process *retp, struct process *proc); +int arch_process_exec(struct process *proc); /* The following callback has to be implemented in backend if arch.h * defines ARCH_HAVE_GET_SYM_INFO. * - * This is called for every PLT relocation R in ELF file LTE, that - * ltrace is about to add to it's internal representation of the - * program under trace. - * The corresponding PLT entry is for SYM_INDEX-th relocation in the file. - * - * The callback is responsible for initializing RELA and SYM. - * - * Return 0 if OK. - * Return a negative value if this symbol (SYM_INDEX) should be ignored. */ -int arch_get_sym_info(struct ltelf *lte, const char *filename, - size_t sym_index, GElf_Rela *rela, GElf_Sym *sym); + * This is called for every PLT relocation RELA in ELF file LTE (which + * is named FILENAME), that ltrace is about to add. The corresponding + * PLT entry is for SYM_INDEX-th relocation in the file. This call is + * supposed to initialize SYM and RELA. It returns 0 if there were no + * errors and given symbol should be used, 1 if the symbol should not + * be used, or a negative value if there were errors. */ +int arch_get_sym_info(struct ltelf *lte, const char *filename, size_t sym_index, + GElf_Rela *rela, GElf_Sym *sym); enum plt_status { - plt_fail, - plt_ok, - plt_default, + PLT_FAIL, + PLT_OK, + PLT_DEFAULT, }; -/* The following callback has to be implemented in backend if arch.h - * defines ARCH_HAVE_ADD_PLT_ENTRY. +/* The following callback has to be implemented in OS backend if os.h + * defines OS_HAVE_ADD_PLT_ENTRY. * * This is called for every PLT relocation R in ELF file LTE, that * ltrace is about to add to a library constructed in process PROC. * The corresponding PLT entry is for symbol called NAME, and it's * I-th relocation in the file. * - * If this function returns plt_default, PLT address is obtained by - * calling arch_plt_sym_val, and symbol is allocated. If plt_ok or - * plt_default are returned, the chain of symbols passed back in RET + * If this function returns PLT_DEFAULT, PLT address is obtained by + * calling arch_plt_sym_val, and symbol is allocated. If PLT_OK or + * PLT_DEFAULT are returned, the chain of symbols passed back in RET * is added to library under construction. */ -enum plt_status arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, +enum plt_status os_elf_add_plt_entry(struct process *proc, struct ltelf *lte, + const char *name, GElf_Rela *rela, + size_t i, struct library_symbol **ret); + +/* Like os_elf_add_plt_entry, but tied to ARCH_HAVE_ADD_PLT_ENTRY in + * arch.h. The arch callback is called first. If it returns + * PLT_DEFAULT, the os callback is called next. */ +enum plt_status arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte, const char *name, GElf_Rela *rela, size_t i, struct library_symbol **ret); +/* The following callback has to be implemented in OS backend if os.h + * defines OS_HAVE_ADD_FUNC_ENTRY. + * + * This is called for every symbol in ltrace is about to add to the + * library constructed for LTE in process PROC. + * + * If this function returns PLT_DEFAULT, then if there is a + * pre-existing symbol, its name may be updated if the newly-found + * name is shorter. Otherwise a new symbol is created. + * + * If PLT_OK or PLT_DEFAULT are returned, the chain of symbols passed + * back in RET is added to library under construction. */ +enum plt_status os_elf_add_func_entry(struct process *proc, struct ltelf *lte, + const GElf_Sym *sym, + arch_addr_t addr, const char *name, + struct library_symbol **ret); + +/* Like os_elf_add_func_entry, but tied to ARCH_HAVE_ADD_FUNC_ENTRY in + * arch.h. The arch callback is called first. If it returns + * PLT_DEFAULT, the os callback is called next. */ +enum plt_status arch_elf_add_func_entry(struct process *proc, struct ltelf *lte, + const GElf_Sym *sym, + arch_addr_t addr, const char *name, + struct library_symbol **ret); + /* This callback needs to be implemented if arch.h defines * ARCH_HAVE_DYNLINK_DONE. It is called after the dynamic linker is - * done with the process startup. */ -void arch_dynlink_done(struct Process *proc); + * done with the process start-up. */ +void arch_dynlink_done(struct process *proc); /* This callback needs to be implemented if arch.h defines * ARCH_HAVE_SYMBOL_RET. It is called after a traced call returns. */ -void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym); +void arch_symbol_ret(struct process *proc, struct library_symbol *libsym); /* This callback needs to be implemented if arch.h defines @@ -327,9 +385,36 @@ void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym); * DYN_ADDR holds the address of the dynamic section. * If the debug area is found, return 0 and fill in the address in *RET. * If the debug area is not found, return a negative value. */ -int arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr, +int arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr, arch_addr_t *ret); +/* This is called to obtain a list of directories to search when + * loading config files. The callback sets *RETP to a pointer to the + * first element of a NULL-terminated array of directory names. It's + * legitimate to set *RETP to NULL to indicate there are no + * directories. The function returns 0 on success or a negative value + * on a failure. + * + * If PRIVATE is set, the list in *RETP should contain only user's own + * directories (presumably under HOME if there's any such thing on the + * given OS). Otherwise only system directories should be reported. + * + * The directories don't have to exist. Directories passed in -F are + * handled separately by the caller and this callback shouldn't + * concern itself with it. */ +int os_get_config_dirs(int private, const char ***retp); + +/* This is called to obtain list of legacy config files to import, if + * any. A reference to initialized vector of char* is passed in. + * + * This returns 0 on success, in which case strings from *RETP (if + * any) are interpreted as files names. These files belong to the + * caller and will eventually be freed. + * + * Returns a negative value for failure, in which case *RETP contents + * are not consulted in any way. */ +int os_get_ltrace_conf_filenames(struct vect *retp); + /* If arch.h defines ARCH_HAVE_FETCH_ARG, the following callbacks have * to be implemented: arch_fetch_arg_init, arch_fetch_arg_clone, * arch_fetch_arg_done, arch_fetch_arg_next and arch_fetch_retval. @@ -340,4 +425,34 @@ int arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr, * implemented: arch_fetch_param_pack_start, * arch_fetch_param_pack_end. See fetch.h for details. */ +enum sw_singlestep_status { + SWS_FAIL, + SWS_OK, + SWS_HW, +}; +struct sw_singlestep_data; + +/* The following callback has to be implemented in backend if arch.h + * defines ARCH_HAVE_SW_SINGLESTEP. + * + * This is called before the OS backend requests hardware singlestep. + * arch_sw_singlestep should consider whether a singlestep needs to be + * done in software. If not, it returns SWS_HW. Otherwise it needs + * to add one or several breakpoints by calling ADD_CB. When it is + * done, it continues the process as appropriate, and answers either + * SWS_OK, or SWS_FAIL, depending on how it went. + * + * PROC is the process that should perform the singlestep, BP the + * breakpoint that we are singlestepping over. ADD_CB is a callback + * to request adding breakpoints that should trap the process after + * it's continued. The arguments to ADD_CB are the address where the + * breakpoint should be added, and DATA. ADD_CB returns 0 on success + * or a negative value on failure. It is expected that + * arch_sw_singlestep returns SWS_FAIL if ADD_CB returns error. */ +enum sw_singlestep_status arch_sw_singlestep(struct process *proc, + struct breakpoint *bp, + int (*add_cb)(arch_addr_t addr, + struct sw_singlestep_data *), + struct sw_singlestep_data *data); + #endif /* BACKEND_H */ |