blob: 2d1822233ad407385a298f8d149ae93adc4a4f0d [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
Juan Cespedesf1bfe202002-03-27 00:22:23 +010012#ifdef __powerpc__
13#include <sys/ptrace.h>
14#endif
15
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020016/*****************************************************************************/
17
18/*
19 Dictionary code done by Morten Eriksen <mortene@sim.no>.
20
21 FIXME: should we merge with dictionary code in demangle.c? 19990704 mortene.
22*/
23
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010024struct dict_entry {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020025 struct process * proc;
26 struct breakpoint brk; /* addr field of struct is the hash key. */
27 struct dict_entry * next;
28};
29
30#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
31static struct dict_entry * dict_buckets[DICTTABLESIZE];
32static int dict_initialized = 0;
33
34static void dict_init(void);
35static void dict_clear(void);
36static struct breakpoint * dict_enter(struct process * proc, void * brkaddr);
Juan Cespedes5bfb0612002-03-31 20:01:28 +020037struct breakpoint * dict_find_entry(struct process * proc, void * brkaddr);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020038static void dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data);
39
40
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010041static void
42dict_init(void) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020043 int i;
44 /* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */
45 for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL;
46 dict_initialized = 1;
47}
48
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010049static void
50dict_clear(void) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020051 int i;
52 struct dict_entry * entry, * nextentry;
53
54 for (i = 0; i < DICTTABLESIZE; i++) {
55 for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) {
56 nextentry = entry->next;
57 free(entry);
58 }
59 dict_buckets[i] = NULL;
60 }
61}
62
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010063static struct breakpoint *
64dict_enter(struct process * proc, void * brkaddr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020065 struct dict_entry * entry, * newentry;
66 unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE;
67
68 newentry = malloc(sizeof(struct dict_entry));
69 if (!newentry) {
70 perror("malloc");
71 return NULL;
72 }
73
74 newentry->proc = proc;
75 newentry->brk.addr = brkaddr;
76 newentry->brk.enabled = 0;
77 newentry->next = NULL;
78
79 entry = dict_buckets[bucketpos];
80 while (entry && entry->next) entry = entry->next;
81
82 if (entry) entry->next = newentry;
83 else dict_buckets[bucketpos] = newentry;
84
85 if (opt_d > 2)
86 output_line(0, "new brk dict entry at %p\n", brkaddr);
87
88 return &(newentry->brk);
89}
90
Juan Cespedes5bfb0612002-03-31 20:01:28 +020091struct breakpoint *
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010092dict_find_entry(struct process * proc, void * brkaddr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020093 unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE;
94 struct dict_entry * entry = dict_buckets[bucketpos];
95 while (entry) {
96 if ((entry->brk.addr == brkaddr) && (entry->proc == proc)) break;
97 entry = entry->next;
98 }
99 return entry ? &(entry->brk) : NULL;
100}
101
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100102static void
103dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200104 int i;
105
106 for (i = 0; i < DICTTABLESIZE; i++) {
107 struct dict_entry * entry = dict_buckets[i];
108 while (entry) {
109 func(entry->proc, &(entry->brk), data);
110 entry = entry->next;
111 }
112 }
113}
114
115#undef DICTTABLESIZE
116
117/*****************************************************************************/
118
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100119struct breakpoint *
120address2bpstruct(struct process * proc, void * addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200121 return dict_find_entry(proc, addr);
122}
123
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100124void
125insert_breakpoint(struct process * proc, void * addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200126 struct breakpoint * sbp;
127
128 if (!dict_initialized) {
129 dict_init();
130 atexit(dict_clear);
131 }
132
133 sbp = dict_find_entry(proc, addr);
134 if (!sbp) sbp = dict_enter(proc, addr);
135 if (!sbp) return;
136
137 sbp->enabled++;
138 if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp);
139}
140
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100141void
142delete_breakpoint(struct process * proc, void * addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200143 struct breakpoint * sbp = dict_find_entry(proc, addr);
144 assert(sbp); /* FIXME: remove after debugging has been done. */
145 /* This should only happen on out-of-memory conditions. */
146 if (sbp == NULL) return;
147
148 sbp->enabled--;
149 if (sbp->enabled == 0) disable_breakpoint(proc->pid, sbp);
150 assert(sbp->enabled >= 0);
151}
152
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100153static void
154enable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200155 struct process * myproc = (struct process *)data;
156 if (myproc == proc && sbp->enabled) enable_breakpoint(proc->pid, sbp);
157}
158
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100159void
160enable_all_breakpoints(struct process * proc) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100161 if (proc->breakpoints_enabled <= 0) {
Juan Cespedesf1bfe202002-03-27 00:22:23 +0100162#ifdef __powerpc__
163 unsigned long a;
164
165 /*
166 * PPC HACK! (XXX FIXME TODO)
167 * If the dynamic linker hasn't populated the PLT then
168 * dont enable the breakpoints
169 */
170 a = ptrace(PTRACE_PEEKTEXT, proc->pid, proc->list_of_symbols->enter_addr, 0);
171 if (a == 0x0)
172 return;
173#endif
174
Juan Cespedes5e01f651998-03-08 22:31:44 +0100175 if (opt_d>0) {
176 output_line(0, "Enabling breakpoints for pid %u...", proc->pid);
177 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200178 dict_apply_to_all(enable_bp_cb, proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100179 }
180 proc->breakpoints_enabled = 1;
181}
182
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100183static void
184disable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200185 struct process * myproc = (struct process *)data;
186 if (myproc == proc && sbp->enabled) disable_breakpoint(proc->pid, sbp);
187}
188
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100189void
190disable_all_breakpoints(struct process * proc) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100191 if (proc->breakpoints_enabled) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100192 if (opt_d>0) {
193 output_line(0, "Disabling breakpoints for pid %u...", proc->pid);
194 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200195 dict_apply_to_all(disable_bp_cb, proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100196 }
197 proc->breakpoints_enabled = 0;
198}