Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/ddb/db_break.c
39476 views
1
/*-
2
* SPDX-License-Identifier: MIT-CMU
3
*
4
* Mach Operating System
5
* Copyright (c) 1991,1990 Carnegie Mellon University
6
* All Rights Reserved.
7
*
8
* Permission to use, copy, modify and distribute this software and its
9
* documentation is hereby granted, provided that both the copyright
10
* notice and this permission notice appear in all copies of the
11
* software, derivative works or modified versions, and any portions
12
* thereof, and that both notices appear in supporting documentation.
13
*
14
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17
*
18
* Carnegie Mellon requests users of this software to return to
19
*
20
* Software Distribution Coordinator or [email protected]
21
* School of Computer Science
22
* Carnegie Mellon University
23
* Pittsburgh PA 15213-3890
24
*
25
* any improvements or extensions that they make and grant Carnegie the
26
* rights to redistribute these changes.
27
*
28
*/
29
/*
30
* Author: David B. Golub, Carnegie Mellon University
31
* Date: 7/90
32
*/
33
/*
34
* Breakpoints.
35
*/
36
37
#include <sys/param.h>
38
#include <sys/systm.h>
39
#include <sys/kdb.h>
40
41
#include <vm/vm.h>
42
#include <vm/vm_kern.h>
43
44
#include <machine/kdb.h>
45
46
#include <ddb/ddb.h>
47
#include <ddb/db_break.h>
48
#include <ddb/db_access.h>
49
#include <ddb/db_sym.h>
50
51
struct db_breakpoint_type {
52
db_breakpoint_t db_next_free_breakpoint;
53
db_breakpoint_t db_breakpoint_limit;
54
db_breakpoint_t db_free_breakpoints;
55
db_breakpoint_t db_breakpoint_list;
56
};
57
58
#define NBREAKPOINTS 100
59
static struct db_breakpoint db_break_table[NBREAKPOINTS];
60
61
static struct db_breakpoint_type db_breakpoint = {
62
.db_next_free_breakpoint = &db_break_table[0],
63
.db_breakpoint_limit = &db_break_table[NBREAKPOINTS],
64
.db_free_breakpoints = NULL,
65
.db_breakpoint_list = NULL,
66
};
67
68
#ifdef HAS_HW_BREAKPOINT
69
static struct db_breakpoint db_hbreak_table[NHBREAKPOINTS];
70
71
static struct db_breakpoint_type db_hbreakpoint = {
72
.db_next_free_breakpoint = &db_hbreak_table[0],
73
.db_breakpoint_limit = &db_hbreak_table[NHBREAKPOINTS],
74
.db_free_breakpoints = NULL,
75
.db_breakpoint_list = NULL,
76
};
77
#endif
78
79
static db_breakpoint_t db_breakpoint_alloc(
80
struct db_breakpoint_type *bkpt_type);
81
static void db_breakpoint_free(struct db_breakpoint_type *bkpt_typ,
82
db_breakpoint_t bkpt);
83
static void db_delete_breakpoint(struct db_breakpoint_type *bkpt_type,
84
vm_map_t map, db_addr_t addr);
85
static db_breakpoint_t db_find_breakpoint(struct db_breakpoint_type *bkpt_type,
86
vm_map_t map, db_addr_t addr);
87
static void db_list_breakpoints(void);
88
static bool db_set_breakpoint(struct db_breakpoint_type *bkpt_type,
89
vm_map_t map, db_addr_t addr, int count);
90
91
static db_breakpoint_t
92
db_breakpoint_alloc(struct db_breakpoint_type *bkpt_type)
93
{
94
register db_breakpoint_t bkpt;
95
96
if ((bkpt = bkpt_type->db_free_breakpoints) != 0) {
97
bkpt_type->db_free_breakpoints = bkpt->link;
98
return (bkpt);
99
}
100
if (bkpt_type->db_next_free_breakpoint ==
101
bkpt_type->db_breakpoint_limit) {
102
db_printf("All breakpoints used.\n");
103
return (0);
104
}
105
bkpt = bkpt_type->db_next_free_breakpoint;
106
bkpt_type->db_next_free_breakpoint++;
107
108
return (bkpt);
109
}
110
111
static void
112
db_breakpoint_free(struct db_breakpoint_type *bkpt_type, db_breakpoint_t bkpt)
113
{
114
bkpt->link = bkpt_type->db_free_breakpoints;
115
bkpt_type->db_free_breakpoints = bkpt;
116
}
117
118
static bool
119
db_set_breakpoint(struct db_breakpoint_type *bkpt_type, vm_map_t map,
120
db_addr_t addr, int count)
121
{
122
register db_breakpoint_t bkpt;
123
124
if (db_find_breakpoint(bkpt_type, map, addr)) {
125
db_printf("Already set.\n");
126
return (false);
127
}
128
129
bkpt = db_breakpoint_alloc(bkpt_type);
130
if (bkpt == 0) {
131
db_printf("Too many breakpoints.\n");
132
return (false);
133
}
134
135
bkpt->map = map;
136
bkpt->address = addr;
137
bkpt->flags = 0;
138
bkpt->init_count = count;
139
bkpt->count = count;
140
141
bkpt->link = bkpt_type->db_breakpoint_list;
142
bkpt_type->db_breakpoint_list = bkpt;
143
144
return (true);
145
}
146
147
static void
148
db_delete_breakpoint(struct db_breakpoint_type *bkpt_type, vm_map_t map,
149
db_addr_t addr)
150
{
151
register db_breakpoint_t bkpt;
152
register db_breakpoint_t *prev;
153
154
for (prev = &bkpt_type->db_breakpoint_list;
155
(bkpt = *prev) != 0;
156
prev = &bkpt->link) {
157
if (db_map_equal(bkpt->map, map) &&
158
(bkpt->address == addr)) {
159
*prev = bkpt->link;
160
break;
161
}
162
}
163
if (bkpt == 0) {
164
db_printf("Not set.\n");
165
return;
166
}
167
168
db_breakpoint_free(bkpt_type, bkpt);
169
}
170
171
static db_breakpoint_t
172
db_find_breakpoint(struct db_breakpoint_type *bkpt_type, vm_map_t map,
173
db_addr_t addr)
174
{
175
register db_breakpoint_t bkpt;
176
177
for (bkpt = bkpt_type->db_breakpoint_list;
178
bkpt != 0;
179
bkpt = bkpt->link)
180
{
181
if (db_map_equal(bkpt->map, map) &&
182
(bkpt->address == addr))
183
return (bkpt);
184
}
185
return (0);
186
}
187
188
db_breakpoint_t
189
db_find_breakpoint_here(db_addr_t addr)
190
{
191
db_breakpoint_t bkpt;
192
193
bkpt = db_find_breakpoint(&db_breakpoint, db_map_addr(addr), addr);
194
#ifdef HAS_HW_BREAKPOINT
195
if (bkpt == NULL)
196
bkpt = db_find_breakpoint(&db_hbreakpoint, db_map_addr(addr),
197
addr);
198
#endif
199
200
return (bkpt);
201
}
202
203
static bool db_breakpoints_inserted = true;
204
205
#ifndef BKPT_WRITE
206
#define BKPT_WRITE(addr, storage) \
207
do { \
208
*storage = db_get_value(addr, BKPT_SIZE, false); \
209
db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage)); \
210
} while (0)
211
#endif
212
213
#ifndef BKPT_CLEAR
214
#define BKPT_CLEAR(addr, storage) \
215
db_put_value(addr, BKPT_SIZE, *storage)
216
#endif
217
218
/*
219
* Set software breakpoints.
220
*/
221
void
222
db_set_breakpoints(void)
223
{
224
register db_breakpoint_t bkpt;
225
226
if (!db_breakpoints_inserted) {
227
for (bkpt = db_breakpoint.db_breakpoint_list;
228
bkpt != 0;
229
bkpt = bkpt->link)
230
if (db_map_current(bkpt->map)) {
231
BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst);
232
}
233
db_breakpoints_inserted = true;
234
}
235
}
236
237
/*
238
* Clean software breakpoints.
239
*/
240
void
241
db_clear_breakpoints(void)
242
{
243
register db_breakpoint_t bkpt;
244
245
if (db_breakpoints_inserted) {
246
for (bkpt = db_breakpoint.db_breakpoint_list;
247
bkpt != 0;
248
bkpt = bkpt->link)
249
if (db_map_current(bkpt->map)) {
250
BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst);
251
}
252
db_breakpoints_inserted = false;
253
}
254
}
255
256
/*
257
* List software breakpoints.
258
*/
259
static void
260
db_list_breakpoints(void)
261
{
262
register db_breakpoint_t bkpt;
263
264
if (db_breakpoint.db_breakpoint_list == 0) {
265
db_printf("No breakpoints set\n");
266
return;
267
}
268
269
db_printf(" Map Count Address\n");
270
for (bkpt = db_breakpoint.db_breakpoint_list;
271
bkpt != 0;
272
bkpt = bkpt->link) {
273
db_printf("%s%8p %5d ",
274
db_map_current(bkpt->map) ? "*" : " ",
275
(void *)bkpt->map, bkpt->init_count);
276
db_printsym(bkpt->address, DB_STGY_PROC);
277
db_printf("\n");
278
}
279
}
280
281
/*
282
* Delete software breakpoint
283
*/
284
/*ARGSUSED*/
285
void
286
db_delete_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
287
{
288
db_delete_breakpoint(&db_breakpoint, db_map_addr(addr),
289
(db_addr_t)addr);
290
}
291
292
/*
293
* Set software breakpoint with skip count
294
*/
295
/*ARGSUSED*/
296
void
297
db_breakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
298
{
299
if (count == -1)
300
count = 1;
301
302
db_set_breakpoint(&db_breakpoint, db_map_addr(addr), (db_addr_t)addr,
303
count);
304
}
305
306
#ifdef HAS_HW_BREAKPOINT
307
/*
308
* Delete hardware breakpoint
309
*/
310
void
311
db_deletehbreak_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
312
char *modif)
313
{
314
if (count == -1)
315
count = 1;
316
317
if (kdb_cpu_clr_breakpoint(addr) != 0) {
318
db_printf("hardware breakpoint could not be delete\n");
319
return;
320
}
321
322
db_delete_breakpoint(&db_hbreakpoint, db_map_addr(addr),
323
(db_addr_t)addr);
324
}
325
326
/*
327
* Set hardware breakpoint
328
*/
329
void
330
db_hbreakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
331
{
332
if (count == -1)
333
count = 1;
334
335
if (!db_set_breakpoint(&db_hbreakpoint, db_map_addr(addr),
336
(db_addr_t)addr, count))
337
return;
338
339
if (kdb_cpu_set_breakpoint(addr) != 0) {
340
db_printf("hardware breakpoint could not be set\n");
341
db_delete_breakpoint(&db_hbreakpoint, db_map_addr(addr),
342
(db_addr_t)addr);
343
}
344
}
345
#endif
346
347
/* list breakpoints */
348
void
349
db_listbreak_cmd(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
350
{
351
db_list_breakpoints();
352
#ifdef HAS_HW_BREAKPOINT
353
db_md_list_breakpoints();
354
#endif
355
}
356
357
/*
358
* We want ddb to be usable before most of the kernel has been
359
* initialized. In particular, current_thread() or kernel_map
360
* (or both) may be null.
361
*/
362
363
bool
364
db_map_equal(vm_map_t map1, vm_map_t map2)
365
{
366
return ((map1 == map2) ||
367
((map1 == NULL) && (map2 == kernel_map)) ||
368
((map1 == kernel_map) && (map2 == NULL)));
369
}
370
371
bool
372
db_map_current(vm_map_t map)
373
{
374
#if 0
375
thread_t thread;
376
377
return ((map == NULL) ||
378
(map == kernel_map) ||
379
(((thread = current_thread()) != NULL) &&
380
(map == thread->task->map)));
381
#else
382
return (true);
383
#endif
384
}
385
386
vm_map_t
387
db_map_addr(vm_offset_t addr)
388
{
389
#if 0
390
thread_t thread;
391
392
/*
393
* We want to return kernel_map for all
394
* non-user addresses, even when debugging
395
* kernel tasks with their own maps.
396
*/
397
398
if ((VM_MIN_ADDRESS <= addr) &&
399
(addr < VM_MAX_ADDRESS) &&
400
((thread = current_thread()) != NULL))
401
return thread->task->map;
402
else
403
#endif
404
return kernel_map;
405
}
406
407