/* * This file is part of ltrace. * Copyright (C) 2011,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 * 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 _LTRACE_LINUX_TRACE_H_ #define _LTRACE_LINUX_TRACE_H_ #include "proc.h" /* This publishes some Linux-specific data structures used for process * handling. */ /** * This is used for bookkeeping related to PIDs that the event * handlers work with. */ struct pid_task { pid_t pid; /* This may be 0 for tasks that exited * mid-handling. */ int sigstopped : 1; int got_event : 1; int delivered : 1; int vforked : 1; int sysret : 1; }; struct pid_set { struct pid_task *tasks; size_t count; size_t alloc; }; /** * Breakpoint re-enablement. When we hit a breakpoint, we must * disable it, single-step, and re-enable it. That single-step can be * done only by one task in a task group, while others are stopped, * otherwise the processes would race for who sees the breakpoint * disabled and who doesn't. The following is to keep track of it * all. */ struct process_stopping_handler { struct event_handler super; /* The task that is doing the re-enablement. */ struct process *task_enabling_breakpoint; /* The pointer being re-enabled. */ struct breakpoint *breakpoint_being_enabled; /* Software singlestep breakpoints, if any needed. */ struct breakpoint *sws_bps[2]; /* When all tasks are stopped, this callback gets called. */ void (*on_all_stopped)(struct process_stopping_handler *); /* When we get a singlestep event, this is called to decide * whether to stop stepping, or whether to enable the * brakpoint, sink remaining signals, and continue * everyone. */ enum callback_status (*keep_stepping_p) (struct process_stopping_handler *); /* Whether we need to use ugly workaround to get around * various problems with singlestepping. */ enum callback_status (*ugly_workaround_p) (struct process_stopping_handler *); enum { /* We are waiting for everyone to land in t/T. */ PSH_STOPPING = 0, /* We are doing the PTRACE_SINGLESTEP. */ PSH_SINGLESTEP, /* We are waiting for all the SIGSTOPs to arrive so * that we can sink them. */ PSH_SINKING, /* This is for tracking the ugly workaround. */ PSH_UGLY_WORKAROUND, } state; int exiting; struct pid_set pids; }; /* Allocate a process stopping handler, initialize it and install it. * Return 0 on success or a negative value on failure. Pass NULL for * each callback to use a default instead. The default for * ON_ALL_STOPPED is LINUX_PTRACE_DISABLE_AND_SINGLESTEP, the default * for KEEP_STEPPING_P and UGLY_WORKAROUND_P is "no". */ int process_install_stopping_handler (struct process *proc, struct breakpoint *sbp, void (*on_all_stopped)(struct process_stopping_handler *), enum callback_status (*keep_stepping_p) (struct process_stopping_handler *), enum callback_status (*ugly_workaround_p) (struct process_stopping_handler *)); void linux_ptrace_disable_and_singlestep(struct process_stopping_handler *self); void linux_ptrace_disable_and_continue(struct process_stopping_handler *self); /* When main binary needs to call an IFUNC function defined in the * binary itself, a PLT entry is set up so that dynamic linker can get * involved and resolve the symbol. But unlike other PLT relocation, * this one can't rely on symbol table being available. So it doesn't * reference the symbol by its name, but by its address, and * correspondingly, has another type. When arch backend wishes to * support these IRELATIVE relocations, it should override * arch_elf_add_plt_entry and dispatch to this function for IRELATIVE * relocations. * * This function behaves as arch_elf_add_plt_entry, except that it * doesn't take name for a parameter, but instead looks up the name in * symbol tables in LTE. */ enum plt_status linux_elf_add_plt_entry_irelative(struct process *proc, struct ltelf *lte, GElf_Rela *rela, size_t ndx, struct library_symbol **ret); /* Service routine of the above. Determines a name corresponding to * ADDR, or invents a new one. Returns NULL on failures, otherwise it * returns a malloc'd pointer that the caller is responsible for * freeing. */ char *linux_elf_find_irelative_name(struct ltelf *lte, GElf_Addr addr); /* Returns ${NAME}.IFUNC in a newly-malloc'd block, or NULL on * failures. */ char *linux_append_IFUNC_to_name(const char *name); /* Returns a statically allocated prototype that represents the * prototype "void *()". Never fails. */ struct prototype *linux_IFUNC_prototype(void); #endif /* _LTRACE_LINUX_TRACE_H_ */