[RFC] New option -B: simplify running gdb from build directory

Doug Evans
2013-12-27T19:42:38Z

Hi.

The "make run" Makefile rule simplifies running gdb from the shell,
but it doesn't simplify running gdb from gdb: I'm always typing
"--data-directory=$(pwd)/data-directory".
And since we can't agree on a way to let gdb auto-detect being run
from the build directory, how about this?

This patch provides a new option, -B, which if provided tells gdb
it *may* have been run from the build directory. If -B was provided
and --data-directory was not provided, use a heuristic to determine
if gdb was run from the build directory and if so set gdb_datadir
appropriately.

We can certainly discuss what's the best heuristic to use here.
We don't, IMO, have to employ too complicated a heuristic because
the user has explicitly passed -B.
OTOH, I'm sure one can improve a bit on the heuristic that's here.
One thought I have is to have the Makefile create a file with a name that
is reasonably obscure (maybe even pseudo-cryptographically secure and encode
the name in gdb?), and then simplify the test by just checking for that file.

If we can agree on this approach, I'll add NEWS and docs.

2013-12-27 Doug Evans <dje@google.com>

* main.c (maybe_run_from_builddir): New global.
(get_builddir): New function.
(captured_main): New option enum OPT_BATCH_SILENT, use it for
--batch-silent instead of 'B'. Add option -B: If -B is provided
and --data-directory is not, see if being run from build directory
and use that for gdb_datadir if so.

diff --git a/gdb/main.c b/gdb/main.c
index 7ff9183..7fa4168 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -58,6 +58,9 @@ int xdb_commands = 0;
/* Whether dbx commands will be handled. */
int dbx_commands = 0;

+/* Whether GDB may have been run from the build directory. */
+static int maybe_run_from_builddir = 0;
+
/* System root path, used to find libraries etc. */
char *gdb_sysroot = 0;

@@ -161,6 +164,52 @@ relocate_gdb_directory (const char *initial, int flag)
return dir;
}

+/* Return the directory gdb was run from if we can reasonably determine that
+ it was the build directory, otherwise return NULL.
+ Space for the builddir is obtained with malloc, caller must free.
+
+ We say "reasonably" because gdb *could* be run from a place that *looks*
+ like the build directory, and we want to avoid false positives as much as
+ is reasonably possible. This code is only used if the user passes -B to
+ gdb so our tests needn't be *perfect*.
+
+ The test is done by seeing if various files exist that we expect to find
+ in a build directory. There are a few constraints on our choices:
+
+ 1) We don't test for object files so that we don't have to deal with the
+ complexity of different suffixes (e.g., .o vs .obj).
+ 2) If the file got removed for whatever reason the developer might choose,
+ does that break using gdb? E.g., we could test for config.status or
+ some such, or deal with the complexity of different objfile suffixes,
+ but the file's absence doesn't actually break using gdb from the
+ build directory.
+ 3) We can't test for files that only exist for a particular configuration.
+
+ In the end the files we choose are files in data-directory since those
+ files are needed by gdb, plus files that typically only exist in the
+ build tree: stamp-syscalls and gdb-syscalls.dtd. */
+
+static char *
+get_builddir (void)
+{
+ char *gdb_dirname = ldirname (gdb_program_name);
+ char *datadir = xstrprintf ("%s/data-directory", gdb_dirname);
+ char *test_file1 = xstrprintf ("%s/stamp-syscalls", datadir);
+ char *test_file2 = xstrprintf ("%s/syscalls/gdb-syscalls.dtd", datadir);
+ int builddir_found;
+
+ builddir_found = (access (test_file1, R_OK) == 0
+ && access (test_file2, R_OK) == 0);
+ xfree (gdb_dirname);
+ xfree (test_file1);
+ xfree (test_file2);
+
+ if (builddir_found)
+ return datadir;
+ xfree (datadir);
+ return NULL;
+}
+
/* Compute the locations of init files that GDB should source and
return them in SYSTEM_GDBINIT, HOME_GDBINIT, LOCAL_GDBINIT. If
there is no system gdbinit (resp. home gdbinit and local gdbinit)
@@ -462,7 +511,8 @@ captured_main (void *data)
OPT_NOWINDOWS,
OPT_WINDOWS,
OPT_IX,
- OPT_IEX
+ OPT_IEX,
+ OPT_BATCH_SILENT
};
static struct option long_options[] =
{
@@ -477,7 +527,7 @@ captured_main (void *data)
{"nh", no_argument, &inhibit_home_gdbinit, 1},
{"nx", no_argument, &inhibit_gdbinit, 1},
{"n", no_argument, &inhibit_gdbinit, 1},
- {"batch-silent", no_argument, 0, 'B'},
+ {"batch-silent", no_argument, 0, OPT_BATCH_SILENT},
{"batch", no_argument, &batch_flag, 1},

/* This is a synonym for "--annotate=1". --annotate is now
@@ -531,6 +581,7 @@ captured_main (void *data)
{"args", no_argument, &set_args, 1},
{"l", required_argument, 0, 'l'},
{"return-child-result", no_argument, &return_child_result, 1},
+ {"B", no_argument, &maybe_run_from_builddir, 1},
{0, no_argument, 0, 0}
};

@@ -642,7 +693,7 @@ captured_main (void *data)
VEC_safe_push (cmdarg_s, cmdarg_vec, &cmdarg);
}
break;
- case 'B':
+ case OPT_BATCH_SILENT:
batch_flag = batch_silent = 1;
gdb_stdout = ui_file_new();
break;
@@ -755,6 +806,19 @@ captured_main (void *data)
quiet = 1;
}

+ /* If -B was provided and --data-directory was not, then see if we have been
+ run from the build directory and if so use the data-directory there. */
+ if (maybe_run_from_builddir && !gdb_datadir_provided)
+ {
+ char *builddir = get_builddir ();
+
+ if (builddir != NULL)
+ {
+ xfree (gdb_datadir);
+ gdb_datadir = builddir;
+ }
+ }
+
/* Initialize all files. Give the interpreter a chance to take
control of the console via the deprecated_init_ui_hook (). */
gdb_init (gdb_program_name);