| /* | 
 |  * 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_ */ |