fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/lib/brkpt.c *
7 * Created: 2004-05-25 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2004-2013 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26
27#include "brkpt.h"
28#include "cmd.h"
29
30
31breakpoint_t *bp_new (unsigned type)
32{
33 breakpoint_t *bp;
34
35 bp = malloc (sizeof (breakpoint_t));
36 if (bp == NULL) {
37 return (NULL);
38 }
39
40 bp->type = type;
41
42 bp->del = NULL;
43 bp->match = NULL;
44 bp->print = NULL;
45
46 bp->pass = 0;
47 bp->reset = 0;
48
49 return (bp);
50}
51
52void bp_set_pass (breakpoint_t *bp, unsigned pass, unsigned reset)
53{
54 bp->pass = pass;
55 bp->reset = reset;
56}
57
58unsigned bp_get_pass (breakpoint_t *bp)
59{
60 return (bp->pass);
61}
62
63void bp_del (breakpoint_t *bp)
64{
65 if (bp->del != NULL) {
66 bp->del (bp);
67 }
68 else {
69 free (bp);
70 }
71}
72
73int bp_match (breakpoint_t *bp, unsigned seg, unsigned long addr)
74{
75 int r;
76
77 if (bp->match != NULL) {
78 r = bp->match (bp, seg, addr);
79 }
80 else {
81 r = 0;
82 }
83
84 if (r) {
85 if (bp->pass > 0) {
86 bp->pass -= 1;
87 }
88
89 if (bp->pass == 0) {
90 if (bp->reset > 0) {
91 bp->pass = bp->reset;
92 }
93
94 return (1);
95 }
96 }
97
98 return (0);
99}
100
101void bp_print (breakpoint_t *bp, FILE *fp)
102{
103 if (bp->print != NULL) {
104 return (bp->print (bp, fp));
105 }
106}
107
108
109static
110void bp_addr_del (breakpoint_t *bp)
111{
112 free (bp);
113}
114
115static
116int bp_addr_match (breakpoint_t *bp, unsigned seg, unsigned long addr)
117{
118 addr += (unsigned long) seg << 4;
119
120 if (bp->addr == addr) {
121 return (1);
122 }
123
124 return (0);
125}
126
127static
128void bp_addr_print (breakpoint_t *bp, FILE *fp)
129{
130 printf ("A %08lX %04X %04X\n",
131 bp->addr, bp->pass, bp->reset
132 );
133}
134
135breakpoint_t *bp_addr_new (unsigned long addr)
136{
137 breakpoint_t *bp;
138
139 bp = bp_new (BP_TYPE_ADDR);
140 if (bp == NULL) {
141 return (NULL);
142 }
143
144 bp->del = bp_addr_del;
145 bp->match = bp_addr_match;
146 bp->print = bp_addr_print;
147
148 bp->seg = 0;
149 bp->addr = addr;
150
151 return (bp);
152}
153
154
155static
156void bp_segofs_del (breakpoint_t *bp)
157{
158 free (bp);
159}
160
161static
162int bp_segofs_match (breakpoint_t *bp, unsigned seg, unsigned long addr)
163{
164 if ((bp->seg == seg) && (bp->addr == addr)) {
165 return (1);
166 }
167
168 return (0);
169}
170
171static
172void bp_segofs_print (breakpoint_t *bp, FILE *fp)
173{
174 printf ("S %04X:%04lX %04X %04X\n",
175 bp->seg, bp->addr, bp->pass, bp->reset
176 );
177}
178
179breakpoint_t *bp_segofs_new (unsigned short seg, unsigned short ofs)
180{
181 breakpoint_t *bp;
182
183 bp = bp_new (BP_TYPE_SEGOFS);
184
185 if (bp == NULL) {
186 return (NULL);
187 }
188
189 bp->del = bp_segofs_del;
190 bp->match = bp_segofs_match;
191 bp->print = bp_segofs_print;
192
193 bp->seg = seg;
194 bp->addr = ofs;
195
196 return (bp);
197}
198
199
200static
201void bp_expr_del (breakpoint_t *bp)
202{
203 free (bp->expr);
204 free (bp);
205}
206
207static
208int bp_expr_match (breakpoint_t *bp, unsigned seg, unsigned long addr)
209{
210 unsigned long val;
211 cmd_t cmd;
212
213 cmd_set_str (&cmd, bp->expr);
214
215 if (cmd_match_uint32 (&cmd, &val)) {
216 if (val) {
217 return (1);
218 }
219 }
220
221 return (0);
222}
223
224static
225void bp_expr_print (breakpoint_t *bp, FILE *fp)
226{
227 printf ("E \"%s\"\n", bp->expr);
228}
229
230breakpoint_t *bp_expr_new (const char *expr)
231{
232 breakpoint_t *bp;
233
234 bp = bp_new (BP_TYPE_EXPR);
235 if (bp == NULL) {
236 return (NULL);
237 }
238
239 bp->del = bp_expr_del;
240 bp->match = bp_expr_match;
241 bp->print = bp_expr_print;
242
243 bp->expr = strdup (expr);
244
245 return (bp);
246}
247
248
249
250void bps_init (bp_set_t *bps)
251{
252 bps->cnt = 0;
253 bps->bp = NULL;
254}
255
256void bps_free (bp_set_t *bps)
257{
258 unsigned i;
259
260 for (i = 0; i < bps->cnt; i++) {
261 bp_del (bps->bp[i]);
262 }
263
264 free (bps->bp);
265}
266
267int bps_bp_add (bp_set_t *bps, breakpoint_t *bp)
268{
269 breakpoint_t **tmp;
270
271 tmp = realloc (bps->bp, (bps->cnt + 1) * sizeof (breakpoint_t *));
272 if (tmp == NULL) {
273 return (1);
274 }
275
276 bps->bp = tmp;
277 bps->bp[bps->cnt] = bp;
278 bps->cnt += 1;
279
280 return (0);
281}
282
283breakpoint_t *bps_bp_get_index (bp_set_t *bps, unsigned idx)
284{
285 if (idx < bps->cnt) {
286 return (bps->bp[idx]);
287 }
288
289 return (NULL);
290}
291
292void bps_bp_del_index (bp_set_t *bps, unsigned idx)
293{
294 if (idx >= bps->cnt) {
295 return;
296 }
297
298 bp_del (bps->bp[idx]);
299
300 idx += 1;
301 while (idx < bps->cnt) {
302 bps->bp[idx - 1] = bps->bp[idx];
303 idx += 1;
304 }
305
306 bps->cnt -= 1;
307}
308
309void bps_bp_del (bp_set_t *bps, breakpoint_t *bp)
310{
311 unsigned i;
312
313 for (i = 0; i < bps->cnt; i++) {
314 if (bps->bp[i] == bp) {
315 bps_bp_del_index (bps, i);
316 return;
317 }
318 }
319}
320
321void bps_bp_del_all (bp_set_t *bps)
322{
323 unsigned i;
324
325 for (i = 0; i < bps->cnt; i++) {
326 bp_del (bps->bp[i]);
327 }
328
329 free (bps->bp);
330
331 bps->cnt = 0;
332 bps->bp = NULL;
333}
334
335void bps_list (bp_set_t *bps, FILE *fp)
336{
337 unsigned i;
338
339 for (i = 0; i < bps->cnt; i++) {
340 fprintf (fp, "%4u ", i);
341 bp_print (bps->bp[i], fp);
342 }
343
344 fflush (fp);
345}
346
347breakpoint_t *bps_match (bp_set_t *bps, unsigned seg, unsigned long addr)
348{
349 unsigned i;
350
351 for (i = 0; i < bps->cnt; i++) {
352 if (bp_match (bps->bp[i], seg, addr)) {
353 return (bps->bp[i]);
354 }
355 }
356
357 return (NULL);
358}
359
360/*
361 * Check if a breakpoint is triggered
362 */
363int bps_check (bp_set_t *bps, unsigned seg, unsigned long addr, FILE *fp)
364{
365 breakpoint_t *bp;
366
367 bp = bps_match (bps, seg, addr);
368
369 if (bp != NULL) {
370 bp_print (bp, fp);
371
372 if (bp_get_pass (bp) == 0) {
373 bps_bp_del (bps, bp);
374 }
375
376 return (1);
377 }
378
379 return (0);
380}
381
382
383static
384void cmd_do_bsa (cmd_t *cmd, bp_set_t *bps)
385{
386 int isseg;
387 unsigned seg;
388 unsigned long addr;
389 unsigned short pass, reset;
390 breakpoint_t *bp;
391
392 pass = 1;
393 reset = 0;
394
395 isseg = 0;
396 seg = 0;
397 addr = 0;
398
399 if (!cmd_match_uint32 (cmd, &addr)) {
400 cmd_error (cmd, "expecting address");
401 return;
402 }
403
404 if (cmd_match (cmd, ":")) {
405 seg = addr & 0xffff;
406
407 if (cmd_match_uint32 (cmd, &addr) == 0) {
408 cmd_error (cmd, "expecting offset");
409 return;
410 }
411
412 isseg = 1;
413 }
414
415 cmd_match_uint16 (cmd, &pass);
416 cmd_match_uint16 (cmd, &reset);
417
418 if (!cmd_match_end (cmd)) {
419 return;
420 }
421
422 if (pass > 0) {
423 if (isseg) {
424 bp = bp_segofs_new (seg, addr);
425 }
426 else {
427 bp = bp_addr_new (addr);
428 }
429
430 bp_set_pass (bp, pass, reset);
431 bp_print (bp, stdout);
432 bps_bp_add (bps, bp);
433 }
434}
435
436static
437void cmd_do_bsx (cmd_t *cmd, bp_set_t *bps)
438{
439 breakpoint_t *bp;
440 unsigned short pass, reset;
441 char expr[256];
442
443 pass = 1;
444 reset = 0;
445
446 if (!cmd_match_str (cmd, expr, 256)) {
447 cmd_error (cmd, "expecting expression");
448 return;
449 }
450
451 cmd_match_uint16 (cmd, &pass);
452 cmd_match_uint16 (cmd, &reset);
453
454 if (!cmd_match_end (cmd)) {
455 return;
456 }
457
458 if (pass > 0) {
459 bp = bp_expr_new (expr);
460 bp_set_pass (bp, pass, reset);
461
462 bp_print (bp, stdout);
463
464 bps_bp_add (bps, bp);
465 }
466}
467
468static
469void cmd_do_bs (cmd_t *cmd, bp_set_t *bps)
470{
471 if (cmd_match (cmd, "x")) {
472 cmd_do_bsx (cmd, bps);
473 }
474 else {
475 cmd_do_bsa (cmd, bps);
476 }
477}
478
479static
480void cmd_do_bc (cmd_t *cmd, bp_set_t *bps)
481{
482 unsigned short idx;
483
484 if (cmd_match_eol (cmd)) {
485 bps_bp_del_all (bps);
486 return;
487 }
488
489 while (cmd_match_uint16 (cmd, &idx)) {
490 bps_bp_del_index (bps, idx);
491 }
492
493 if (!cmd_match_end (cmd)) {
494 return;
495 }
496}
497
498static
499void cmd_do_bl (cmd_t *cmd, bp_set_t *bps)
500{
501 if (!cmd_match_end (cmd)) {
502 return;
503 }
504
505 bps_list (bps, stdout);
506}
507
508void cmd_do_b (cmd_t *cmd, bp_set_t *bps)
509{
510 if (cmd_match (cmd, "l")) {
511 cmd_do_bl (cmd, bps);
512 }
513 else if (cmd_match (cmd, "s")) {
514 cmd_do_bs (cmd, bps);
515 }
516 else if (cmd_match (cmd, "c")) {
517 cmd_do_bc (cmd, bps);
518 }
519 else {
520 cmd_error (cmd, "b: unknown command");
521 }
522}