summaryrefslogtreecommitdiff
path: root/backend.h
diff options
context:
space:
mode:
Diffstat (limited to 'backend.h')
-rw-r--r--backend.h343
1 files changed, 343 insertions, 0 deletions
diff --git a/backend.h b/backend.h
new file mode 100644
index 0000000..89c05c3
--- /dev/null
+++ b/backend.h
@@ -0,0 +1,343 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2012 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
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include "forward.h"
+#include "sysdep.h"
+
+#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. */
+};
+
+/*
+ * This file contains documentation of back end interface. Some of
+ * these may be implemented on an OS level (i.e. they are the same
+ * e.g. on all Linux architectures), some may differ per architecture
+ * on the same OS (e.g. a way to insert a breakpoint into the process
+ * image is a likely candidate).
+ */
+
+/* Convert a PID to a path to the corresponding binary. */
+char *pid2name(pid_t pid);
+
+/* Given a PID, find a leader of thread group. */
+pid_t process_leader(pid_t pid);
+
+/* Given a PID of leader thread, fill in PIDs of all the tasks. The
+ * function will initialize the pointer *RET_TASKS to a
+ * newly-allocated array, and will store number of elements in that
+ * array to *RET_N. You have to free that buffer when you don't need
+ * it anymore. */
+int process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n);
+
+/* Answer whether the process PID is stopped. Returns 0 when not
+ * stopped, 1 when stopped, or -1 when there was an error. */
+int process_stopped(pid_t pid);
+
+/* Answer a status of the task PID. See enum process_status. */
+enum process_status process_status(pid_t pid);
+
+/* Wait for PID to be ready for tracing. */
+int wait_for_proc(pid_t pid);
+
+/* Send a signal SIG to the task 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);
+
+/* Called after ltrace forks. Should attach the newly created child,
+ * in whose context this function is called. */
+void trace_me(void);
+
+/* Called when ltrace needs to attach to PID, such as when it attaches
+ * to a running process, whose PID is given on the command line. */
+int trace_pid(pid_t pid);
+
+/* Stop tracing PID. */
+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);
+
+/* Return current instruction pointer of PROC.
+ *
+ * XXX note that the IP must fit into an arch pointer. This prevents
+ * us to use 32-bit ltrace to trace 64-bit process, even on arches
+ * 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);
+
+/* Set instruction pointer of PROC to ADDR. XXX see above. */
+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);
+
+/* 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);
+
+/* Enable breakpoint SBP in process PROC. */
+void enable_breakpoint(struct Process *proc, struct breakpoint *sbp);
+
+/* Disable breakpoint SBP in process PROC. */
+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);
+
+/* Continue execution of the process with given PID. */
+void continue_process(pid_t pid);
+
+/* Called after we received a signal SIGNUM. Should do whatever
+ * book-keeping is necessary and continue the process if
+ * necessary. */
+void continue_after_signal(pid_t pid, int signum);
+
+/* Called after we received a system call SYSNUM. RET_P is 0 if this
+ * 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);
+
+/* 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);
+
+/* 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);
+
+/* Called when trace_me or primary trace_pid fail. This may plug in
+ * any platform-specific knowledge of why it could be so. */
+void trace_fail_warning(pid_t pid);
+
+/* A pair of functions called to initiate a detachment request when
+ * ltrace is about to exit. Their job is to undo any effects that
+ * tracing had and eventually detach process, perhaps by way of
+ * installing a process handler.
+ *
+ * OS_LTRACE_EXITING_SIGHANDLER is called from a signal handler
+ * context right after the signal was captured. It returns 1 if the
+ * request was handled or 0 if it wasn't.
+ *
+ * If the call to OS_LTRACE_EXITING_SIGHANDLER didn't handle the
+ * request, OS_LTRACE_EXITING is called when the next event is
+ * generated. Therefore it's called in "safe" context, without
+ * re-entrancy concerns, but it's only called after an even is
+ * generated. */
+int os_ltrace_exiting_sighandler(void);
+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);
+
+/* 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);
+
+/* Obtain address of PLT entry corresponding to relocation RELA in
+ * file LTE. This is NDX-th PLT entry in the file.
+ *
+ * XXX should this return arch_addr_t? */
+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);
+
+/* 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
+ * should be either statically allocated, or the management should be
+ * done some other way. */
+struct Event *next_event(void);
+
+/* Called when process PROC was removed. */
+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,
+ arch_addr_t *entryp,
+ arch_addr_t *interp_biasp);
+
+
+/* Optional callbacks
+ *
+ * Some callbacks are only available if backend (arch.h) has a certain
+ * define. If such a define is not present, default implementation
+ * (most often doing nothing at all) us used instead. This is used
+ * for gradual extensions of ltrace, so that backends that are not
+ * fully up to date, or that don't need certain functionality, keep
+ * working, while other backends take advantage of the optional
+ * features. */
+
+/* The following callbacks have to be implemented in backend if arch.h
+ * defines ARCH_HAVE_LTELF_DATA. Those are used to init and destroy
+ * LTE->arch. arch_elf_init returns 0 on success or a negative value
+ * on failure. */
+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 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);
+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 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);
+void arch_library_destroy(struct library *lib);
+void arch_library_clone(struct library *retp, struct library *lib);
+
+/* The following callbacks have to be implemented in backend if arch.h
+ * defines ARCH_HAVE_LIBRARY_SYMBOL_DATA. Those are used to init,
+ * destroy and clone LIBSYM->arch. arch_library_symbol_init and
+ * arch_library_symbol_clone return 0 on success or a negative value
+ * on failure. */
+int arch_library_symbol_init(struct library_symbol *libsym);
+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 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);
+
+/* 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);
+
+enum plt_status {
+ plt_fail,
+ plt_ok,
+ plt_default,
+};
+
+/* The following callback has to be implemented in backend if arch.h
+ * defines ARCH_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
+ * is added to library under construction. */
+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);
+
+/* 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);
+
+/* 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);
+
+
+/* This callback needs to be implemented if arch.h defines
+ * ARCH_HAVE_FIND_DL_DEBUG.
+ * It is called by generic code to find the address of the dynamic
+ * linkers debug structure.
+ * 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,
+ arch_addr_t *ret);
+
+/* 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.
+ * See fetch.h for details. */
+
+/* If arch.h defines both ARCH_HAVE_FETCH_ARG and
+ * ARCH_HAVE_FETCH_PACK, the following callbacks have to be
+ * implemented: arch_fetch_param_pack_start,
+ * arch_fetch_param_pack_end. See fetch.h for details. */
+
+#endif /* BACKEND_H */