/[gxemul]/trunk/src/debugger/debugger.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/debugger/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 28 by dpavlin, Mon Oct 8 16:20:26 2007 UTC revision 44 by dpavlin, Mon Oct 8 16:22:56 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2004-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2004-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: debugger.c,v 1.14 2006/07/01 21:15:46 debug Exp $   *  $Id: debugger.c,v 1.27 2007/06/28 14:58:38 debug Exp $
29   *   *
30   *  Single-step debugger.   *  Single-step debugger.
31   *   *
32   *   *
33   *  TODO:   *  This entire module is very much non-reentrant. :-/  TODO: Fix.
  *  
  *      This entire module is very much non-reentrant. :-/  
  *  
  *      Add more functionality that already exists elsewhere in the emulator.  
  *  
  *      Call stack display (back-trace)?  
  *  
  *      More generic expression evaluator (for example + - * / between multiple  
  *      terms), including _TAB COMPLETION_ of symbols and register names!  
  *      Must be possible to reach any emul, any machine in any emul, any  
  *      cpu in any machine, other variables in the emulator, and so forth.  
  *      Perhaps a "settable variables registry" somewhere?  
  *  
  *      Nicer looking output of register dumps, floating point registers,  
  *      etc. Warn about weird/invalid register contents.  
  *  
  *      Ctrl-C doesn't enter the debugger on some OSes (HP-UX?)...  
  *  
  *      Many other TODOs.  
34   */   */
35    
36  #include <ctype.h>  #include <ctype.h>
# Line 63  Line 44 
44  #include "cpu.h"  #include "cpu.h"
45  #include "device.h"  #include "device.h"
46  #include "debugger.h"  #include "debugger.h"
 #include "debugger_gdb.h"  
47  #include "diskimage.h"  #include "diskimage.h"
48  #include "emul.h"  #include "emul.h"
49  #include "machine.h"  #include "machine.h"
# Line 71  Line 51 
51  #include "misc.h"  #include "misc.h"
52  #include "net.h"  #include "net.h"
53  #include "settings.h"  #include "settings.h"
54    #include "timer.h"
55  #include "x11.h"  #include "x11.h"
56    
57    
# Line 104  int old_show_trace_tree = 0; Line 85  int old_show_trace_tree = 0;
85    
86  static volatile int ctrl_c;  static volatile int ctrl_c;
87    
 static int debugger_n_emuls;  
 static struct emul **debugger_emuls;  
88  static struct emul *debugger_emul;  static struct emul *debugger_emul;
89    
90    /*  Currently focused CPU, machine, and emulation:  */
91    int debugger_cur_cpu;
92    int debugger_cur_machine;
93  static struct machine *debugger_machine;  static struct machine *debugger_machine;
94    static struct emul *debugger_emul;
95    
96  #define MAX_CMD_BUFLEN          72  #define MAX_CMD_BUFLEN          72
97  #define N_PREVIOUS_CMDS         150  #define N_PREVIOUS_CMDS         150
# Line 127  static uint64_t last_unasm_addr = MAGIC_ Line 111  static uint64_t last_unasm_addr = MAGIC_
111   */   */
112  char debugger_readchar(void)  char debugger_readchar(void)
113  {  {
114          int ch, i, j;          int ch;
115    
116          while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) {          while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) {
117                  /*  Check for X11 events:  */                  /*  Check for X11 events:  */
118                  x11_check_event(debugger_emuls, debugger_n_emuls);                  x11_check_event(debugger_emul);
   
                 /*  Check for incoming GDB packets:  */  
                 for (i=0; i<debugger_n_emuls; i++) {  
                         struct emul *e = debugger_emuls[i];  
                         if (e == NULL)  
                                 continue;  
   
                         for (j=0; j<e->n_machines; j++) {  
                                 if (e->machines[j]->gdb.port > 0)  
                                         debugger_gdb_check_incoming(  
                                             e->machines[j]);  
                         }  
                 }  
   
                 /*  TODO: The X11 and GDB checks above should probably  
                         be factored out...  */  
119    
120                  /*  Give up some CPU time:  */                  /*  Give up some CPU time:  */
121                  usleep(1);                  usleep(10000);
122          }          }
123          return ch;          return ch;
124  }  }
# Line 194  void debugger_activate(int x) Line 162  void debugger_activate(int x)
162    
163    
164  /*  /*
  *  debugger_parse_name():  
  *  
  *  This function reads a string, and tries to match it to a register name,  
  *  a symbol, or treat it as a decimal numeric value.  
  *  
  *  Some examples:  
  *  
  *      "0x7fff1234"            ==> numeric value (hex, in this case)  
  *      "pc", "r5", "hi", "t4"  ==> register (CPU dependent)  
  *      "memcpy+64"             ==> symbol (plus offset)  
  *  
  *  Register names can be preceeded by "x:" where x is the CPU number. (CPU  
  *  0 is assumed by default.)  
  *  
  *  To force detection of different types, a character can be added in front of  
  *  the name: "$" for numeric values, "%" for registers, and "@" for symbols.  
  *  
  *  Return value is:  
  *  
  *      NAME_PARSE_NOMATCH      no match  
  *      NAME_PARSE_MULTIPLE     multiple matches  
  *  
  *  or one of these (and then *valuep is read or written, depending on  
  *  the writeflag):  
  *  
  *      NAME_PARSE_REGISTER     a register  
  *      NAME_PARSE_NUMBER       a hex number  
  *      NAME_PARSE_SYMBOL       a symbol  
  */  
 #define NAME_PARSE_NOMATCH      0  
 #define NAME_PARSE_MULTIPLE     1  
 #define NAME_PARSE_REGISTER     2  
 #define NAME_PARSE_NUMBER       3  
 #define NAME_PARSE_SYMBOL       4  
 static int debugger_parse_name(struct machine *m, char *name, int writeflag,  
         uint64_t *valuep)  
 {  
         int match_register = 0, match_symbol = 0, match_numeric = 0;  
         int skip_register, skip_numeric, skip_symbol;  
   
         if (m == NULL || name == NULL) {  
                 fprintf(stderr, "debugger_parse_name(): NULL ptr\n");  
                 exit(1);  
         }  
   
         /*  Warn about non-signextended values:  */  
         if (writeflag) {  
                 if (m->cpus[0]->is_32bit) {  
                         /*  Automagically sign-extend.  TODO: Is this good?  */  
                         if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)  
                                 (*valuep) |= 0xffffffff00000000ULL;  
                 } else {  
                         if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)  
                                 printf("WARNING: The value is not sign-extende"  
                                     "d. Is this what you intended?\n");  
                 }  
         }  
   
         skip_register = name[0] == '$' || name[0] == '@';  
         skip_numeric  = name[0] == '%' || name[0] == '@';  
         skip_symbol   = name[0] == '$' || name[0] == '%';  
   
         /*  Check for a register match:  */  
         if (!skip_register && strlen(name) >= 1)  
                 cpu_register_match(m, name, writeflag, valuep,  
                     &match_register);  
   
         /*  Check for a number match:  */  
         if (!skip_numeric && isdigit((int)name[0])) {  
                 uint64_t x;  
                 x = strtoull(name, NULL, 0);  
                 if (writeflag) {  
                         printf("You cannot assign like that.\n");  
                 } else  
                         *valuep = x;  
                 match_numeric = 1;  
         }  
   
         /*  Check for a symbol match:  */  
         if (!skip_symbol) {  
                 int res;  
                 char *p, *sn;  
                 uint64_t newaddr, ofs = 0;  
   
                 sn = malloc(strlen(name) + 1);  
                 if (sn == NULL) {  
                         fprintf(stderr, "out of memory in debugger\n");  
                         exit(1);  
                 }  
                 strlcpy(sn, name, strlen(name)+1);  
   
                 /*  Is there a '+' in there? Then treat that as an offset:  */  
                 p = strchr(sn, '+');  
                 if (p != NULL) {  
                         *p = '\0';  
                         ofs = strtoull(p+1, NULL, 0);  
                 }  
   
                 res = get_symbol_addr(&m->symbol_context, sn, &newaddr);  
                 if (res) {  
                         if (writeflag) {  
                                 printf("You cannot assign like that.\n");  
                         } else  
                                 *valuep = newaddr + ofs;  
                         match_symbol = 1;  
                 }  
   
                 free(sn);  
         }  
   
         if (match_register + match_symbol + match_numeric > 1)  
                 return NAME_PARSE_MULTIPLE;  
   
         if (match_register)  
                 return NAME_PARSE_REGISTER;  
         if (match_numeric)  
                 return NAME_PARSE_NUMBER;  
         if (match_symbol)  
                 return NAME_PARSE_SYMBOL;  
   
         return NAME_PARSE_NOMATCH;  
 }  
   
   
 /*  
165   *  show_breakpoint():   *  show_breakpoint():
166   */   */
167  static void show_breakpoint(struct machine *m, int i)  static void show_breakpoint(struct machine *m, int i)
168  {  {
169          printf("%3i: 0x", i);          printf("%3i: 0x", i);
170          if (m->cpus[0]->is_32bit)          if (m->cpus[0]->is_32bit)
171                  printf("%08"PRIx32, (uint32_t) m->breakpoint_addr[i]);                  printf("%08"PRIx32, (uint32_t) m->breakpoints.addr[i]);
172          else          else
173                  printf("%016"PRIx64, (uint64_t) m->breakpoint_addr[i]);                  printf("%016"PRIx64, (uint64_t) m->breakpoints.addr[i]);
174          if (m->breakpoint_string[i] != NULL)          if (m->breakpoints.string[i] != NULL)
175                  printf(" (%s)", m->breakpoint_string[i]);                  printf(" (%s)", m->breakpoints.string[i]);
         if (m->breakpoint_flags[i])  
                 printf(": flags=0x%x", m->breakpoint_flags[i]);  
176          printf("\n");          printf("\n");
177  }  }
178    
# Line 357  void debugger_assignment(struct machine Line 198  void debugger_assignment(struct machine
198          uint64_t tmp;          uint64_t tmp;
199          uint64_t old_pc = m->cpus[0]->pc;       /*  TODO: multiple cpus?  */          uint64_t old_pc = m->cpus[0]->pc;       /*  TODO: multiple cpus?  */
200    
201          left  = malloc(MAX_CMD_BUFLEN);          CHECK_ALLOCATION(left = malloc(MAX_CMD_BUFLEN));
         if (left == NULL) {  
                 fprintf(stderr, "out of memory in debugger_assignment()\n");  
                 exit(1);  
         }  
202          strlcpy(left, cmd, MAX_CMD_BUFLEN);          strlcpy(left, cmd, MAX_CMD_BUFLEN);
203          right = strchr(left, '=');          right = strchr(left, '=');
204          if (right == NULL) {          if (right == NULL) {
# Line 381  void debugger_assignment(struct machine Line 218  void debugger_assignment(struct machine
218    
219          /*  printf("left  = '%s'\nright = '%s'\n", left, right);  */          /*  printf("left  = '%s'\nright = '%s'\n", left, right);  */
220    
221          res_right = debugger_parse_name(m, right, 0, &tmp);          res_right = debugger_parse_expression(m, right, 0, &tmp);
222          switch (res_right) {          switch (res_right) {
223          case NAME_PARSE_NOMATCH:          case PARSE_NOMATCH:
224                  printf("No match for the right-hand side of the assignment.\n");                  printf("No match for the right-hand side of the assignment.\n");
225                  break;                  break;
226          case NAME_PARSE_MULTIPLE:          case PARSE_MULTIPLE:
227                  printf("Multiple matches for the right-hand side of the "                  printf("Multiple matches for the right-hand side of the "
228                      "assignment.\n");                      "assignment.\n");
229                  break;                  break;
230          default:          default:
231                  res_left = debugger_parse_name(m, left, 1, &tmp);                  res_left = debugger_parse_expression(m, left, 1, &tmp);
232                  switch (res_left) {                  switch (res_left) {
233                  case NAME_PARSE_NOMATCH:                  case PARSE_NOMATCH:
234                          printf("No match for the left-hand side of the "                          printf("No match for the left-hand side of the "
235                              "assignment.\n");                              "assignment.\n");
236                          break;                          break;
237                  case NAME_PARSE_MULTIPLE:                  case PARSE_MULTIPLE:
238                          printf("Multiple matches for the left-hand side "                          printf("Multiple matches for the left-hand side "
239                              "of the assignment.\n");                              "of the assignment.\n");
240                          break;                          break;
# Line 710  static char *debugger_readline(void) Line 547  static char *debugger_readline(void)
547                  } else if (ch == 27) {                  } else if (ch == 27) {
548                          /*  Escape codes: (cursor keys etc)  */                          /*  Escape codes: (cursor keys etc)  */
549                          while ((ch = console_readchar(MAIN_CONSOLE)) < 0)                          while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
550                                  usleep(1);                                  usleep(10000);
551                          if (ch == '[' || ch == 'O') {                          if (ch == '[' || ch == 'O') {
552                                  while ((ch = console_readchar(MAIN_CONSOLE))                                  while ((ch = console_readchar(MAIN_CONSOLE))
553                                      < 0)                                      < 0)
554                                          usleep(1);                                          usleep(10000);
555                                  switch (ch) {                                  switch (ch) {
556                                  case '2':       /*  2~ = ins  */                                  case '2':       /*  2~ = ins  */
557                                  case '5':       /*  5~ = pgup  */                                  case '5':       /*  5~ = pgup  */
# Line 722  static char *debugger_readline(void) Line 559  static char *debugger_readline(void)
559                                          /*  TODO: Ugly hack, but might work.  */                                          /*  TODO: Ugly hack, but might work.  */
560                                          while ((ch = console_readchar(                                          while ((ch = console_readchar(
561                                              MAIN_CONSOLE)) < 0)                                              MAIN_CONSOLE)) < 0)
562                                                  usleep(1);                                                  usleep(10000);
563                                          /*  Do nothing for these keys.  */                                          /*  Do nothing for these keys.  */
564                                          break;                                          break;
565                                  case '3':       /*  3~ = delete  */                                  case '3':       /*  3~ = delete  */
566                                          /*  TODO: Ugly hack, but might work.  */                                          /*  TODO: Ugly hack, but might work.  */
567                                          while ((ch = console_readchar(                                          while ((ch = console_readchar(
568                                              MAIN_CONSOLE)) < 0)                                              MAIN_CONSOLE)) < 0)
569                                                  usleep(1);                                                  usleep(10000);
570                                          console_makeavail(MAIN_CONSOLE, '\b');                                          console_makeavail(MAIN_CONSOLE, '\b');
571                                          break;                                          break;
572                                  case 'A':       /*  Up.  */                                  case 'A':       /*  Up.  */
# Line 798  void debugger(void) Line 635  void debugger(void)
635                              debugger_machine->cpus[i], 0, INVALIDATE_ALL);                              debugger_machine->cpus[i], 0, INVALIDATE_ALL);
636                  }                  }
637    
638          /*          /*  Stop timers while interacting with the user:  */
639           *  Ugly GDB hack: After single stepping, we need to send back          timer_stop();
          *  status to GDB:  
          */  
         if (exit_debugger == -1) {  
                 int i, j;  
                 for (i=0; i<debugger_n_emuls; i++) {  
                         struct emul *e = debugger_emuls[i];  
                         if (e == NULL)  
                                 continue;  
   
                         for (j=0; j<e->n_machines; j++) {  
                                 if (e->machines[j]->gdb.port > 0)  
                                         debugger_gdb_after_singlestep(  
                                             e->machines[j]);  
                         }  
                 }  
         }  
   
640    
641          exit_debugger = 0;          exit_debugger = 0;
642    
# Line 824  void debugger(void) Line 644  void debugger(void)
644                  /*  Read a line from the terminal:  */                  /*  Read a line from the terminal:  */
645                  cmd = debugger_readline();                  cmd = debugger_readline();
646    
                 /*  Special hack for the "step" _GDB_ command:  */  
                 if (exit_debugger == -1)  
                         return;  
   
647                  cmd_len = strlen(cmd);                  cmd_len = strlen(cmd);
648    
649                  /*  Remove spaces:  */                  /*  Remove spaces:  */
# Line 858  void debugger(void) Line 674  void debugger(void)
674                          return;                          return;
675          }          }
676    
677          gettimeofday(&debugger_machine->starttime, NULL);          /*  Start up timers again:  */
678          debugger_machine->ninstrs_since_gettimeofday = 0;          timer_start();
679    
680            /*  ... and reset starttime, so that nr of instructions per second
681                can be calculated correctly:  */
682            for (i=0; i<debugger_machine->ncpus; i++) {
683                    gettimeofday(&debugger_machine->cpus[i]->starttime, NULL);
684                    debugger_machine->cpus[i]->ninstrs_since_gettimeofday = 0;
685            }
686    
687          single_step = NOT_SINGLE_STEPPING;          single_step = NOT_SINGLE_STEPPING;
688          debugger_machine->instruction_trace = old_instruction_trace;          debugger_machine->instruction_trace = old_instruction_trace;
# Line 887  void debugger_reset(void) Line 710  void debugger_reset(void)
710   *   *
711   *  Must be called before any other debugger function is used.   *  Must be called before any other debugger function is used.
712   */   */
713  void debugger_init(struct emul **emuls, int n_emuls)  void debugger_init(struct emul *emul)
714  {  {
715          int i, j;          int i;
716    
717          debugger_n_emuls = n_emuls;          debugger_emul = emul;
         debugger_emuls = emuls;  
718    
719          if (n_emuls < 1) {          if (emul->n_machines < 1) {
720                  fprintf(stderr, "\nERROR: No emuls (?)\n");                  fprintf(stderr, "\nERROR: No machines, "
                 exit(1);  
         }  
   
         debugger_emul = emuls[0];  
         if (emuls[0]->n_machines < 1) {  
                 fprintf(stderr, "\nERROR: No machines in emuls[0], "  
721                      "cannot handle this situation yet.\n\n");                      "cannot handle this situation yet.\n\n");
722                  exit(1);                  exit(1);
723          }          }
724    
725          for (i=0; i<n_emuls; i++)          debugger_machine = emul->machines[0];
                 for (j=0; j<emuls[i]->n_machines; j++)  
                         debugger_gdb_init(emuls[i]->machines[j]);  
726    
727          debugger_machine = emuls[0]->machines[0];          debugger_cur_cpu = 0;
728            debugger_cur_machine = 0;
729    
730          for (i=0; i<N_PREVIOUS_CMDS; i++) {          for (i=0; i<N_PREVIOUS_CMDS; i++) {
731                  last_cmd[i] = malloc(MAX_CMD_BUFLEN);                  CHECK_ALLOCATION(last_cmd[i] = malloc(MAX_CMD_BUFLEN));
                 if (last_cmd[i] == NULL) {  
                         fprintf(stderr, "debugger_init(): out of memory\n");  
                         exit(1);  
                 }  
732                  last_cmd[i][0] = '\0';                  last_cmd[i][0] = '\0';
733          }          }
734    

Legend:
Removed from v.28  
changed lines
  Added in v.44

  ViewVC Help
Powered by ViewVC 1.1.26