| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of ltrace. |
| Petr Machata | 693dfad | 2013-01-14 22:10:51 +0100 | [diff] [blame] | 3 | * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc. |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License as |
| 7 | * published by the Free Software Foundation; either version 2 of the |
| 8 | * License, or (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, but |
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
| 18 | * 02110-1301 USA |
| 19 | */ |
| 20 | |
| 21 | #ifndef _LTRACE_LINUX_TRACE_H_ |
| 22 | #define _LTRACE_LINUX_TRACE_H_ |
| 23 | |
| Petr Machata | ba1664b | 2012-04-28 14:59:05 +0200 | [diff] [blame] | 24 | #include "proc.h" |
| 25 | |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 26 | /* This publishes some Linux-specific data structures used for process |
| 27 | * handling. */ |
| 28 | |
| 29 | /** |
| 30 | * This is used for bookkeeping related to PIDs that the event |
| 31 | * handlers work with. |
| 32 | */ |
| 33 | struct pid_task { |
| 34 | pid_t pid; /* This may be 0 for tasks that exited |
| 35 | * mid-handling. */ |
| 36 | int sigstopped : 1; |
| 37 | int got_event : 1; |
| 38 | int delivered : 1; |
| 39 | int vforked : 1; |
| 40 | int sysret : 1; |
| 41 | }; |
| 42 | |
| 43 | struct pid_set { |
| 44 | struct pid_task *tasks; |
| 45 | size_t count; |
| 46 | size_t alloc; |
| 47 | }; |
| 48 | |
| 49 | /** |
| 50 | * Breakpoint re-enablement. When we hit a breakpoint, we must |
| 51 | * disable it, single-step, and re-enable it. That single-step can be |
| 52 | * done only by one task in a task group, while others are stopped, |
| 53 | * otherwise the processes would race for who sees the breakpoint |
| 54 | * disabled and who doesn't. The following is to keep track of it |
| 55 | * all. |
| 56 | */ |
| 57 | struct process_stopping_handler |
| 58 | { |
| 59 | struct event_handler super; |
| 60 | |
| 61 | /* The task that is doing the re-enablement. */ |
| Petr Machata | 929bd57 | 2012-12-17 03:20:34 +0100 | [diff] [blame] | 62 | struct process *task_enabling_breakpoint; |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 63 | |
| 64 | /* The pointer being re-enabled. */ |
| 65 | struct breakpoint *breakpoint_being_enabled; |
| 66 | |
| Petr Machata | 6e5e2de | 2013-01-21 22:25:34 +0100 | [diff] [blame] | 67 | /* Software singlestep breakpoints, if any needed. */ |
| 68 | struct breakpoint *sws_bps[2]; |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 69 | |
| 70 | /* When all tasks are stopped, this callback gets called. */ |
| 71 | void (*on_all_stopped)(struct process_stopping_handler *); |
| 72 | |
| Petr Machata | 36f40e7 | 2012-03-28 02:07:19 +0200 | [diff] [blame] | 73 | /* When we get a singlestep event, this is called to decide |
| 74 | * whether to stop stepping, or whether to enable the |
| 75 | * brakpoint, sink remaining signals, and continue |
| 76 | * everyone. */ |
| 77 | enum callback_status (*keep_stepping_p) |
| 78 | (struct process_stopping_handler *); |
| 79 | |
| Petr Machata | cb9a28d | 2012-03-28 11:11:32 +0200 | [diff] [blame] | 80 | /* Whether we need to use ugly workaround to get around |
| 81 | * various problems with singlestepping. */ |
| 82 | enum callback_status (*ugly_workaround_p) |
| 83 | (struct process_stopping_handler *); |
| 84 | |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 85 | enum { |
| 86 | /* We are waiting for everyone to land in t/T. */ |
| Petr Machata | 96cb8e3 | 2012-12-17 03:49:41 +0100 | [diff] [blame] | 87 | PSH_STOPPING = 0, |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 88 | |
| 89 | /* We are doing the PTRACE_SINGLESTEP. */ |
| Petr Machata | 96cb8e3 | 2012-12-17 03:49:41 +0100 | [diff] [blame] | 90 | PSH_SINGLESTEP, |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 91 | |
| 92 | /* We are waiting for all the SIGSTOPs to arrive so |
| 93 | * that we can sink them. */ |
| Petr Machata | 96cb8e3 | 2012-12-17 03:49:41 +0100 | [diff] [blame] | 94 | PSH_SINKING, |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 95 | |
| 96 | /* This is for tracking the ugly workaround. */ |
| Petr Machata | 96cb8e3 | 2012-12-17 03:49:41 +0100 | [diff] [blame] | 97 | PSH_UGLY_WORKAROUND, |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 98 | } state; |
| 99 | |
| 100 | int exiting; |
| 101 | |
| 102 | struct pid_set pids; |
| 103 | }; |
| 104 | |
| 105 | /* Allocate a process stopping handler, initialize it and install it. |
| Petr Machata | 36f40e7 | 2012-03-28 02:07:19 +0200 | [diff] [blame] | 106 | * Return 0 on success or a negative value on failure. Pass NULL for |
| 107 | * each callback to use a default instead. The default for |
| Petr Machata | 1e2a4dd | 2012-04-15 04:35:48 +0200 | [diff] [blame] | 108 | * ON_ALL_STOPPED is LINUX_PTRACE_DISABLE_AND_SINGLESTEP, the default |
| 109 | * for KEEP_STEPPING_P and UGLY_WORKAROUND_P is "no". */ |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 110 | int process_install_stopping_handler |
| Petr Machata | 929bd57 | 2012-12-17 03:20:34 +0100 | [diff] [blame] | 111 | (struct process *proc, struct breakpoint *sbp, |
| Petr Machata | 36f40e7 | 2012-03-28 02:07:19 +0200 | [diff] [blame] | 112 | void (*on_all_stopped)(struct process_stopping_handler *), |
| 113 | enum callback_status (*keep_stepping_p) |
| Petr Machata | cb9a28d | 2012-03-28 11:11:32 +0200 | [diff] [blame] | 114 | (struct process_stopping_handler *), |
| 115 | enum callback_status (*ugly_workaround_p) |
| Petr Machata | 36f40e7 | 2012-03-28 02:07:19 +0200 | [diff] [blame] | 116 | (struct process_stopping_handler *)); |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 117 | |
| Petr Machata | 1e2a4dd | 2012-04-15 04:35:48 +0200 | [diff] [blame] | 118 | void linux_ptrace_disable_and_singlestep(struct process_stopping_handler *self); |
| 119 | void linux_ptrace_disable_and_continue(struct process_stopping_handler *self); |
| 120 | |
| Petr Machata | b420a22 | 2013-10-15 10:46:28 +0200 | [diff] [blame] | 121 | /* When main binary needs to call an IFUNC function defined in the |
| 122 | * binary itself, a PLT entry is set up so that dynamic linker can get |
| 123 | * involved and resolve the symbol. But unlike other PLT relocation, |
| 124 | * this one can't rely on symbol table being available. So it doesn't |
| 125 | * reference the symbol by its name, but by its address, and |
| 126 | * correspondingly, has another type. When arch backend wishes to |
| 127 | * support these IRELATIVE relocations, it should override |
| 128 | * arch_elf_add_plt_entry and dispatch to this function for IRELATIVE |
| 129 | * relocations. |
| 130 | * |
| 131 | * This function behaves as arch_elf_add_plt_entry, except that it |
| 132 | * doesn't take name for a parameter, but instead looks up the name in |
| 133 | * symbol tables in LTE. */ |
| 134 | enum plt_status linux_elf_add_plt_entry_irelative(struct process *proc, |
| 135 | struct ltelf *lte, |
| 136 | GElf_Rela *rela, size_t ndx, |
| 137 | struct library_symbol **ret); |
| 138 | |
| Petr Machata | b061bae | 2013-10-25 23:50:18 +0200 | [diff] [blame] | 139 | /* Service routine of the above. Determines a name corresponding to |
| Petr Machata | 54bb64c | 2013-11-04 20:00:43 +0100 | [diff] [blame] | 140 | * ADDR, or invents a new one. Returns NULL on failures, otherwise it |
| Petr Machata | b061bae | 2013-10-25 23:50:18 +0200 | [diff] [blame] | 141 | * returns a malloc'd pointer that the caller is responsible for |
| 142 | * freeing. */ |
| Petr Machata | 54bb64c | 2013-11-04 20:00:43 +0100 | [diff] [blame] | 143 | char *linux_elf_find_irelative_name(struct ltelf *lte, GElf_Addr addr); |
| Petr Machata | b061bae | 2013-10-25 23:50:18 +0200 | [diff] [blame] | 144 | |
| Petr Machata | fa844db | 2013-11-05 01:55:57 +0100 | [diff] [blame] | 145 | /* Returns ${NAME}.IFUNC in a newly-malloc'd block, or NULL on |
| 146 | * failures. */ |
| 147 | char *linux_append_IFUNC_to_name(const char *name); |
| 148 | |
| 149 | /* Returns a statically allocated prototype that represents the |
| 150 | * prototype "void *()". Never fails. */ |
| 151 | struct prototype *linux_IFUNC_prototype(void); |
| 152 | |
| 153 | |
| Petr Machata | 9282254 | 2012-03-28 00:31:14 +0200 | [diff] [blame] | 154 | #endif /* _LTRACE_LINUX_TRACE_H_ */ |