| Petr Machata | e99af27 | 2012-10-26 00:29:52 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * This file is part of ltrace. | 
 | 3 |  * Copyright (C) 2006,2007,2011,2012 Petr Machata, Red Hat Inc. | 
 | 4 |  * Copyright (C) 2009 Juan Cespedes | 
 | 5 |  * Copyright (C) 1998,2001,2002,2003,2007,2008,2009 Juan Cespedes | 
 | 6 |  * Copyright (C) 2006 Ian Wienand | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or | 
 | 9 |  * modify it under the terms of the GNU General Public License as | 
 | 10 |  * published by the Free Software Foundation; either version 2 of the | 
 | 11 |  * License, or (at your option) any later version. | 
 | 12 |  * | 
 | 13 |  * This program is distributed in the hope that it will be useful, but | 
 | 14 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 15 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 16 |  * General Public License for more details. | 
 | 17 |  * | 
 | 18 |  * You should have received a copy of the GNU General Public License | 
 | 19 |  * along with this program; if not, write to the Free Software | 
 | 20 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 
 | 21 |  * 02110-1301 USA | 
 | 22 |  */ | 
 | 23 |  | 
| Juan Cespedes | d44c6b8 | 1998-09-25 14:48:42 +0200 | [diff] [blame] | 24 | #include "config.h" | 
| Juan Cespedes | d44c6b8 | 1998-09-25 14:48:42 +0200 | [diff] [blame] | 25 |  | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 26 | #include <assert.h> | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 27 | #include <errno.h> | 
| Petr Machata | ba1664b | 2012-04-28 14:59:05 +0200 | [diff] [blame] | 28 | #include <stdio.h> | 
 | 29 | #include <stdlib.h> | 
 | 30 | #include <string.h> | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 31 |  | 
| Juan Cespedes | f1bfe20 | 2002-03-27 00:22:23 +0100 | [diff] [blame] | 32 | #ifdef __powerpc__ | 
 | 33 | #include <sys/ptrace.h> | 
 | 34 | #endif | 
 | 35 |  | 
| Petr Machata | 6426260 | 2012-01-07 03:41:36 +0100 | [diff] [blame] | 36 | #include "backend.h" | 
| Petr Machata | ba1664b | 2012-04-28 14:59:05 +0200 | [diff] [blame] | 37 | #include "breakpoint.h" | 
 | 38 | #include "debug.h" | 
 | 39 | #include "library.h" | 
 | 40 | #include "ltrace-elf.h" | 
 | 41 | #include "proc.h" | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 42 |  | 
| Petr Machata | c67a6e6 | 2012-03-28 02:39:49 +0200 | [diff] [blame] | 43 | #ifndef ARCH_HAVE_TRANSLATE_ADDRESS | 
 | 44 | int | 
| Petr Machata | b1492df | 2012-04-30 21:01:40 +0200 | [diff] [blame] | 45 | arch_translate_address_dyn(struct Process *proc, | 
| Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 46 | 		       arch_addr_t addr, arch_addr_t *ret) | 
| Petr Machata | b1492df | 2012-04-30 21:01:40 +0200 | [diff] [blame] | 47 | { | 
 | 48 | 	*ret = addr; | 
 | 49 | 	return 0; | 
 | 50 | } | 
 | 51 |  | 
 | 52 | struct ltelf; | 
 | 53 | int | 
 | 54 | arch_translate_address(struct ltelf *lte, | 
| Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 55 | 		       arch_addr_t addr, arch_addr_t *ret) | 
| Petr Machata | c67a6e6 | 2012-03-28 02:39:49 +0200 | [diff] [blame] | 56 | { | 
 | 57 | 	*ret = addr; | 
 | 58 | 	return 0; | 
 | 59 | } | 
 | 60 | #endif | 
 | 61 |  | 
| Petr Machata | a9fd8f4 | 2012-02-07 13:25:56 +0100 | [diff] [blame] | 62 | void | 
 | 63 | breakpoint_on_hit(struct breakpoint *bp, struct Process *proc) | 
 | 64 | { | 
 | 65 | 	assert(bp != NULL); | 
 | 66 | 	if (bp->cbs != NULL && bp->cbs->on_hit != NULL) | 
| Petr Machata | 55ac932 | 2012-03-27 03:07:35 +0200 | [diff] [blame] | 67 | 		(bp->cbs->on_hit)(bp, proc); | 
 | 68 | } | 
 | 69 |  | 
 | 70 | void | 
 | 71 | breakpoint_on_continue(struct breakpoint *bp, struct Process *proc) | 
 | 72 | { | 
 | 73 | 	assert(bp != NULL); | 
 | 74 | 	if (bp->cbs != NULL && bp->cbs->on_continue != NULL) | 
 | 75 | 		(bp->cbs->on_continue)(bp, proc); | 
 | 76 | 	else | 
 | 77 | 		continue_after_breakpoint(proc, bp); | 
| Petr Machata | a9fd8f4 | 2012-02-07 13:25:56 +0100 | [diff] [blame] | 78 | } | 
 | 79 |  | 
| Petr Machata | 86d3828 | 2012-04-24 18:09:01 +0200 | [diff] [blame] | 80 | void | 
 | 81 | breakpoint_on_retract(struct breakpoint *bp, struct Process *proc) | 
 | 82 | { | 
 | 83 | 	assert(bp != NULL); | 
 | 84 | 	if (bp->cbs != NULL && bp->cbs->on_retract != NULL) | 
 | 85 | 		(bp->cbs->on_retract)(bp, proc); | 
 | 86 | } | 
 | 87 |  | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 88 | /*****************************************************************************/ | 
 | 89 |  | 
| Petr Machata | 9294d82 | 2012-02-07 12:35:58 +0100 | [diff] [blame] | 90 | struct breakpoint * | 
| Petr Machata | fed1e8d | 2012-02-07 02:06:29 +0100 | [diff] [blame] | 91 | address2bpstruct(Process *proc, void *addr) | 
 | 92 | { | 
| Petr Machata | 2662768 | 2011-07-08 18:15:32 +0200 | [diff] [blame] | 93 | 	assert(proc != NULL); | 
 | 94 | 	assert(proc->breakpoints != NULL); | 
| Petr Machata | 9a5420c | 2011-07-09 11:21:23 +0200 | [diff] [blame] | 95 | 	assert(proc->leader == proc); | 
| Juan Cespedes | cd8976d | 2009-05-14 13:47:58 +0200 | [diff] [blame] | 96 | 	debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); | 
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame] | 97 | 	return dict_find_entry(proc->breakpoints, addr); | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 98 | } | 
 | 99 |  | 
| Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 100 | #ifndef ARCH_HAVE_BREAKPOINT_DATA | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 101 | int | 
 | 102 | arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp) | 
 | 103 | { | 
 | 104 | 	return 0; | 
 | 105 | } | 
| Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 106 |  | 
 | 107 | void | 
 | 108 | arch_breakpoint_destroy(struct breakpoint *sbp) | 
 | 109 | { | 
 | 110 | } | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 111 |  | 
 | 112 | int | 
 | 113 | arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) | 
 | 114 | { | 
 | 115 | 	return 0; | 
 | 116 | } | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 117 | #endif | 
 | 118 |  | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 119 | static void | 
 | 120 | breakpoint_init_base(struct breakpoint *bp, struct Process *proc, | 
| Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 121 | 		     arch_addr_t addr, struct library_symbol *libsym) | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 122 | { | 
 | 123 | 	bp->cbs = NULL; | 
 | 124 | 	bp->addr = addr; | 
 | 125 | 	memset(bp->orig_value, 0, sizeof(bp->orig_value)); | 
 | 126 | 	bp->enabled = 0; | 
 | 127 | 	bp->libsym = libsym; | 
 | 128 | } | 
 | 129 |  | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 130 | /* On second thought, I don't think we need PROC.  All the translation | 
 | 131 |  * (arch_translate_address in particular) should be doable using | 
 | 132 |  * static lookups of various sections in the ELF file.  We shouldn't | 
 | 133 |  * need process for anything.  */ | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 134 | int | 
 | 135 | breakpoint_init(struct breakpoint *bp, struct Process *proc, | 
| Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 136 | 		arch_addr_t addr, struct library_symbol *libsym) | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 137 | { | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 138 | 	breakpoint_init_base(bp, proc, addr, libsym); | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 139 | 	return arch_breakpoint_init(proc, bp); | 
 | 140 | } | 
 | 141 |  | 
| Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 142 | void | 
| Petr Machata | 55ac932 | 2012-03-27 03:07:35 +0200 | [diff] [blame] | 143 | breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs) | 
 | 144 | { | 
 | 145 | 	if (bp->cbs != NULL) | 
 | 146 | 		assert(bp->cbs == NULL); | 
 | 147 | 	bp->cbs = cbs; | 
 | 148 | } | 
 | 149 |  | 
 | 150 | void | 
| Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 151 | breakpoint_destroy(struct breakpoint *bp) | 
 | 152 | { | 
 | 153 | 	if (bp == NULL) | 
 | 154 | 		return; | 
| Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 155 | 	arch_breakpoint_destroy(bp); | 
 | 156 | } | 
 | 157 |  | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 158 | int | 
 | 159 | breakpoint_clone(struct breakpoint *retp, struct Process *new_proc, | 
 | 160 | 		 struct breakpoint *bp, struct Process *old_proc) | 
 | 161 | { | 
| Petr Machata | 165b566 | 2012-10-27 19:23:12 +0200 | [diff] [blame] | 162 | 	struct library_symbol *libsym = NULL; | 
 | 163 | 	if (bp->libsym != NULL) { | 
 | 164 | 		int rc = proc_find_symbol(new_proc, bp->libsym, NULL, &libsym); | 
 | 165 | 		assert(rc == 0); | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 166 | 	} | 
 | 167 |  | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 168 | 	breakpoint_init_base(retp, new_proc, bp->addr, libsym); | 
 | 169 | 	memcpy(retp->orig_value, bp->orig_value, sizeof(bp->orig_value)); | 
 | 170 | 	retp->enabled = bp->enabled; | 
| Petr Machata | d3cc988 | 2012-04-13 21:40:23 +0200 | [diff] [blame] | 171 | 	if (arch_breakpoint_clone(retp, bp) < 0) | 
 | 172 | 		return -1; | 
 | 173 | 	breakpoint_set_callbacks(retp, bp->cbs); | 
 | 174 | 	return 0; | 
 | 175 | } | 
 | 176 |  | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 177 | int | 
| Petr Machata | fa0c570 | 2012-04-13 18:43:40 +0200 | [diff] [blame] | 178 | breakpoint_turn_on(struct breakpoint *bp, struct Process *proc) | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 179 | { | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 180 | 	bp->enabled++; | 
 | 181 | 	if (bp->enabled == 1) { | 
| Petr Machata | fa0c570 | 2012-04-13 18:43:40 +0200 | [diff] [blame] | 182 | 		assert(proc->pid != 0); | 
 | 183 | 		enable_breakpoint(proc, bp); | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 184 | 	} | 
 | 185 | 	return 0; | 
 | 186 | } | 
 | 187 |  | 
 | 188 | int | 
| Petr Machata | fa0c570 | 2012-04-13 18:43:40 +0200 | [diff] [blame] | 189 | breakpoint_turn_off(struct breakpoint *bp, struct Process *proc) | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 190 | { | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 191 | 	bp->enabled--; | 
 | 192 | 	if (bp->enabled == 0) | 
| Petr Machata | fa0c570 | 2012-04-13 18:43:40 +0200 | [diff] [blame] | 193 | 		disable_breakpoint(proc, bp); | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 194 | 	assert(bp->enabled >= 0); | 
 | 195 | 	return 0; | 
 | 196 | } | 
 | 197 |  | 
| Petr Machata | 9294d82 | 2012-02-07 12:35:58 +0100 | [diff] [blame] | 198 | struct breakpoint * | 
| Petr Machata | 9df1501 | 2012-02-20 12:49:46 +0100 | [diff] [blame] | 199 | insert_breakpoint(struct Process *proc, void *addr, | 
 | 200 | 		  struct library_symbol *libsym) | 
| Petr Machata | fed1e8d | 2012-02-07 02:06:29 +0100 | [diff] [blame] | 201 | { | 
| Petr Machata | 9df1501 | 2012-02-20 12:49:46 +0100 | [diff] [blame] | 202 | 	Process *leader = proc->leader; | 
| Petr Machata | 9a5420c | 2011-07-09 11:21:23 +0200 | [diff] [blame] | 203 |  | 
 | 204 | 	/* Only the group leader should be getting the breakpoints and | 
 | 205 | 	 * thus have ->breakpoint initialized.  */ | 
 | 206 | 	assert(leader != NULL); | 
 | 207 | 	assert(leader->breakpoints != NULL); | 
 | 208 |  | 
| Petr Machata | 050b0a6 | 2012-04-03 01:30:30 +0200 | [diff] [blame] | 209 | 	debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", | 
 | 210 | 	      proc->pid, addr, libsym ? libsym->name : "NULL"); | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 211 |  | 
| Petr Machata | 218c5ff | 2012-04-15 04:22:39 +0200 | [diff] [blame] | 212 | 	assert(addr != 0); | 
| Ian Wienand | 9a2ad35 | 2006-02-20 22:44:45 +0100 | [diff] [blame] | 213 |  | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 214 | 	/* XXX what we need to do instead is have a list of | 
 | 215 | 	 * breakpoints that are enabled at this address.  The | 
 | 216 | 	 * following works if every breakpoint is the same and there's | 
 | 217 | 	 * no extra data, but that doesn't hold anymore.  For now it | 
 | 218 | 	 * will suffice, about the only realistic case where we need | 
 | 219 | 	 * to have more than one breakpoint per address is return from | 
 | 220 | 	 * a recursive library call.  */ | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 221 | 	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr); | 
| Petr Machata | fed1e8d | 2012-02-07 02:06:29 +0100 | [diff] [blame] | 222 | 	if (sbp == NULL) { | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 223 | 		sbp = malloc(sizeof(*sbp)); | 
 | 224 | 		if (sbp == NULL | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 225 | 		    || breakpoint_init(sbp, proc, addr, libsym) < 0) { | 
 | 226 | 			free(sbp); | 
 | 227 | 			return NULL; | 
 | 228 | 		} | 
| Petr Machata | fa0c570 | 2012-04-13 18:43:40 +0200 | [diff] [blame] | 229 | 		if (proc_add_breakpoint(leader, sbp) < 0) { | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 230 | 		fail: | 
 | 231 | 			breakpoint_destroy(sbp); | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 232 | 			free(sbp); | 
 | 233 | 			return NULL; | 
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame] | 234 | 		} | 
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame] | 235 | 	} | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 236 |  | 
| Petr Machata | 4572877 | 2012-04-15 04:23:55 +0200 | [diff] [blame] | 237 | 	if (breakpoint_turn_on(sbp, proc) < 0) { | 
 | 238 | 		proc_remove_breakpoint(leader, sbp); | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 239 | 		goto fail; | 
| Petr Machata | 4572877 | 2012-04-15 04:23:55 +0200 | [diff] [blame] | 240 | 	} | 
| Petr Machata | 9294d82 | 2012-02-07 12:35:58 +0100 | [diff] [blame] | 241 |  | 
 | 242 | 	return sbp; | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 243 | } | 
 | 244 |  | 
| Juan Cespedes | f135052 | 2008-12-16 18:19:58 +0100 | [diff] [blame] | 245 | void | 
| Petr Machata | fed1e8d | 2012-02-07 02:06:29 +0100 | [diff] [blame] | 246 | delete_breakpoint(Process *proc, void *addr) | 
 | 247 | { | 
| Juan Cespedes | cd8976d | 2009-05-14 13:47:58 +0200 | [diff] [blame] | 248 | 	debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); | 
 | 249 |  | 
| Petr Machata | 9a5420c | 2011-07-09 11:21:23 +0200 | [diff] [blame] | 250 | 	Process * leader = proc->leader; | 
 | 251 | 	assert(leader != NULL); | 
 | 252 |  | 
| Petr Machata | f7fee43 | 2012-04-19 17:00:53 +0200 | [diff] [blame] | 253 | 	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr); | 
 | 254 | 	assert(sbp != NULL); | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 255 | 	/* This should only happen on out-of-memory conditions. */ | 
| Ian Wienand | 2d45b1a | 2006-02-20 22:48:07 +0100 | [diff] [blame] | 256 | 	if (sbp == NULL) | 
 | 257 | 		return; | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 258 |  | 
| Petr Machata | fa0c570 | 2012-04-13 18:43:40 +0200 | [diff] [blame] | 259 | 	if (breakpoint_turn_off(sbp, proc) < 0) { | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 260 | 		fprintf(stderr, "Couldn't turn off the breakpoint %s@%p\n", | 
 | 261 | 			breakpoint_name(sbp), sbp->addr); | 
 | 262 | 		return; | 
 | 263 | 	} | 
| Petr Machata | f7fee43 | 2012-04-19 17:00:53 +0200 | [diff] [blame] | 264 | 	if (sbp->enabled == 0) { | 
 | 265 | 		proc_remove_breakpoint(leader, sbp); | 
 | 266 | 		breakpoint_destroy(sbp); | 
 | 267 | 		free(sbp); | 
 | 268 | 	} | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 269 | } | 
 | 270 |  | 
| Petr Machata | e9aebd6 | 2012-03-25 01:38:53 +0100 | [diff] [blame] | 271 | const char * | 
 | 272 | breakpoint_name(const struct breakpoint *bp) | 
 | 273 | { | 
 | 274 | 	assert(bp != NULL); | 
 | 275 | 	return bp->libsym != NULL ? bp->libsym->name : NULL; | 
 | 276 | } | 
 | 277 |  | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 278 | struct library * | 
 | 279 | breakpoint_library(const struct breakpoint *bp) | 
 | 280 | { | 
 | 281 | 	assert(bp != NULL); | 
 | 282 | 	return bp->libsym != NULL ? bp->libsym->lib : NULL; | 
 | 283 | } | 
 | 284 |  | 
| Juan Cespedes | f135052 | 2008-12-16 18:19:58 +0100 | [diff] [blame] | 285 | static void | 
| Petr Machata | fed1e8d | 2012-02-07 02:06:29 +0100 | [diff] [blame] | 286 | enable_bp_cb(void *addr, void *sbp, void *proc) | 
 | 287 | { | 
| Juan Cespedes | cd8976d | 2009-05-14 13:47:58 +0200 | [diff] [blame] | 288 | 	debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); | 
| Petr Machata | bc37326 | 2012-02-07 23:31:15 +0100 | [diff] [blame] | 289 | 	if (((struct breakpoint *)sbp)->enabled) | 
| Petr Machata | f789c9c | 2011-07-09 10:54:27 +0200 | [diff] [blame] | 290 | 		enable_breakpoint(proc, sbp); | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 291 | } | 
 | 292 |  | 
| Juan Cespedes | f135052 | 2008-12-16 18:19:58 +0100 | [diff] [blame] | 293 | void | 
| Petr Machata | bc37326 | 2012-02-07 23:31:15 +0100 | [diff] [blame] | 294 | enable_all_breakpoints(Process *proc) | 
 | 295 | { | 
| Juan Cespedes | cd8976d | 2009-05-14 13:47:58 +0200 | [diff] [blame] | 296 | 	debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); | 
| Petr Machata | 61196a4 | 2012-02-07 16:41:03 +0100 | [diff] [blame] | 297 |  | 
 | 298 | 	debug(1, "Enabling breakpoints for pid %u...", proc->pid); | 
 | 299 | 	if (proc->breakpoints) { | 
 | 300 | 		dict_apply_to_all(proc->breakpoints, enable_bp_cb, | 
 | 301 | 				  proc); | 
 | 302 | 	} | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 303 | } | 
 | 304 |  | 
| Juan Cespedes | f135052 | 2008-12-16 18:19:58 +0100 | [diff] [blame] | 305 | static void | 
| Petr Machata | fed1e8d | 2012-02-07 02:06:29 +0100 | [diff] [blame] | 306 | disable_bp_cb(void *addr, void *sbp, void *proc) | 
 | 307 | { | 
| Juan Cespedes | cd8976d | 2009-05-14 13:47:58 +0200 | [diff] [blame] | 308 | 	debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); | 
| Petr Machata | bc37326 | 2012-02-07 23:31:15 +0100 | [diff] [blame] | 309 | 	if (((struct breakpoint *)sbp)->enabled) | 
| Petr Machata | f789c9c | 2011-07-09 10:54:27 +0200 | [diff] [blame] | 310 | 		disable_breakpoint(proc, sbp); | 
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 311 | } | 
 | 312 |  | 
| Juan Cespedes | f135052 | 2008-12-16 18:19:58 +0100 | [diff] [blame] | 313 | void | 
| Juan Cespedes | a8909f7 | 2009-04-28 20:02:41 +0200 | [diff] [blame] | 314 | disable_all_breakpoints(Process *proc) { | 
| Juan Cespedes | cd8976d | 2009-05-14 13:47:58 +0200 | [diff] [blame] | 315 | 	debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); | 
| Petr Machata | 9a5420c | 2011-07-09 11:21:23 +0200 | [diff] [blame] | 316 | 	assert(proc->leader == proc); | 
| Petr Machata | 61196a4 | 2012-02-07 16:41:03 +0100 | [diff] [blame] | 317 | 	dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 318 | } | 
| Juan Cespedes | 7186e2a | 2003-01-31 19:56:34 +0100 | [diff] [blame] | 319 |  | 
| Petr Machata | d09d240 | 2012-04-13 21:34:08 +0200 | [diff] [blame] | 320 | /* XXX This is not currently properly supported.  On clone, this is | 
 | 321 |  * just sliced.  Hopefully at the point that clone is done, this | 
 | 322 |  * breakpoint is not necessary anymore.  If this use case ends up | 
 | 323 |  * being important, we need to add a clone and destroy callbacks to | 
 | 324 |  * breakpoints, and we should also probably drop arch_breakpoint_data | 
 | 325 |  * so that we don't end up with two different customization mechanisms | 
 | 326 |  * for one structure.  */ | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 327 | struct entry_breakpoint { | 
 | 328 | 	struct breakpoint super; | 
| Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 329 | 	arch_addr_t dyn_addr; | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 330 | }; | 
 | 331 |  | 
| Petr Machata | 02648a1 | 2012-02-07 13:44:54 +0100 | [diff] [blame] | 332 | static void | 
| Petr Machata | 12affff | 2012-03-29 18:33:03 +0200 | [diff] [blame] | 333 | entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc) | 
| Petr Machata | 02648a1 | 2012-02-07 13:44:54 +0100 | [diff] [blame] | 334 | { | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 335 | 	struct entry_breakpoint *bp = (void *)a; | 
| Petr Machata | 02648a1 | 2012-02-07 13:44:54 +0100 | [diff] [blame] | 336 | 	if (proc == NULL || proc->leader == NULL) | 
 | 337 | 		return; | 
| Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 338 | 	arch_addr_t dyn_addr = bp->dyn_addr; | 
| Petr Machata | 3fd099b | 2012-04-03 02:25:42 +0200 | [diff] [blame] | 339 | 	delete_breakpoint(proc, bp->super.addr); | 
| Petr Machata | 5ee3682 | 2012-04-19 17:01:51 +0200 | [diff] [blame] | 340 | 	linkmap_init(proc, dyn_addr); | 
| Petr Machata | 93d95df | 2012-04-17 05:16:19 +0200 | [diff] [blame] | 341 | 	arch_dynlink_done(proc); | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 342 | } | 
 | 343 |  | 
 | 344 | int | 
 | 345 | entry_breakpoint_init(struct Process *proc, | 
| Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 346 | 		      struct entry_breakpoint *bp, arch_addr_t addr, | 
| Petr Machata | 9a04d0e | 2012-03-29 16:50:38 +0200 | [diff] [blame] | 347 | 		      struct library *lib) | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 348 | { | 
| Petr Machata | 1c79025 | 2012-10-30 23:29:27 +0100 | [diff] [blame] | 349 | 	assert(addr != 0); | 
 | 350 | 	int err = breakpoint_init(&bp->super, proc, addr, NULL); | 
 | 351 | 	if (err < 0) | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 352 | 		return err; | 
 | 353 |  | 
 | 354 | 	static struct bp_callbacks entry_callbacks = { | 
| Petr Machata | 12affff | 2012-03-29 18:33:03 +0200 | [diff] [blame] | 355 | 		.on_hit = entry_breakpoint_on_hit, | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 356 | 	}; | 
 | 357 | 	bp->super.cbs = &entry_callbacks; | 
| Petr Machata | 9a04d0e | 2012-03-29 16:50:38 +0200 | [diff] [blame] | 358 | 	bp->dyn_addr = lib->dyn_addr; | 
| Petr Machata | 52dbfb1 | 2012-03-29 16:38:26 +0200 | [diff] [blame] | 359 | 	return 0; | 
| Petr Machata | 02648a1 | 2012-02-07 13:44:54 +0100 | [diff] [blame] | 360 | } | 
 | 361 |  | 
| Petr Machata | 1974dbc | 2011-08-19 18:58:01 +0200 | [diff] [blame] | 362 | int | 
| Petr Machata | 75934ad | 2012-04-14 02:28:03 +0200 | [diff] [blame] | 363 | breakpoints_init(Process *proc) | 
| Petr Machata | c7585b6 | 2011-07-08 22:58:12 +0200 | [diff] [blame] | 364 | { | 
| Juan Cespedes | cd8976d | 2009-05-14 13:47:58 +0200 | [diff] [blame] | 365 | 	debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); | 
| Petr Machata | 2662768 | 2011-07-08 18:15:32 +0200 | [diff] [blame] | 366 |  | 
| Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 367 | 	/* XXX breakpoint dictionary should be initialized | 
 | 368 | 	 * outside.  Here we just put in breakpoints.  */ | 
 | 369 | 	assert(proc->breakpoints != NULL); | 
 | 370 |  | 
 | 371 | 	/* Only the thread group leader should hold the breakpoints.  */ | 
| Petr Machata | 9a5420c | 2011-07-09 11:21:23 +0200 | [diff] [blame] | 372 | 	assert(proc->leader == proc); | 
 | 373 |  | 
| Petr Machata | 807cdd8 | 2012-04-05 02:08:25 +0200 | [diff] [blame] | 374 | 	/* N.B. the following used to be conditional on this, and | 
 | 375 | 	 * maybe it still needs to be.  */ | 
 | 376 | 	assert(proc->filename != NULL); | 
 | 377 |  | 
 | 378 | 	struct library *lib = ltelf_read_main_binary(proc, proc->filename); | 
 | 379 | 	struct entry_breakpoint *entry_bp = NULL; | 
 | 380 | 	int bp_state = 0; | 
 | 381 | 	int result = -1; | 
 | 382 | 	switch (lib != NULL) { | 
 | 383 | 	fail: | 
| Petr Machata | 807cdd8 | 2012-04-05 02:08:25 +0200 | [diff] [blame] | 384 | 		switch (bp_state) { | 
 | 385 | 		case 2: | 
| Petr Machata | a241636 | 2012-04-06 02:43:34 +0200 | [diff] [blame] | 386 | 			proc_remove_library(proc, lib); | 
| Petr Machata | 807cdd8 | 2012-04-05 02:08:25 +0200 | [diff] [blame] | 387 | 			proc_remove_breakpoint(proc, &entry_bp->super); | 
 | 388 | 		case 1: | 
 | 389 | 			breakpoint_destroy(&entry_bp->super); | 
| Petr Machata | 1974dbc | 2011-08-19 18:58:01 +0200 | [diff] [blame] | 390 | 		} | 
| Petr Machata | a241636 | 2012-04-06 02:43:34 +0200 | [diff] [blame] | 391 | 		library_destroy(lib); | 
| Petr Machata | 807cdd8 | 2012-04-05 02:08:25 +0200 | [diff] [blame] | 392 | 		free(entry_bp); | 
 | 393 | 	case 0: | 
 | 394 | 		return result; | 
| Petr Machata | 02648a1 | 2012-02-07 13:44:54 +0100 | [diff] [blame] | 395 | 	} | 
 | 396 |  | 
| Petr Machata | 807cdd8 | 2012-04-05 02:08:25 +0200 | [diff] [blame] | 397 | 	entry_bp = malloc(sizeof(*entry_bp)); | 
 | 398 | 	if (entry_bp == NULL | 
| Petr Machata | 91c399c | 2012-05-15 12:17:51 +0200 | [diff] [blame] | 399 | 	    || (entry_breakpoint_init(proc, entry_bp, | 
 | 400 | 				      lib->entry, lib)) < 0) { | 
 | 401 | 		fprintf(stderr, | 
 | 402 | 			"Couldn't initialize entry breakpoint for PID %d.\n" | 
 | 403 | 			"Some tracing events may be missed.\n", proc->pid); | 
 | 404 | 		free(entry_bp); | 
| Petr Machata | 0092820 | 2012-04-07 01:14:24 +0200 | [diff] [blame] | 405 |  | 
| Petr Machata | 91c399c | 2012-05-15 12:17:51 +0200 | [diff] [blame] | 406 | 	} else { | 
 | 407 | 		++bp_state; | 
| Petr Machata | 0092820 | 2012-04-07 01:14:24 +0200 | [diff] [blame] | 408 |  | 
| Petr Machata | 91c399c | 2012-05-15 12:17:51 +0200 | [diff] [blame] | 409 | 		if ((result = proc_add_breakpoint(proc, &entry_bp->super)) < 0) | 
 | 410 | 			goto fail; | 
 | 411 | 		++bp_state; | 
 | 412 |  | 
 | 413 | 		if ((result = breakpoint_turn_on(&entry_bp->super, proc)) < 0) | 
 | 414 | 			goto fail; | 
 | 415 | 	} | 
| Petr Machata | a241636 | 2012-04-06 02:43:34 +0200 | [diff] [blame] | 416 | 	proc_add_library(proc, lib); | 
 | 417 |  | 
| Juan Cespedes | 7186e2a | 2003-01-31 19:56:34 +0100 | [diff] [blame] | 418 | 	proc->callstack_depth = 0; | 
| Petr Machata | 1974dbc | 2011-08-19 18:58:01 +0200 | [diff] [blame] | 419 | 	return 0; | 
| Juan Cespedes | 7186e2a | 2003-01-31 19:56:34 +0100 | [diff] [blame] | 420 | } |