Пример #1
0
/* handle_gdb_valgrind_command handles the provided mon string command.
   If command is recognised, return 1 else return 0.
   Note that in case of ambiguous command, 1 is returned.

   *sink_wanted_at_return is modified if one of the commands 
   'v.set *_output' is handled.
*/
static
int handle_gdb_valgrind_command (char* mon, OutputSink* sink_wanted_at_return)
{
   UWord ret = 0;
   char s[strlen(mon)+1]; /* copy for strtok_r */
   char* wcmd;
   Char* ssaveptr;
   char* endptr;
   int   kwdid;
   int int_value;

   vg_assert (initial_valgrind_sink_saved);

   strcpy (s, mon);
   wcmd = strtok_r (s, " ", &ssaveptr);
   /* NB: if possible, avoid introducing a new command below which
      starts with the same 3 first letters as an already existing
      command. This ensures a shorter abbreviation for the user. */
   switch (VG_(keyword_id) ("help v.set v.info v.wait v.kill v.translate",
                            wcmd, kwd_report_duplicated_matches)) {
   case -2:
      ret = 1;
      break;
   case -1: 
      break;
   case  0: /* help */
      ret = 1;
      wcmd = strtok_r (NULL, " ", &ssaveptr);
      if (wcmd == NULL) {
         int_value = 0;
      } else {
         switch (VG_(keyword_id) ("debug", wcmd, kwd_report_all)) {
         case -2: int_value = 0; break;
         case -1: int_value = 0; break;
         case  0: int_value = 1; break;
         default: tl_assert (0);
         }
      }

      VG_(gdb_printf) (
"general valgrind monitor commands:\n"
"  help [debug]             : monitor command help. With debug: + debugging commands\n"
"  v.wait [<ms>]           : sleep <ms> (default 0) then continue\n"
"  v.info all_errors       : show all errors found so far\n"
"  v.info last_error       : show last error found\n"
"  v.info n_errs_found     : show the nr of errors found so far\n"
"  v.kill                  : kill the Valgrind process\n"
"  v.set gdb_output        : set valgrind output to gdb\n"
"  v.set log_output        : set valgrind output to log\n"
"  v.set mixed_output      : set valgrind output to log, interactive output to gdb\n"
"  v.set vgdb-error <errornr> : debug me at error >= <errornr> \n");
      if (int_value) { VG_(gdb_printf) (
"debugging valgrind internals monitor commands:\n"
"  v.info gdbserver_status : show gdbserver status\n"
"  v.info memory [aspacemgr] : show valgrind heap memory stats\n"
"     (with aspacemgr arg, also shows valgrind segments on log ouput)\n"
"  v.info scheduler        : show valgrind thread state and stacktrace\n"
"  v.set debuglog <level>  : set valgrind debug log level to <level>\n"
"  v.translate <addr> [<traceflags>]  : debug translation of <addr> with <traceflags>\n"
"    (default traceflags 0b00100000 : show after instrumentation)\n"
"   An additional flag  0b100000000 allows to show gdbserver instrumentation\n");
      }
      break;
   case  1: /* v.set */
      ret = 1;
      wcmd = strtok_r (NULL, " ", &ssaveptr);
      switch (kwdid = VG_(keyword_id) 
              ("vgdb-error debuglog gdb_output log_output mixed_output",
               wcmd, kwd_report_all)) {
      case -2:
      case -1: 
         break;
      case 0: /* vgdb-error */
      case 1: /* debuglog */
         wcmd = strtok_r (NULL, " ", &ssaveptr);
         if (wcmd == NULL) {
            int_value = 0;
            endptr = "empty"; /* to report an error below */
         } else {
            int_value = strtol (wcmd, &endptr, 10);
         }
         if (*endptr != '\0') {
            VG_(gdb_printf) ("missing or malformed integer value\n");
         } else if (kwdid == 0) {
            VG_(gdb_printf) ("vgdb-error value changed from %d to %d\n",
                             VG_(dyn_vgdb_error), int_value);
            VG_(dyn_vgdb_error) = int_value;
         } else if (kwdid == 1) {
            VG_(gdb_printf) ("debuglog value changed from %d to %d\n",
                             VG_(debugLog_getLevel)(), int_value);
            VG_(debugLog_startup) (int_value, "gdbsrv");
         } else {
            vg_assert (0);
         }
         break;
      case 2: /* gdb_output */
         (*sink_wanted_at_return).fd = -2;
         command_output_to_log = False;
         VG_(gdb_printf) ("valgrind output will go to gdb\n");
         break;
      case 3: /* log_output */
         (*sink_wanted_at_return).fd = initial_valgrind_sink.fd;
         command_output_to_log = True;
         VG_(gdb_printf) ("valgrind output will go to log\n");
         break;
      case 4: /* mixed output */
         (*sink_wanted_at_return).fd = initial_valgrind_sink.fd;
         command_output_to_log = False;
         VG_(gdb_printf)
            ("valgrind output will go to log, interactive output will go to gdb\n");
         break;
      default:
         vg_assert (0);
      }
      break;
   case  2: /* v.info */ {
      ret = 1;
      wcmd = strtok_r (NULL, " ", &ssaveptr);
      switch (kwdid = VG_(keyword_id) 
              ("all_errors n_errs_found last_error gdbserver_status memory"
               " scheduler",
               wcmd, kwd_report_all)) {
      case -2:
      case -1: 
         break;
      case 0: // all_errors
         // A verbosity of minimum 2 is needed to show the errors.
         VG_(show_all_errors)(/* verbosity */ 2, /* xml */ False);
         break;
      case  1: // n_errs_found
         VG_(gdb_printf) ("n_errs_found %d n_errs_shown %d (vgdb-error %d)\n", 
                          VG_(get_n_errs_found) (),
                          VG_(get_n_errs_shown) (),
                          VG_(dyn_vgdb_error));
         break;
      case 2: // last_error
         VG_(show_last_error)();
         break;
      case  3: // gdbserver_status
         VG_(gdbserver_status_output)();
         break;
      case  4: /* memory */
         VG_(print_all_arena_stats) ();
         if (VG_(clo_profile_heap))
            VG_(print_arena_cc_analysis) ();
         wcmd = strtok_r (NULL, " ", &ssaveptr);
         if (wcmd != NULL) {
            switch (VG_(keyword_id) ("aspacemgr", wcmd, kwd_report_all)) {
            case -2:
            case -1: break;
            case  0: 
               VG_(am_show_nsegments) (0, "gdbserver v.info memory aspacemgr");
               break;
            default: tl_assert (0);
            }
         }

         ret = 1;
         break;
      case  5: /* scheduler */
         VG_(show_sched_status) ();
         ret = 1;
         break;
      default:
         vg_assert(0);
      }
      break;
   }
   case  3: /* v.wait */
      wcmd = strtok_r (NULL, " ", &ssaveptr);
      if (wcmd != NULL) {
         int_value = strtol (wcmd, &endptr, 10);
         VG_(gdb_printf) ("gdbserver: continuing in %d ms ...\n", int_value);
         VG_(poll)(NULL, 0, int_value);
      }
      VG_(gdb_printf) ("gdbserver: continuing after wait ...\n");
      ret = 1;
      break;
   case  4: /* v.kill */
      kill_request ("monitor command request to kill this process\n");
      break;
   case  5: { /* v.translate */
      Addr address;
      SizeT verbosity = 0x20;
      
      ret = 1;

      VG_(strtok_get_address_and_size) (&address, &verbosity, &ssaveptr);
      if (address != (Addr) 0 || verbosity != 0) {
         /* we need to force the output to log for the translation trace,
            as low level VEX tracing cannot be redirected to gdb. */
         int saved_command_output_to_log = command_output_to_log;
         int saved_fd = VG_(log_output_sink).fd;
         Bool single_stepping_on_entry = valgrind_single_stepping();
         int vex_verbosity = verbosity & 0xff;
         VG_(log_output_sink).fd = initial_valgrind_sink.fd;
         if ((verbosity & 0x100) && !single_stepping_on_entry) {
            valgrind_set_single_stepping(True); 
            // to force gdbserver instrumentation.
         }
#        if defined(VGA_arm)
         // on arm, we need to (potentially) convert this address
         // to the thumb form.
         address = thumb_pc (address);
#        endif

         VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
                          address,
                          /*debugging*/True, 
                          (Int) vex_verbosity,
                          /*bbs_done*/0,
                          /*allow redir?*/True);
         if ((verbosity & 0x100) && !single_stepping_on_entry) {
            valgrind_set_single_stepping(False);
            // reset single stepping.
         }
         command_output_to_log = saved_command_output_to_log;
         VG_(log_output_sink).fd = saved_fd;
      }
      break;
   }

   default:
      vg_assert (0);
   }
   return ret;
}
Пример #2
0
Bool VG_(is_watched)(PointKind kind, Addr addr, Int szB)
{
   GS_Watch* g;
   Bool watched = False;
   const ThreadId tid = VG_(running_tid);

   if (!gdbserver_called)
      return False;

   Addr to = addr + szB; // semi-open interval [addr, to[

   vg_assert (kind == access_watchpoint 
              || kind == read_watchpoint 
              || kind == write_watchpoint);
   dlog(1, "tid %d VG_(is_watched) %s addr %p szB %d\n",
        tid, VG_(ppPointKind) (kind), C2v(addr), szB);
   VG_(HT_ResetIter) (gs_watches);
   while ((g = VG_(HT_Next) (gs_watches))) {
      switch (g->kind) {
      case software_breakpoint:
      case hardware_breakpoint:
         break;
      case access_watchpoint:
      case read_watchpoint:
      case write_watchpoint:
         if (to <= g->addr || addr >= (g->addr + g->len))
            /* If no overlap, examine next watchpoint: */
            continue;

         watched = True; /* We have an overlap */

         /* call gdbserver if access kind reported by the tool
            matches the watchpoint kind. */
         if (kind == access_watchpoint
             || g->kind == access_watchpoint
             || g->kind == kind) {
            /* Watchpoint encountered.
               If this is a read watchpoint, we directly call gdbserver
               to report it to gdb.
               Otherwise, for a write watchpoint, we have to finish
               the instruction so as to modify the value.
               If we do not finish the instruction, then gdb sees no
               value change and continues.
               For a read watchpoint, we better call gdbserver directly:
               in case the current block is not gdbserved, Valgrind
               will execute instructions till the next block. */

            /* set the watchpoint stop address to the first read or written. */
            if (g->addr <= addr) {
               VG_(set_watchpoint_stop_address) (addr);
            } else {
               VG_(set_watchpoint_stop_address) (g->addr);
            }

            if (kind == write_watchpoint) {
               /* Let Valgrind stop as early as possible after this instruction
                  by switching to Single Stepping mode. */
               valgrind_set_single_stepping (True);
               invalidate_current_ip (tid, "m_gdbserver write watchpoint");
            } else {
               call_gdbserver (tid, watch_reason);
               VG_(set_watchpoint_stop_address) ((Addr) 0);
            }
            return True; // we are watched here.
         }
         break;
      default:
         vg_assert (0);
      }
   }
   return watched;
}