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