breakpoints.c revision a413e5b8880de643a83ad124d078091c0956fe1d
1#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <stdlib.h>
6#include <string.h>
7#include <assert.h>
8
9#ifdef __powerpc__
10#include <sys/ptrace.h>
11#endif
12
13#include "ltrace.h"
14#include "options.h"
15#include "debug.h"
16#include "dict.h"
17#include "elf.h"
18
19/*****************************************************************************/
20
21struct breakpoint *address2bpstruct(struct process *proc, void *addr)
22{
23	return dict_find_entry(proc->breakpoints, addr);
24}
25
26void
27insert_breakpoint(struct process *proc, void *addr,
28		  struct library_symbol *libsym)
29{
30	struct breakpoint *sbp;
31	debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr);
32
33	if (!addr)
34		return;
35
36	if (libsym)
37		libsym->needs_init = 0;
38
39	sbp = dict_find_entry(proc->breakpoints, addr);
40	if (!sbp) {
41		sbp = calloc(1, sizeof(struct breakpoint));
42		if (!sbp) {
43			return;	/* TODO FIXME XXX: error_mem */
44		}
45		dict_enter(proc->breakpoints, addr, sbp);
46		sbp->addr = addr;
47		sbp->libsym = libsym;
48		if (libsym)
49			libsym->brkpnt = sbp;
50	}
51	sbp->enabled++;
52	if (sbp->enabled == 1 && proc->pid)
53		enable_breakpoint(proc->pid, sbp);
54}
55
56void delete_breakpoint(struct process *proc, void *addr)
57{
58	struct breakpoint *sbp = dict_find_entry(proc->breakpoints, addr);
59	assert(sbp);		/* FIXME: remove after debugging has been done. */
60	/* This should only happen on out-of-memory conditions. */
61	if (sbp == NULL)
62		return;
63
64	sbp->enabled--;
65	if (sbp->enabled == 0)
66		disable_breakpoint(proc->pid, sbp);
67	assert(sbp->enabled >= 0);
68}
69
70static void enable_bp_cb(void *addr, void *sbp, void *proc)
71{
72	if (((struct breakpoint *)sbp)->enabled) {
73		enable_breakpoint(((struct process *)proc)->pid, sbp);
74	}
75}
76
77void enable_all_breakpoints(struct process *proc)
78{
79	if (proc->breakpoints_enabled <= 0) {
80#ifdef __powerpc__
81		unsigned long a;
82
83		/*
84		 * PPC HACK! (XXX FIXME TODO)
85		 * If the dynamic linker hasn't populated the PLT then
86		 * dont enable the breakpoints
87		 */
88		if (opt_L) {
89			a = ptrace(PTRACE_PEEKTEXT, proc->pid,
90				   sym2addr(proc, proc->list_of_symbols),
91				   0);
92			if (a == 0x0)
93				return;
94		}
95#endif
96
97		debug(1, "Enabling breakpoints for pid %u...", proc->pid);
98		if (proc->breakpoints) {
99			dict_apply_to_all(proc->breakpoints, enable_bp_cb,
100					  proc);
101		}
102#ifdef __mips__
103		{
104			// I'm sure there is a nicer way to do this. We need to
105			// insert breakpoints _after_ the child has been started.
106			struct library_symbol *sym;
107			struct library_symbol *new_sym;
108			sym=proc->list_of_symbols;
109			while(sym){
110				void *addr= sym2addr(proc,sym);
111				if(!addr){
112					sym=sym->next;
113					continue;
114				}
115				if(dict_find_entry(proc->breakpoints,addr)){
116					sym=sym->next;
117					continue;
118				}
119				debug(2,"inserting bp %p %s",addr,sym->name);
120				new_sym=malloc(sizeof(*new_sym));
121				memcpy(new_sym,sym,sizeof(*new_sym));
122				new_sym->next=proc->list_of_symbols;
123				proc->list_of_symbols=new_sym;
124				new_sym->brkpnt=0;
125				insert_breakpoint(proc, addr, new_sym);
126				sym=sym->next;
127			}
128		}
129#endif
130	}
131	proc->breakpoints_enabled = 1;
132}
133
134static void disable_bp_cb(void *addr, void *sbp, void *proc)
135{
136	if (((struct breakpoint *)sbp)->enabled) {
137		disable_breakpoint(((struct process *)proc)->pid, sbp);
138	}
139}
140
141void disable_all_breakpoints(struct process *proc)
142{
143	if (proc->breakpoints_enabled) {
144		debug(1, "Disabling breakpoints for pid %u...", proc->pid);
145		dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
146	}
147	proc->breakpoints_enabled = 0;
148}
149
150static void free_bp_cb(void *addr, void *sbp, void *data)
151{
152	assert(sbp);
153	free(sbp);
154}
155
156void breakpoints_init(struct process *proc)
157{
158	struct library_symbol *sym;
159
160	if (proc->breakpoints) {	/* let's remove that struct */
161		dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL);
162		dict_clear(proc->breakpoints);
163		proc->breakpoints = NULL;
164	}
165	proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int);
166
167	if (opt_L && proc->filename) {
168		proc->list_of_symbols = read_elf(proc);
169		if (opt_e) {
170			struct library_symbol **tmp1 = &(proc->list_of_symbols);
171			while (*tmp1) {
172				struct opt_e_t *tmp2 = opt_e;
173				int keep = !opt_e_enable;
174
175				while (tmp2) {
176					if (!strcmp((*tmp1)->name, tmp2->name)) {
177						keep = opt_e_enable;
178					}
179					tmp2 = tmp2->next;
180				}
181				if (!keep) {
182					*tmp1 = (*tmp1)->next;
183				} else {
184					tmp1 = &((*tmp1)->next);
185				}
186			}
187		}
188	} else {
189		proc->list_of_symbols = NULL;
190	}
191	for (sym = proc->list_of_symbols; sym; sym = sym->next) {
192		/* proc->pid==0 delays enabling. */
193		insert_breakpoint(proc, sym2addr(proc, sym), sym);
194	}
195	proc->callstack_depth = 0;
196	proc->breakpoints_enabled = -1;
197}
198
199void reinitialize_breakpoints(struct process *proc)
200{
201	struct library_symbol *sym = proc->list_of_symbols;
202
203	while (sym) {
204		if (sym->needs_init) {
205			insert_breakpoint(proc, sym2addr(proc, sym),
206					  sym);
207			if (sym->needs_init && !sym->is_weak) {
208				fprintf(stderr,
209					"could not re-initialize breakpoint for \"%s\" in file \"%s\"\n",
210					sym->name, proc->filename);
211				exit(1);
212			}
213		}
214		sym = sym->next;
215	}
216}
217