Mercurial > repos > blastem
comparison debug.c @ 2393:5f4917b9ecfa
Add debugger save command
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 05 Dec 2023 21:29:21 -0800 |
parents | 9f178feb3cb0 |
children | 340299a76db7 |
comparison
equal
deleted
inserted
replaced
2392:a71176b9903d | 2393:5f4917b9ecfa |
---|---|
3000 tern_foreach(root->symbols, print_symbol, &max_len); | 3000 tern_foreach(root->symbols, print_symbol, &max_len); |
3001 } | 3001 } |
3002 return 1; | 3002 return 1; |
3003 } | 3003 } |
3004 | 3004 |
3005 static uint8_t cmd_save(debug_root *root, parsed_command *cmd) | |
3006 { | |
3007 char size = cmd->format ? cmd->format[0] : 'b'; | |
3008 if (size != 'b' && size != 'w' && size != 'l') { | |
3009 fprintf(stderr, "Invalid size %s\n", cmd->format); | |
3010 return 1; | |
3011 } | |
3012 FILE *f = fopen(cmd->args[0].raw, "wb"); | |
3013 if (!f) { | |
3014 fprintf(stderr, "Failed to open %s for writing\n", cmd->args[0].raw); | |
3015 return 1; | |
3016 } | |
3017 uint32_t start = 0; | |
3018 debug_val val; | |
3019 debug_array * arr = NULL; | |
3020 if (cmd->args[1].parsed->type == EXPR_MEM) { | |
3021 | |
3022 if (!eval_expr(root, cmd->args[1].parsed->left, &val)) { | |
3023 fprintf(stderr, "Failed to eval start index\n"); | |
3024 goto cleanup; | |
3025 } | |
3026 if (!debug_cast_int(val, &start)) { | |
3027 fprintf(stderr, "Start index must evaluate to integer\n"); | |
3028 goto cleanup; | |
3029 } | |
3030 if (cmd->args[1].parsed->right) { | |
3031 if (!eval_expr(root, cmd->args[1].parsed->right, &val)) { | |
3032 fprintf(stderr, "Failed to eval array name in argument %s\n", cmd->args[1].raw); | |
3033 goto cleanup; | |
3034 } | |
3035 arr = get_array(val); | |
3036 if (!arr) { | |
3037 fprintf(stderr, "Name in argument %s did not evaluate to an array\n", cmd->args[1].raw); | |
3038 goto cleanup; | |
3039 } | |
3040 } | |
3041 } else { | |
3042 if (!eval_expr(root, cmd->args[1].parsed, &val)) { | |
3043 fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); | |
3044 goto cleanup; | |
3045 } | |
3046 arr = get_array(val); | |
3047 if (!arr) { | |
3048 fprintf(stderr, "Argument %s did not evaluate to an array\n", cmd->args[1].raw); | |
3049 goto cleanup; | |
3050 } | |
3051 } | |
3052 uint32_t count = 0; | |
3053 if (cmd->num_args > 2) { | |
3054 if (!eval_expr(root, cmd->args[2].parsed, &val)) { | |
3055 fprintf(stderr, "Failed to eval %s\n", cmd->args[2].raw); | |
3056 goto cleanup; | |
3057 } | |
3058 if (!debug_cast_int(val, &count)) { | |
3059 fprintf(stderr, "Count must evaluate to integer\n"); | |
3060 goto cleanup; | |
3061 } | |
3062 } else if (arr) { | |
3063 count = arr->size < start ? 0 : arr->size - start; | |
3064 } else { | |
3065 count = root->chunk_end(root, start) - start; | |
3066 if (size == 'l') { | |
3067 count /= 4; | |
3068 } else if (size == 'w') { | |
3069 count /= 2; | |
3070 } | |
3071 } | |
3072 union { | |
3073 uint8_t b[1024]; | |
3074 uint16_t w[512]; | |
3075 uint32_t l[256]; | |
3076 } buffer; | |
3077 uint32_t cur = start; | |
3078 if (size == 'l') { | |
3079 while (count) | |
3080 { | |
3081 uint32_t n = count < 256 ? count : 256; | |
3082 count -= n; | |
3083 for (uint32_t i = 0; i < n ; i++) | |
3084 { | |
3085 if (arr) { | |
3086 val = arr->get(arr, cur++); | |
3087 if (!debug_cast_int(val, buffer.l + i)) { | |
3088 n = i; | |
3089 count = 0; | |
3090 } | |
3091 } else { | |
3092 buffer.l[i] = cur; | |
3093 cur += 4; | |
3094 if (!root->read_mem(root, buffer.l + i, 'l')) { | |
3095 n = i; | |
3096 count = 0; | |
3097 } | |
3098 } | |
3099 } | |
3100 fwrite(buffer.l, sizeof(uint32_t), n, f); | |
3101 } | |
3102 } else if (size == 'w') { | |
3103 while (count) | |
3104 { | |
3105 uint32_t n = count < 512 ? count : 512; | |
3106 count -= n; | |
3107 uint32_t tmp; | |
3108 for (uint32_t i = 0; i < n ; i++) | |
3109 { | |
3110 if (arr) { | |
3111 val = arr->get(arr, cur++); | |
3112 if (!debug_cast_int(val, &tmp)) { | |
3113 n = i; | |
3114 count = 0; | |
3115 } | |
3116 } else { | |
3117 tmp = cur; | |
3118 cur += 2; | |
3119 if (!root->read_mem(root, &tmp, 'w')) { | |
3120 n = i; | |
3121 count = 0; | |
3122 } | |
3123 } | |
3124 buffer.w[i] = tmp; | |
3125 } | |
3126 fwrite(buffer.w, sizeof(uint16_t), n, f); | |
3127 } | |
3128 } else { | |
3129 while (count) | |
3130 { | |
3131 uint32_t n = count < 1024 ? count : 1024; | |
3132 count -= n; | |
3133 uint32_t tmp; | |
3134 for (uint32_t i = 0; i < n ; i++) | |
3135 { | |
3136 if (arr) { | |
3137 val = arr->get(arr, cur++); | |
3138 if (!debug_cast_int(val, &tmp)) { | |
3139 n = i; | |
3140 count = 0; | |
3141 } | |
3142 } else { | |
3143 tmp = cur++; | |
3144 if (!root->read_mem(root, &tmp, 'b')) { | |
3145 n = i; | |
3146 count = 0; | |
3147 } | |
3148 } | |
3149 buffer.b[i] = tmp; | |
3150 } | |
3151 fwrite(buffer.b, sizeof(uint8_t), n, f); | |
3152 } | |
3153 } | |
3154 cleanup: | |
3155 fclose(f); | |
3156 return 1; | |
3157 } | |
3158 | |
3005 static uint8_t cmd_delete_m68k(debug_root *root, parsed_command *cmd) | 3159 static uint8_t cmd_delete_m68k(debug_root *root, parsed_command *cmd) |
3006 { | 3160 { |
3007 uint32_t index; | 3161 uint32_t index; |
3008 if (!debug_cast_int(cmd->args[0].value, &index)) { | 3162 if (!debug_cast_int(cmd->args[0].value, &index)) { |
3009 fprintf(stderr, "Argument to delete must be an integer\n"); | 3163 fprintf(stderr, "Argument to delete must be an integer\n"); |
3642 .desc = "Loads a list of symbols from the file indicated by FILENAME or lists currently loaded symbols if FILENAME is omitted", | 3796 .desc = "Loads a list of symbols from the file indicated by FILENAME or lists currently loaded symbols if FILENAME is omitted", |
3643 .impl = cmd_symbols, | 3797 .impl = cmd_symbols, |
3644 .min_args = 0, | 3798 .min_args = 0, |
3645 .max_args = 1, | 3799 .max_args = 1, |
3646 .raw_args = 1 | 3800 .raw_args = 1 |
3801 }, | |
3802 { | |
3803 .names = (const char *[]){ | |
3804 "save", NULL | |
3805 }, | |
3806 .usage = "save[/SIZE] FILENAME ARRAY [COUNT]", | |
3807 .desc = "Saves COUNT elements of size SIZE from the array or memory region specified by ARRAY to a file", | |
3808 .impl = cmd_save, | |
3809 .min_args = 2, | |
3810 .max_args = 3, | |
3811 .skip_eval = 1 | |
3647 } | 3812 } |
3648 }; | 3813 }; |
3649 #define NUM_COMMON (sizeof(common_commands)/sizeof(*common_commands)) | 3814 #define NUM_COMMON (sizeof(common_commands)/sizeof(*common_commands)) |
3650 | 3815 |
3651 command_def m68k_commands[] = { | 3816 command_def m68k_commands[] = { |
4221 { | 4386 { |
4222 vdp_context *vdp = var->ptr; | 4387 vdp_context *vdp = var->ptr; |
4223 return debug_int(vdp->frame); | 4388 return debug_int(vdp->frame); |
4224 } | 4389 } |
4225 | 4390 |
4391 static uint32_t m68k_chunk_end(debug_root *root, uint32_t start_address) | |
4392 { | |
4393 m68k_context *m68k = root->cpu_context; | |
4394 memmap_chunk const *chunk = find_map_chunk(start_address, &m68k->options->gen, 0, NULL); | |
4395 if (!chunk) { | |
4396 return start_address; | |
4397 } | |
4398 if (chunk->mask == m68k->options->gen.address_mask) { | |
4399 return chunk->end; | |
4400 } | |
4401 return (start_address & ~chunk->mask) + chunk->mask + 1; | |
4402 } | |
4403 | |
4226 debug_root *find_m68k_root(m68k_context *context) | 4404 debug_root *find_m68k_root(m68k_context *context) |
4227 { | 4405 { |
4228 debug_root *root = find_root(context); | 4406 debug_root *root = find_root(context); |
4229 if (root && !root->commands) { | 4407 if (root && !root->commands) { |
4230 add_commands(root, common_commands, NUM_COMMON); | 4408 add_commands(root, common_commands, NUM_COMMON); |
4231 add_commands(root, m68k_commands, NUM_68K); | 4409 add_commands(root, m68k_commands, NUM_68K); |
4232 root->read_mem = read_m68k; | 4410 root->read_mem = read_m68k; |
4233 root->write_mem = write_m68k; | 4411 root->write_mem = write_m68k; |
4412 root->chunk_end = m68k_chunk_end; | |
4234 root->disasm = create_68000_disasm(); | 4413 root->disasm = create_68000_disasm(); |
4235 m68k_names(root); | 4414 m68k_names(root); |
4236 debug_var *var; | 4415 debug_var *var; |
4237 switch (current_system->type) | 4416 switch (current_system->type) |
4238 { | 4417 { |
4609 var->get = z80_pc_get; | 4788 var->get = z80_pc_get; |
4610 root->variables = tern_insert_ptr(root->variables, "pc", var); | 4789 root->variables = tern_insert_ptr(root->variables, "pc", var); |
4611 root->variables = tern_insert_ptr(root->variables, "PC", var); | 4790 root->variables = tern_insert_ptr(root->variables, "PC", var); |
4612 } | 4791 } |
4613 | 4792 |
4793 static uint32_t z80_chunk_end(debug_root *root, uint32_t start_address) | |
4794 { | |
4795 z80_context *z80 = root->cpu_context; | |
4796 memmap_chunk const *chunk = find_map_chunk(start_address, &z80->options->gen, 0, NULL); | |
4797 if (!chunk) { | |
4798 return start_address; | |
4799 } | |
4800 if (chunk->mask == z80->options->gen.address_mask) { | |
4801 return chunk->end; | |
4802 } | |
4803 return (start_address & ~chunk->mask) + chunk->mask + 1; | |
4804 } | |
4805 | |
4614 debug_root *find_z80_root(z80_context *context) | 4806 debug_root *find_z80_root(z80_context *context) |
4615 { | 4807 { |
4616 debug_root *root = find_root(context); | 4808 debug_root *root = find_root(context); |
4617 if (root && !root->commands) { | 4809 if (root && !root->commands) { |
4618 add_commands(root, common_commands, NUM_COMMON); | 4810 add_commands(root, common_commands, NUM_COMMON); |
4645 //root->resolve = resolve_z80; | 4837 //root->resolve = resolve_z80; |
4646 } | 4838 } |
4647 root->read_mem = read_z80; | 4839 root->read_mem = read_z80; |
4648 root->write_mem = write_z80; | 4840 root->write_mem = write_z80; |
4649 root->disasm = create_z80_disasm(); | 4841 root->disasm = create_z80_disasm(); |
4842 root->chunk_end = z80_chunk_end; | |
4650 } | 4843 } |
4651 return root; | 4844 return root; |
4652 } | 4845 } |
4653 | 4846 |
4654 z80_context * zdebugger(z80_context * context, uint16_t address) | 4847 z80_context * zdebugger(z80_context * context, uint16_t address) |