blob: 9d1f11469691c5528ed679d6ba3667989396e9c7 [file] [log] [blame]
Juan Cespedesd44c6b81998-09-25 14:48:42 +02001#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
Juan Cespedes5e01f651998-03-08 22:31:44 +01005#include "ltrace.h"
6#include "options.h"
7#include "output.h"
8
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +02009#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
Juan Cespedes5e01f651998-03-08 22:31:44 +0100156void enable_all_breakpoints(struct process * proc)
157{
158 if (proc->breakpoints_enabled <= 0) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100159 if (opt_d>0) {
160 output_line(0, "Enabling breakpoints for pid %u...", proc->pid);
161 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200162 dict_apply_to_all(enable_bp_cb, proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100163 }
164 proc->breakpoints_enabled = 1;
165}
166
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200167static 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
Juan Cespedes5e01f651998-03-08 22:31:44 +0100173void disable_all_breakpoints(struct process * proc)
174{
175 if (proc->breakpoints_enabled) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100176 if (opt_d>0) {
177 output_line(0, "Disabling breakpoints for pid %u...", proc->pid);
178 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200179 dict_apply_to_all(disable_bp_cb, proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100180 }
181 proc->breakpoints_enabled = 0;
182}