Implement a GDB server in Valgrind. See #214909.
(Philippe Waroquiers, philippe.waroquiers@skynet.be)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11727 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 67702cd..6bc4925 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -180,6 +180,7 @@
#include "pub_tool_tooliface.h"
#include "pub_tool_xarray.h"
#include "pub_tool_clientstate.h"
+#include "pub_tool_gdbserver.h"
#include "valgrind.h" // For {MALLOC,FREE}LIKE_BLOCK
@@ -1977,6 +1978,21 @@
//--- Client Requests ---//
//------------------------------------------------------------//
+static void print_monitor_help ( void )
+{
+ VG_(gdb_printf) ("\n");
+ VG_(gdb_printf) ("massif monitor commands:\n");
+ VG_(gdb_printf) (" ms.snapshot [<filename>] [detailed]\n");
+ VG_(gdb_printf) (" takes a snapshot and saves it in <filename>\n");
+ VG_(gdb_printf) (" default <filename> is massif.vgdb.out\n");
+ VG_(gdb_printf) (" if present, detailed argument indicates to take a detailed snapshot\n");
+ VG_(gdb_printf) ("\n");
+}
+
+
+/* Forward declaration.
+ return True if request recognised, False otherwise */
+static Bool handle_gdb_monitor_command (ThreadId tid, Char *req);
static Bool ms_handle_client_request ( ThreadId tid, UWord* argv, UWord* ret )
{
switch (argv[0]) {
@@ -2003,6 +2019,15 @@
*ret = 0;
return True;
}
+ case VG_USERREQ__GDB_MONITOR_COMMAND: {
+ Bool handled = handle_gdb_monitor_command (tid, (Char*)argv[1]);
+ if (handled)
+ *ret = 1;
+ else
+ *ret = 0;
+ return handled;
+ }
+
default:
*ret = 0;
return False;
@@ -2287,19 +2312,13 @@
}
}
-static void write_snapshots_to_file(void)
+static void write_snapshots_to_file(Char* massif_out_file,
+ Snapshot snapshots_array[],
+ Int nr_elements)
{
Int i, fd;
SysRes sres;
- // Setup output filename. Nb: it's important to do this now, ie. as late
- // as possible. If we do it at start-up and the program forks and the
- // output file format string contains a %p (pid) specifier, both the
- // parent and child will incorrectly write to the same file; this
- // happened in 3.3.0.
- Char* massif_out_file =
- VG_(expand_file_name)("--massif-out-file", clo_massif_out_file);
-
sres = VG_(open)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
VKI_S_IRUSR|VKI_S_IWUSR);
if (sr_isError(sres)) {
@@ -2307,11 +2326,9 @@
// between multiple cachegrinded processes?), give up now.
VG_(umsg)("error: can't open output file '%s'\n", massif_out_file );
VG_(umsg)(" ... so profiling results will be missing.\n");
- VG_(free)(massif_out_file);
return;
} else {
fd = sr_Res(sres);
- VG_(free)(massif_out_file);
}
// Print massif-specific options that were used.
@@ -2342,12 +2359,75 @@
FP("time_unit: %s\n", TimeUnit_to_string(clo_time_unit));
- for (i = 0; i < next_snapshot_i; i++) {
- Snapshot* snapshot = & snapshots[i];
+ for (i = 0; i < nr_elements; i++) {
+ Snapshot* snapshot = & snapshots_array[i];
pp_snapshot(fd, snapshot, i); // Detailed snapshot!
}
+ VG_(close) (fd);
}
+static void write_snapshots_array_to_file(void)
+{
+ // Setup output filename. Nb: it's important to do this now, ie. as late
+ // as possible. If we do it at start-up and the program forks and the
+ // output file format string contains a %p (pid) specifier, both the
+ // parent and child will incorrectly write to the same file; this
+ // happened in 3.3.0.
+ Char* massif_out_file =
+ VG_(expand_file_name)("--massif-out-file", clo_massif_out_file);
+ write_snapshots_to_file (massif_out_file, snapshots, next_snapshot_i);
+ VG_(free)(massif_out_file);
+}
+
+static Bool handle_gdb_monitor_command (ThreadId tid, Char *req)
+{
+ Char* wcmd;
+ Char s[VG_(strlen(req))]; /* copy for strtok_r */
+ Char *ssaveptr;
+
+ VG_(strcpy) (s, req);
+
+ wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
+ switch (VG_(keyword_id) ("help ms.snapshot",
+ wcmd, kwd_report_duplicated_matches)) {
+ case -2: /* multiple matches */
+ return True;
+ case -1: /* not found */
+ return False;
+ case 0: /* help */
+ print_monitor_help();
+ return True;
+ case 1: { /* ms.snapshot */
+ Char* kw;
+ Char* filename = NULL;
+ Bool detailed = False;
+ Snapshot snapshot;
+
+ for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr);
+ kw != NULL;
+ kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
+ if (filename == NULL)
+ filename = kw;
+ else if (0 == VG_(strncmp)(kw, "detailed", VG_(strlen) (kw)))
+ detailed = True;
+ else {
+ VG_(gdb_printf) ("invalid 2nd arg\n");
+ return True;
+ }
+ }
+ clear_snapshot(&snapshot, /* do_sanity_check */ False);
+ take_snapshot(&snapshot, Normal, get_time(), detailed);
+ write_snapshots_to_file ((filename == NULL) ? (Char*) "massif.vgdb.out" : filename,
+ &snapshot,
+ 1);
+ delete_snapshot(&snapshot);
+ return True;
+ }
+ default:
+ tl_assert(0);
+ return False;
+ }
+}
//------------------------------------------------------------//
//--- Finalisation ---//
@@ -2356,7 +2436,7 @@
static void ms_fini(Int exit_status)
{
// Output.
- write_snapshots_to_file();
+ write_snapshots_array_to_file();
// Stats
tl_assert(n_xpts > 0); // always have alloc_xpt