fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 522 lines 8.4 kB view raw
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}