callgrind: add vgdb commands needed for porting callgrind_control

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11866 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/callgrind/main.c b/callgrind/main.c
index a0cf5cd..4670698 100644
--- a/callgrind/main.c
+++ b/callgrind/main.c
@@ -1355,6 +1355,91 @@
     VG_(message)(Vg_DebugMsg, "%s: instrumentation switched %s\n",
 		 reason, state ? "ON" : "OFF");
 }
+
+/* helper for dump_state_togdb */
+static void dump_state_of_thread_togdb(thread_info* ti)
+{
+    static Char buf[512];
+    static FullCost sum = 0, tmp = 0;
+    Int t, p, i;
+    BBCC *from, *to;
+    call_entry* ce;
+
+    t = CLG_(current_tid);
+    CLG_(init_cost_lz)( CLG_(sets).full, &sum );
+    CLG_(copy_cost_lz)( CLG_(sets).full, &tmp, ti->lastdump_cost );
+    CLG_(add_diff_cost)( CLG_(sets).full, sum, ti->lastdump_cost,
+			 ti->states.entry[0]->cost);
+    CLG_(copy_cost)( CLG_(sets).full, ti->lastdump_cost, tmp );
+    CLG_(sprint_mappingcost)(buf, CLG_(dumpmap), sum);
+    VG_(gdb_printf)("events-%d: %s\n", t, buf);
+    VG_(gdb_printf)("frames-%d: %d\n", t, CLG_(current_call_stack).sp);
+
+    ce = 0;
+    for(i = 0; i < CLG_(current_call_stack).sp; i++) {
+      ce = CLG_(get_call_entry)(i);
+      /* if this frame is skipped, we don't have counters */
+      if (!ce->jcc) continue;
+      
+      from = ce->jcc->from;
+      VG_(gdb_printf)("function-%d-%d: %s\n",t, i, from->cxt->fn[0]->name);
+      VG_(gdb_printf)("calls-%d-%d: %llu\n",t, i, ce->jcc->call_counter);
+      
+      /* FIXME: EventSets! */
+      CLG_(copy_cost)( CLG_(sets).full, sum, ce->jcc->cost );
+      CLG_(copy_cost)( CLG_(sets).full, tmp, ce->enter_cost );
+      CLG_(add_diff_cost)( CLG_(sets).full, sum,
+			  ce->enter_cost, CLG_(current_state).cost );
+      CLG_(copy_cost)( CLG_(sets).full, ce->enter_cost, tmp );
+      
+      p = VG_(sprintf)(buf, "events-%d-%d: ",t, i);
+      CLG_(sprint_mappingcost)(buf + p, CLG_(dumpmap), sum );
+      VG_(gdb_printf)("%s\n", buf);
+    }
+    if (ce && ce->jcc) {
+      to = ce->jcc->to;
+      VG_(gdb_printf)("function-%d-%d: %s\n",t, i, to->cxt->fn[0]->name );
+    }
+}
+
+/* Dump current state */
+static void dump_state_togdb(void)
+{
+    static Char buf[512];
+    thread_info** th;
+    int t, p;
+    Int orig_tid = CLG_(current_tid);
+
+    VG_(gdb_printf)("instrumentation: %s\n",
+		    CLG_(instrument_state) ? "on":"off");
+    if (!CLG_(instrument_state)) return;
+
+    VG_(gdb_printf)("executed-bbs: %llu\n", CLG_(stat).bb_executions);
+    VG_(gdb_printf)("executed-calls: %llu\n", CLG_(stat).call_counter);
+    VG_(gdb_printf)("distinct-bbs: %d\n", CLG_(stat).distinct_bbs);
+    VG_(gdb_printf)("distinct-calls: %d\n", CLG_(stat).distinct_jccs);
+    VG_(gdb_printf)("distinct-functions: %d\n", CLG_(stat).distinct_fns);
+    VG_(gdb_printf)("distinct-contexts: %d\n", CLG_(stat).distinct_contexts);
+
+    /* "events:" line. Given here because it will be dynamic in the future */
+    p = VG_(sprintf)(buf, "events: ");
+    CLG_(sprint_eventmapping)(buf+p, CLG_(dumpmap));
+    VG_(gdb_printf)("%s\n", buf);
+    /* "part:" line (number of last part. Is 0 at start */
+    VG_(gdb_printf)("part: %d\n", CLG_(get_dump_counter)());
+		
+    /* threads */
+    th = CLG_(get_threads)();
+    p = VG_(sprintf)(buf, "threads:");
+    for(t=1;t<VG_N_THREADS;t++) {
+	if (!th[t]) continue;
+	p += VG_(sprintf)(buf+p, " %d", t);
+    }
+    VG_(gdb_printf)("%s\n", buf);
+    VG_(gdb_printf)("current-tid: %d\n", orig_tid);
+    CLG_(forall_threads)(dump_state_of_thread_togdb);
+}
+
   
 static void print_monitor_help ( void )
 {
@@ -1364,6 +1449,10 @@
    VG_(gdb_printf) ("        dump counters\n");
    VG_(gdb_printf) ("  zero\n");
    VG_(gdb_printf) ("        zero counters\n");
+   VG_(gdb_printf) ("  status\n");
+   VG_(gdb_printf) ("        print status (statistics and shadow stacks)\n");
+   VG_(gdb_printf) ("  instrumentation [on|off]\n");
+   VG_(gdb_printf) ("        get/set (if on/off given) instrumentation state\n");
    VG_(gdb_printf) ("\n");
 }
 
@@ -1377,7 +1466,7 @@
    VG_(strcpy) (s, req);
 
    wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
-   switch (VG_(keyword_id) ("help dump zero", 
+   switch (VG_(keyword_id) ("help dump zero status instrumentation", 
                             wcmd, kwd_report_duplicated_matches)) {
    case -2: /* multiple matches */
       return True;
@@ -1394,6 +1483,20 @@
       CLG_(zero_all_cost)(False);
       return True;
    }
+   case 3: { /* status */
+     dump_state_togdb();
+     return True;
+   }
+   case 4: { /* instrumentation */
+     Char* arg = VG_(strtok_r) (0, " ", &ssaveptr);
+     if (!arg) {
+       VG_(gdb_printf)("instrumentation: %s\n",
+		       CLG_(instrument_state) ? "on":"off");
+     }
+     else
+       CLG_(set_instrument_state)("Command", VG_(strcmp)(arg,"off")!=0);
+     return True;
+   }
 
    default: 
       tl_assert(0);