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++)