Mercurial > repos > blastem
comparison debug.c @ 2400:c97609fe8315
Implement watchpoints in Z80 debugger
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 23 Dec 2023 23:03:31 -0800 |
parents | bf4f1a8d1d48 |
children | 64cf80e683aa |
comparison
equal
deleted
inserted
replaced
2399:68eba54b60f7 | 2400:c97609fe8315 |
---|---|
4337 if (!*this_bp) { | 4337 if (!*this_bp) { |
4338 fprintf(stderr, "Breakpoint %d does not exist\n", index); | 4338 fprintf(stderr, "Breakpoint %d does not exist\n", index); |
4339 return 1; | 4339 return 1; |
4340 } | 4340 } |
4341 bp_def *tmp = *this_bp; | 4341 bp_def *tmp = *this_bp; |
4342 zremove_breakpoint(root->cpu_context, tmp->address); | 4342 if (tmp->type == BP_TYPE_CPU) { |
4343 zremove_breakpoint(root->cpu_context, tmp->address); | |
4344 } else if (tmp->type == BP_TYPE_CPU_WATCH) { | |
4345 z80_remove_watchpoint(root->cpu_context, tmp->address, tmp->mask); | |
4346 } | |
4343 *this_bp = (*this_bp)->next; | 4347 *this_bp = (*this_bp)->next; |
4344 if (tmp->commands) { | 4348 if (tmp->commands) { |
4345 for (uint32_t i = 0; i < tmp->num_commands; i++) | 4349 for (uint32_t i = 0; i < tmp->num_commands; i++) |
4346 { | 4350 { |
4347 free_parsed_command(tmp->commands + i); | 4351 free_parsed_command(tmp->commands + i); |
4366 new_bp->mask = 0xFFFF; | 4370 new_bp->mask = 0xFFFF; |
4367 new_bp->type = BP_TYPE_CPU; | 4371 new_bp->type = BP_TYPE_CPU; |
4368 new_bp->index = root->bp_index++; | 4372 new_bp->index = root->bp_index++; |
4369 root->breakpoints = new_bp; | 4373 root->breakpoints = new_bp; |
4370 printf("Z80 Breakpoint %d set at $%X\n", new_bp->index, address); | 4374 printf("Z80 Breakpoint %d set at $%X\n", new_bp->index, address); |
4375 return 1; | |
4376 } | |
4377 | |
4378 static uint8_t cmd_watchpoint_z80(debug_root *root, parsed_command *cmd) | |
4379 { | |
4380 uint32_t address; | |
4381 if (!debug_cast_int(cmd->args[0].value, &address)) { | |
4382 fprintf(stderr, "First argument to watchpoint must be an integer\n"); | |
4383 return 1; | |
4384 } | |
4385 uint32_t size = 1; | |
4386 if (cmd->num_args > 1) { | |
4387 if (!debug_cast_int(cmd->args[1].value, &size)) { | |
4388 fprintf(stderr, "Second argument to watchpoint must be an integer if provided\n"); | |
4389 return 1; | |
4390 } | |
4391 } | |
4392 z80_add_watchpoint(root->cpu_context, address, size); | |
4393 bp_def *new_bp = calloc(1, sizeof(bp_def)); | |
4394 new_bp->next = root->breakpoints; | |
4395 new_bp->address = address; | |
4396 new_bp->mask = size; | |
4397 new_bp->index = root->bp_index++; | |
4398 new_bp->type = BP_TYPE_CPU_WATCH; | |
4399 root->breakpoints = new_bp; | |
4400 printf("Z80 Watchpoint %d set for $%X\n", new_bp->index, address); | |
4371 return 1; | 4401 return 1; |
4372 } | 4402 } |
4373 | 4403 |
4374 static uint8_t cmd_advance_z80(debug_root *root, parsed_command *cmd) | 4404 static uint8_t cmd_advance_z80(debug_root *root, parsed_command *cmd) |
4375 { | 4405 { |
4567 .usage = "breakpoint ADDRESSS", | 4597 .usage = "breakpoint ADDRESSS", |
4568 .desc = "Set a breakpoint at ADDRESS", | 4598 .desc = "Set a breakpoint at ADDRESS", |
4569 .impl = cmd_breakpoint_z80, | 4599 .impl = cmd_breakpoint_z80, |
4570 .min_args = 1, | 4600 .min_args = 1, |
4571 .max_args = 1 | 4601 .max_args = 1 |
4602 }, | |
4603 { | |
4604 .names = (const char *[]){ | |
4605 "watchpoint", NULL | |
4606 }, | |
4607 .usage = "watchpoint ADDRESS [SIZE]", | |
4608 .desc = "Set a watchpoint at ADDRESS with an optional SIZE in bytes. SIZE defaults to 1", | |
4609 .impl = cmd_watchpoint_z80, | |
4610 .min_args = 1, | |
4611 .max_args = 2 | |
4572 }, | 4612 }, |
4573 { | 4613 { |
4574 .names = (const char *[]){ | 4614 .names = (const char *[]){ |
4575 "advance", NULL | 4615 "advance", NULL |
4576 }, | 4616 }, |
5181 if (!root) { | 5221 if (!root) { |
5182 return context; | 5222 return context; |
5183 } | 5223 } |
5184 root->address = address; | 5224 root->address = address; |
5185 //Check if this is a user set breakpoint, or just a temporary one | 5225 //Check if this is a user set breakpoint, or just a temporary one |
5226 int debugging; | |
5186 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address, BP_TYPE_CPU); | 5227 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address, BP_TYPE_CPU); |
5187 if (*this_bp) { | 5228 if (*this_bp) { |
5188 if ((*this_bp)->condition) { | 5229 if ((*this_bp)->condition) { |
5189 debug_val condres; | 5230 debug_val condres; |
5190 if (eval_expr(root, (*this_bp)->condition, &condres)) { | 5231 if (eval_expr(root, (*this_bp)->condition, &condres)) { |
5195 fprintf(stderr, "Failed to eval condition for Z80 breakpoint %u\n", (*this_bp)->index); | 5236 fprintf(stderr, "Failed to eval condition for Z80 breakpoint %u\n", (*this_bp)->index); |
5196 free_expr((*this_bp)->condition); | 5237 free_expr((*this_bp)->condition); |
5197 (*this_bp)->condition = NULL; | 5238 (*this_bp)->condition = NULL; |
5198 } | 5239 } |
5199 } | 5240 } |
5200 int debugging = 1; | 5241 debugging = 1; |
5201 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) | 5242 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) |
5202 { | 5243 { |
5203 debugging = run_command(root, (*this_bp)->commands + i); | 5244 debugging = run_command(root, (*this_bp)->commands + i); |
5204 } | 5245 } |
5205 if (debugging) { | 5246 if (debugging) { |
5206 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index); | 5247 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index); |
5207 } else { | 5248 } else { |
5249 fflush(stdout); | |
5208 return context; | 5250 return context; |
5209 } | 5251 } |
5210 } else { | 5252 } else { |
5211 zremove_breakpoint(context, address); | 5253 zremove_breakpoint(context, address); |
5254 } | |
5255 if (context->wp_hit) { | |
5256 context->wp_hit = 0; | |
5257 this_bp = find_breakpoint(&root->breakpoints, context->wp_hit_address, BP_TYPE_CPU_WATCH); | |
5258 if (*this_bp) { | |
5259 if ((*this_bp)->condition) { | |
5260 debug_val condres; | |
5261 if (eval_expr(root, (*this_bp)->condition, &condres)) { | |
5262 if (!condres.v.u32) { | |
5263 return context; | |
5264 } | |
5265 } else { | |
5266 fprintf(stderr, "Failed to eval condition for Z80 watchpoint %u\n", (*this_bp)->index); | |
5267 free_expr((*this_bp)->condition); | |
5268 (*this_bp)->condition = NULL; | |
5269 } | |
5270 } | |
5271 debugging = 1; | |
5272 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) | |
5273 { | |
5274 debugging = run_command(root, (*this_bp)->commands + i); | |
5275 } | |
5276 if (debugging) { | |
5277 if (context->wp_old_value != context->wp_hit_value) { | |
5278 printf("Z80 Watchpoint %d hit, old value: %X, new value %X\n", (*this_bp)->index, context->wp_old_value, context->wp_hit_value); | |
5279 } else { | |
5280 printf("Z80 Watchpoint %d hit\n", (*this_bp)->index); | |
5281 } | |
5282 } else { | |
5283 fflush(stdout); | |
5284 return context; | |
5285 } | |
5286 } | |
5212 } | 5287 } |
5213 uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | 5288 uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen); |
5214 if (!pc) { | 5289 if (!pc) { |
5215 fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address); | 5290 fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address); |
5216 } | 5291 } |
5304 if (eval_expr(root, (*this_bp)->condition, &condres)) { | 5379 if (eval_expr(root, (*this_bp)->condition, &condres)) { |
5305 if (!condres.v.u32) { | 5380 if (!condres.v.u32) { |
5306 return; | 5381 return; |
5307 } | 5382 } |
5308 } else { | 5383 } else { |
5309 fprintf(stderr, "Failed to eval condition for M68K breakpoint %u\n", (*this_bp)->index); | 5384 fprintf(stderr, "Failed to eval condition for M68K watchpoint %u\n", (*this_bp)->index); |
5310 free_expr((*this_bp)->condition); | 5385 free_expr((*this_bp)->condition); |
5311 (*this_bp)->condition = NULL; | 5386 (*this_bp)->condition = NULL; |
5312 } | 5387 } |
5313 } | 5388 } |
5314 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) | 5389 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) |