breakpoints.c revision 5b3ffdf2e696273d38434ff7b3c26349fff5a0ea
1#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include "ltrace.h"
6#include "options.h"
7#include "output.h"
8
9#include <stdlib.h>
10#include <assert.h>
11
12/*****************************************************************************/
13
14/*
15  Dictionary code done by Morten Eriksen <mortene@sim.no>.
16
17  FIXME: should we merge with dictionary code in demangle.c? 19990704 mortene.
18*/
19
20struct dict_entry
21{
22	struct process * proc;
23	struct breakpoint brk; /* addr field of struct is the hash key. */
24	struct dict_entry * next;
25};
26
27#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
28static struct dict_entry * dict_buckets[DICTTABLESIZE];
29static int dict_initialized = 0;
30
31static void dict_init(void);
32static void dict_clear(void);
33static struct breakpoint * dict_enter(struct process * proc, void * brkaddr);
34static struct breakpoint * dict_find_entry(struct process * proc, void * brkaddr);
35static void dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data);
36
37
38static void dict_init(void)
39{
40	int i;
41	/* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */
42	for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL;
43	dict_initialized = 1;
44}
45
46static void dict_clear(void)
47{
48	int i;
49	struct dict_entry * entry, * nextentry;
50
51	for (i = 0; i < DICTTABLESIZE; i++) {
52		for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) {
53			nextentry = entry->next;
54			free(entry);
55		}
56		dict_buckets[i] = NULL;
57	}
58}
59
60static struct breakpoint * dict_enter(struct process * proc, void * brkaddr)
61{
62	struct dict_entry * entry, * newentry;
63	unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE;
64
65	newentry = malloc(sizeof(struct dict_entry));
66	if (!newentry) {
67		perror("malloc");
68		return NULL;
69	}
70
71	newentry->proc = proc;
72	newentry->brk.addr = brkaddr;
73	newentry->brk.enabled = 0;
74	newentry->next = NULL;
75
76	entry = dict_buckets[bucketpos];
77	while (entry && entry->next) entry = entry->next;
78
79	if (entry) entry->next = newentry;
80	else dict_buckets[bucketpos] = newentry;
81
82	if (opt_d > 2)
83		output_line(0, "new brk dict entry at %p\n", brkaddr);
84
85	return &(newentry->brk);
86}
87
88static struct breakpoint * dict_find_entry(struct process * proc, void * brkaddr)
89{
90	unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE;
91	struct dict_entry * entry = dict_buckets[bucketpos];
92	while (entry) {
93		if ((entry->brk.addr == brkaddr) && (entry->proc == proc)) break;
94		entry = entry->next;
95	}
96	return entry ? &(entry->brk) : NULL;
97}
98
99static void dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data)
100{
101	int i;
102
103	for (i = 0; i < DICTTABLESIZE; i++) {
104		struct dict_entry * entry = dict_buckets[i];
105		while (entry) {
106			func(entry->proc, &(entry->brk), data);
107			entry = entry->next;
108		}
109	}
110}
111
112#undef DICTTABLESIZE
113
114/*****************************************************************************/
115
116struct breakpoint * address2bpstruct(struct process * proc, void * addr)
117{
118	return dict_find_entry(proc, addr);
119}
120
121void insert_breakpoint(struct process * proc, void * addr)
122{
123	struct breakpoint * sbp;
124
125	if (!dict_initialized) {
126		dict_init();
127		atexit(dict_clear);
128	}
129
130	sbp = dict_find_entry(proc, addr);
131	if (!sbp) sbp = dict_enter(proc, addr);
132	if (!sbp) return;
133
134	sbp->enabled++;
135	if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp);
136}
137
138void delete_breakpoint(struct process * proc, void * addr)
139{
140	struct breakpoint * sbp = dict_find_entry(proc, addr);
141	assert(sbp); /* FIXME: remove after debugging has been done. */
142	/* This should only happen on out-of-memory conditions. */
143	if (sbp == NULL) return;
144
145	sbp->enabled--;
146	if (sbp->enabled == 0) disable_breakpoint(proc->pid, sbp);
147	assert(sbp->enabled >= 0);
148}
149
150static void enable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data)
151{
152	struct process * myproc = (struct process *)data;
153	if (myproc == proc && sbp->enabled) enable_breakpoint(proc->pid, sbp);
154}
155
156void enable_all_breakpoints(struct process * proc)
157{
158	if (proc->breakpoints_enabled <= 0) {
159		if (opt_d>0) {
160			output_line(0, "Enabling breakpoints for pid %u...", proc->pid);
161		}
162		dict_apply_to_all(enable_bp_cb, proc);
163	}
164	proc->breakpoints_enabled = 1;
165}
166
167static void disable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data)
168{
169	struct process * myproc = (struct process *)data;
170	if (myproc == proc && sbp->enabled) disable_breakpoint(proc->pid, sbp);
171}
172
173void disable_all_breakpoints(struct process * proc)
174{
175	if (proc->breakpoints_enabled) {
176		if (opt_d>0) {
177			output_line(0, "Disabling breakpoints for pid %u...", proc->pid);
178		}
179		dict_apply_to_all(disable_bp_cb, proc);
180	}
181	proc->breakpoints_enabled = 0;
182}
183