Discussion:
[PATCH 0/4] New "set cwd" command
Sergio Durigan Junior
2017-09-12 04:23:21 UTC
Permalink
This patch series is a followup of the discussion that happened at:

https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html

It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
is a GDB-only command for now; its gdbserver counterpart will come
later.

The idea here is that "set cwd" will become the de facto way of
setting the inferior's cwd. Currently, the user can use "cd" for
that, but there are side effects: with "cd", GDB also switches to
another directory, and that can impact the loading of scripts and
other files. With "set cwd", we separate the logic into a new
command.

To maintain backward compatibility, if the user issues a "cd" command
but doesn't use "set cwd", then the inferior's cwd will still be
changed according to what the user specified. However, "set cwd" has
precedence over "cd", so it can always be used to override it.

This has been regtested on BuildBot, and the only failures I'm seeing
are related to a (very strange) stack overflow on guile, which just
happens on certain builders. I don't think this series has anything
to do about it, but if I find something related later I'll let you
know.
Sergio Durigan Junior
2017-09-12 04:23:22 UTC
Permalink
This is not a requirement for the feature, but I think it's a good
cleanup and is related anyway. Currently we have "current_directory"
and "gdb_dirbuf" globals, which means that we basically have two
possible places to consult when we want to know GDB's current working
directory.

This is not ideal and can lead to confusion, so my proposal is to
"internalize" the "gdb_dirbuf" variable, because it is really just
that: a buffer to be used when calling "getcwd". With this, only
"current_directory" should be used to determine the cwd.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* cli/cli-cmds.c (quit_command): Declare "gdb_dirbuf".
(cd_command): Free "current_directory" before assigning to it.
* main.c (captured_main_1): Likewise. Call "xstrdup" when
storing it on "current_directory".
* mi/mi-cmd-env.c (mi_cmd_env_pwd): Declare "gdb_dirbuf".
* top.c (gdb_dirbuf): Remove global declaration.
* top.h (gdb_dirbuf): Likewise.
---
gdb/cli/cli-cmds.c | 7 ++++++-
gdb/main.c | 4 +++-
gdb/mi/mi-cmd-env.c | 1 +
gdb/top.c | 3 ---
gdb/top.h | 1 -
5 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 883844ee70..64e893c784 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -380,6 +380,8 @@ quit_command (char *args, int from_tty)
static void
pwd_command (char *args, int from_tty)
{
+ char gdb_dirbuf[BUFSIZ];
+
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
@@ -434,7 +436,10 @@ cd_command (char *dir, int from_tty)

dir_holder.reset (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
- current_directory = dir_holder.release ();
+ {
+ xfree (current_directory);
+ current_directory = dir_holder.release ();
+ }
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
diff --git a/gdb/main.c b/gdb/main.c
index a0646edad6..9837729966 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -549,10 +549,12 @@ captured_main_1 (struct captured_main_args *context)
(xstrprintf ("%s: warning: ", gdb_program_name));
warning_pre_print = tmp_warn_preprint.get ();

+ char gdb_dirbuf[BUFSIZ];
+
if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
perror_warning_with_name (_("error finding working directory"));

- current_directory = gdb_dirbuf;
+ current_directory = xstrdup (gdb_dirbuf);

/* Set the sysroot path. */
gdb_sysroot = relocate_gdb_directory (TARGET_SYSTEM_ROOT,
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 977b6e274d..55d08ee5f2 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -62,6 +62,7 @@ void
mi_cmd_env_pwd (const char *command, char **argv, int argc)
{
struct ui_out *uiout = current_uiout;
+ char gdb_dirbuf[BUFSIZ];

if (argc > 0)
error (_("-environment-pwd: No arguments allowed"));
diff --git a/gdb/top.c b/gdb/top.c
index 742c1e7a07..0f36dce760 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -133,9 +133,6 @@ show_confirm (struct ui_file *file, int from_tty,

char *current_directory;

-/* The directory name is actually stored here (usually). */
-char gdb_dirbuf[1024];
-
/* The last command line executed on the console. Used for command
repetitions. */
char *saved_command_line;
diff --git a/gdb/top.h b/gdb/top.h
index 45798897f6..6b66083995 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -219,7 +219,6 @@ extern void ui_unregister_input_event_handler (struct ui *ui);
/* From top.c. */
extern char *saved_command_line;
extern int confirm;
-extern char gdb_dirbuf[1024];
extern int inhibit_gdbinit;
extern const char gdbinit[];
--
2.13.3
Pedro Alves
2017-09-13 15:12:11 UTC
Permalink
Post by Sergio Durigan Junior
This is not a requirement for the feature, but I think it's a good
cleanup and is related anyway. Currently we have "current_directory"
and "gdb_dirbuf" globals, which means that we basically have two
possible places to consult when we want to know GDB's current working
directory.
This is not ideal and can lead to confusion, so my proposal is to
"internalize" the "gdb_dirbuf" variable, because it is really just
that: a buffer to be used when calling "getcwd". With this, only
"current_directory" should be used to determine the cwd.
* cli/cli-cmds.c (quit_command): Declare "gdb_dirbuf".
(cd_command): Free "current_directory" before assigning to it.
* main.c (captured_main_1): Likewise. Call "xstrdup" when
storing it on "current_directory".
* mi/mi-cmd-env.c (mi_cmd_env_pwd): Declare "gdb_dirbuf".
* top.c (gdb_dirbuf): Remove global declaration.
* top.h (gdb_dirbuf): Likewise.
---
gdb/cli/cli-cmds.c | 7 ++++++-
gdb/main.c | 4 +++-
gdb/mi/mi-cmd-env.c | 1 +
gdb/top.c | 3 ---
gdb/top.h | 1 -
5 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 883844ee70..64e893c784 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -380,6 +380,8 @@ quit_command (char *args, int from_tty)
static void
pwd_command (char *args, int from_tty)
{
+ char gdb_dirbuf[BUFSIZ];
I don't recall offhand -- what's "BUFSIZ"? What defines it
and is it guaranteed to be the right size for getcwd?
Post by Sergio Durigan Junior
+
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
@@ -434,7 +436,10 @@ cd_command (char *dir, int from_tty)
dir_holder.reset (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
- current_directory = dir_holder.release ();
+ {
+ xfree (current_directory);
+ current_directory = dir_holder.release ();
+ }
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
diff --git a/gdb/main.c b/gdb/main.c
index a0646edad6..9837729966 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -549,10 +549,12 @@ captured_main_1 (struct captured_main_args *context)
(xstrprintf ("%s: warning: ", gdb_program_name));
warning_pre_print = tmp_warn_preprint.get ();
+ char gdb_dirbuf[BUFSIZ];
+
if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
perror_warning_with_name (_("error finding working directory"));
- current_directory = gdb_dirbuf;
+ current_directory = xstrdup (gdb_dirbuf);
As an extension, on GNU/Linux, you can call 'getcwd (NULL, 0)' and
that returns a heap-allocated buffer of the necessary size. Can we
rely on gnulib to implement that behavior everywhere? Since
it seems like we're xstrdup'ing the dir anyway, that likely would
simplify things, and remove one arbitrary hardcoded limit, while
at it.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-13 22:03:35 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
This is not a requirement for the feature, but I think it's a good
cleanup and is related anyway. Currently we have "current_directory"
and "gdb_dirbuf" globals, which means that we basically have two
possible places to consult when we want to know GDB's current working
directory.
This is not ideal and can lead to confusion, so my proposal is to
"internalize" the "gdb_dirbuf" variable, because it is really just
that: a buffer to be used when calling "getcwd". With this, only
"current_directory" should be used to determine the cwd.
* cli/cli-cmds.c (quit_command): Declare "gdb_dirbuf".
(cd_command): Free "current_directory" before assigning to it.
* main.c (captured_main_1): Likewise. Call "xstrdup" when
storing it on "current_directory".
* mi/mi-cmd-env.c (mi_cmd_env_pwd): Declare "gdb_dirbuf".
* top.c (gdb_dirbuf): Remove global declaration.
* top.h (gdb_dirbuf): Likewise.
---
gdb/cli/cli-cmds.c | 7 ++++++-
gdb/main.c | 4 +++-
gdb/mi/mi-cmd-env.c | 1 +
gdb/top.c | 3 ---
gdb/top.h | 1 -
5 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 883844ee70..64e893c784 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -380,6 +380,8 @@ quit_command (char *args, int from_tty)
static void
pwd_command (char *args, int from_tty)
{
+ char gdb_dirbuf[BUFSIZ];
I don't recall offhand -- what's "BUFSIZ"? What defines it
and is it guaranteed to be the right size for getcwd?
BUFSIZ is defined by stdio.h, and is 8192 on my Fedora 25. This is much
greater than the previous "1024" that was being used before. For
reproducibility reasons I didn't want to use PATH_MAX.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
@@ -434,7 +436,10 @@ cd_command (char *dir, int from_tty)
dir_holder.reset (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
- current_directory = dir_holder.release ();
+ {
+ xfree (current_directory);
+ current_directory = dir_holder.release ();
+ }
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
diff --git a/gdb/main.c b/gdb/main.c
index a0646edad6..9837729966 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -549,10 +549,12 @@ captured_main_1 (struct captured_main_args *context)
(xstrprintf ("%s: warning: ", gdb_program_name));
warning_pre_print = tmp_warn_preprint.get ();
+ char gdb_dirbuf[BUFSIZ];
+
if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
perror_warning_with_name (_("error finding working directory"));
- current_directory = gdb_dirbuf;
+ current_directory = xstrdup (gdb_dirbuf);
As an extension, on GNU/Linux, you can call 'getcwd (NULL, 0)' and
that returns a heap-allocated buffer of the necessary size. Can we
rely on gnulib to implement that behavior everywhere? Since
it seems like we're xstrdup'ing the dir anyway, that likely would
simplify things, and remove one arbitrary hardcoded limit, while
at it.
That's true, and it's better when you consider reproducible builds as
well.

According to gnulib:

https://www.gnu.org/software/gnulib/manual/html_node/getcwd.html

It is better to rely on this better version of getcwd.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-13 22:19:27 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -380,6 +380,8 @@ quit_command (char *args, int from_tty)
static void
pwd_command (char *args, int from_tty)
{
+ char gdb_dirbuf[BUFSIZ];
I don't recall offhand -- what's "BUFSIZ"? What defines it
and is it guaranteed to be the right size for getcwd?
BUFSIZ is defined by stdio.h, and is 8192 on my Fedora 25. This is much
greater than the previous "1024" that was being used before.
Ah, that BUFSIZ. That's the FILE* stream buffer size [1], so I don't
see it makes sense to use it for paths over PATH_MAX. It happens to be
greater that 1024 on your system, but that's not guaranteed, no?

[1] - http://pubs.opengroup.org/onlinepubs/9699919799/functions/setbuf.html
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html
Post by Sergio Durigan Junior
For reproducibility reasons I didn't want to use PATH_MAX.
I don't understand this. Can you expand? What's not reproducible
about PATH_MAX? How's that different from BUFSIZ?
Post by Sergio Durigan Junior
Post by Pedro Alves
As an extension, on GNU/Linux, you can call 'getcwd (NULL, 0)' and
that returns a heap-allocated buffer of the necessary size. Can we
rely on gnulib to implement that behavior everywhere? Since
it seems like we're xstrdup'ing the dir anyway, that likely would
simplify things, and remove one arbitrary hardcoded limit, while
at it.
That's true, and it's better when you consider reproducible builds as
well.
/me confused about that.
Post by Sergio Durigan Junior
https://www.gnu.org/software/gnulib/manual/html_node/getcwd.html
It is better to rely on this better version of getcwd.
Alright. This makes the above moot, though I'd still like to
understand the reproducibility argument, since I suspect that
may come back in other cases.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-13 22:46:53 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -380,6 +380,8 @@ quit_command (char *args, int from_tty)
static void
pwd_command (char *args, int from_tty)
{
+ char gdb_dirbuf[BUFSIZ];
I don't recall offhand -- what's "BUFSIZ"? What defines it
and is it guaranteed to be the right size for getcwd?
BUFSIZ is defined by stdio.h, and is 8192 on my Fedora 25. This is much
greater than the previous "1024" that was being used before.
Ah, that BUFSIZ. That's the FILE* stream buffer size [1], so I don't
see it makes sense to use it for paths over PATH_MAX. It happens to be
greater that 1024 on your system, but that's not guaranteed, no?
[1] - http://pubs.opengroup.org/onlinepubs/9699919799/functions/setbuf.html
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html
AFAIK that's not a guarantee, indeed. Although "1024" is also a very
low value for path names on some systems (for example, here PATH_MAX is
defined as 4096), we already had this problem before.
Post by Pedro Alves
Post by Sergio Durigan Junior
For reproducibility reasons I didn't want to use PATH_MAX.
I don't understand this. Can you expand? What's not reproducible
about PATH_MAX? How's that different from BUFSIZ?
Post by Sergio Durigan Junior
Post by Pedro Alves
As an extension, on GNU/Linux, you can call 'getcwd (NULL, 0)' and
that returns a heap-allocated buffer of the necessary size. Can we
rely on gnulib to implement that behavior everywhere? Since
it seems like we're xstrdup'ing the dir anyway, that likely would
simplify things, and remove one arbitrary hardcoded limit, while
at it.
That's true, and it's better when you consider reproducible builds as
well.
/me confused about that.
Post by Sergio Durigan Junior
https://www.gnu.org/software/gnulib/manual/html_node/getcwd.html
It is better to rely on this better version of getcwd.
Alright. This makes the above moot, though I'd still like to
understand the reproducibility argument, since I suspect that
may come back in other cases.
Well, maybe this is more a question of portability than reproducibility,
but I mentioned the latter because I remember doing some fixes in some
Debian packages that were failing the reproducible tests due to the
presence of PATH_MAX. They were actually failing to build on certain
targets, but that can be seen as non-reproducibility as well.

PATH_MAX is defined by POSIX but is not used by every system. GNU/Hurd,
for example, doesn't define it. As usual with GNU programs the
"correct" thing to do is not to rely on some hard-coded limit imposed by
a header file, but rather to make use of the fact that glibc's getcwd
offers the possibility to allocate the variable that holds the path
according to its actual size.

There are some other problems with PATH_MAX, e.g., the fact that the
maximum length of a pathname is really defined by the underlying
filesystem you're using, so just using "4096" doesn't really reflect the
reality.

Again, maybe I should have said "portability issues", but I consider
them reproducibility issues as well.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-13 23:47:24 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Pedro Alves
Ah, that BUFSIZ. That's the FILE* stream buffer size [1], so I don't
see it makes sense to use it for paths over PATH_MAX. It happens to be
greater that 1024 on your system, but that's not guaranteed, no?
[1] - http://pubs.opengroup.org/onlinepubs/9699919799/functions/setbuf.html
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html
AFAIK that's not a guarantee, indeed. Although "1024" is also a very
low value for path names on some systems (for example, here PATH_MAX is
defined as 4096), we already had this problem before.
Yes, but at least 1024 was stable and usually good enough.
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Pedro Alves
For reproducibility reasons I didn't want to use PATH_MAX.
I don't understand this. Can you expand? What's not reproducible
about PATH_MAX? How's that different from BUFSIZ?
Post by Pedro Alves
Post by Pedro Alves
As an extension, on GNU/Linux, you can call 'getcwd (NULL, 0)' and
that returns a heap-allocated buffer of the necessary size. Can we
rely on gnulib to implement that behavior everywhere? Since
it seems like we're xstrdup'ing the dir anyway, that likely would
simplify things, and remove one arbitrary hardcoded limit, while
at it.
That's true, and it's better when you consider reproducible builds as
well.
/me confused about that.
Post by Pedro Alves
https://www.gnu.org/software/gnulib/manual/html_node/getcwd.html
It is better to rely on this better version of getcwd.
Alright. This makes the above moot, though I'd still like to
understand the reproducibility argument, since I suspect that
may come back in other cases.
Well, maybe this is more a question of portability than reproducibility,
but I mentioned the latter because I remember doing some fixes in some
Debian packages that were failing the reproducible tests due to the
presence of PATH_MAX. They were actually failing to build on certain
targets, but that can be seen as non-reproducibility as well.
I think that's stretching what reproducibility means too far,
and ends up being confusing. AFAICT, it'd be like saying that a program
isn't reproducible because it uses "ptrace", because "ptrace" isn't portable.
Well, that "ptrace" call may be the whole point of the program.
If you can always build the program on environment A and end up with
the same binary, then the program is reproducible on environment A.
That does not mean that you should expect to build the program under some
environment B [e.g., different compiler version or different system
libraries, or different kernel, or different architecture, or ...] and
get the same binary as in environment A.
Post by Sergio Durigan Junior
PATH_MAX is defined by POSIX but is not used by every system. GNU/Hurd,
for example, doesn't define it. As usual with GNU programs the
"correct" thing to do is not to rely on some hard-coded limit imposed by
a header file, but rather to make use of the fact that glibc's getcwd
offers the possibility to allocate the variable that holds the path
according to its actual size.
Correct. That's exactly why I thought of suggesting getcwd's extension.
Post by Sergio Durigan Junior
There are some other problems with PATH_MAX, e.g., the fact that the
maximum length of a pathname is really defined by the underlying
filesystem you're using, so just using "4096" doesn't really reflect the
reality.
Right, on GNU/Linux we can certainly have paths longer than that.
Post by Sergio Durigan Junior
Again, maybe I should have said "portability issues", but I consider
them reproducibility issues as well.
Alright, glad we cleared this up, and glad that it's all moot now. :-)

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-12 04:23:24 UTC
Permalink
In order to be able to change the inferior's directory before its
execution, it is necessary to perform a tilde expansion of the
directory provided by the user and then chdir into the resulting dir.
This is what gdb_chdir does.

Unfortunately it is not possible to use "tilde_expand" from readline
because this is common code and gdbserver doesn't use readline. For
that reason I decided to go with "glob" and its GNU extension,
GLOB_TILDE. With the import of the "glob" module from gnulib, this is
a no-brainer.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add gdb_chdir.c.
(HFILES_NO_SRCDIR): Add gdb_chdir.h.
(COMMON_OBS): Add gdb_chdir.o.
* common/gdb_chdir.c: New file.
* common/gdb_chdir.h: Likewise.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add $(srcdir)/common/gdb_chdir.c.
(OBS): Add gdb_chdir.o.
---
gdb/Makefile.in | 3 +++
gdb/common/gdb_chdir.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
gdb/common/gdb_chdir.h | 26 ++++++++++++++++++++
gdb/gdbserver/Makefile.in | 2 ++
4 files changed, 91 insertions(+)
create mode 100644 gdb/common/gdb_chdir.c
create mode 100644 gdb/common/gdb_chdir.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2aa474e598..38c89761dd 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1243,6 +1243,7 @@ SFILES = \
common/filestuff.c \
common/format.c \
common/job-control.c \
+ common/gdb_chdir.c \
common/gdb_vecs.c \
common/new-op.c \
common/print-utils.c \
@@ -1527,6 +1528,7 @@ HFILES_NO_SRCDIR = \
common/fileio.h \
common/format.h \
common/gdb_assert.h \
+ common/gdb_chdir.h \
common/gdb_locale.h \
common/gdb_setjmp.h \
common/gdb_signals.h \
@@ -1732,6 +1734,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
frame-unwind.o \
gcore.o \
gdb_bfd.o \
+ gdb_chdir.o \
gdb-dlfcn.o \
gdb_obstack.o \
gdb_regex.o \
diff --git a/gdb/common/gdb_chdir.c b/gdb/common/gdb_chdir.c
new file mode 100644
index 0000000000..16e2b3adf0
--- /dev/null
+++ b/gdb/common/gdb_chdir.c
@@ -0,0 +1,60 @@
+/* chdir(2) wrapper for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "common-defs.h"
+#include <glob.h>
+#include "gdb_chdir.h"
+
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+
+static std::string
+expand_path (const char *dir)
+{
+ glob_t g;
+ std::string expanded_dir;
+ int err = glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL, &g);
+
+ if (err != 0)
+ {
+ if (err == GLOB_NOMATCH)
+ error (_("No such directory '%s'. Failure to set cwd."), dir);
+
+ error (_("Could not process directory '%s'."), dir);
+ }
+
+ gdb_assert (g.gl_pathc > 0);
+ /* "glob" may return more than one match to the path provided by the
+ user, but we are only interested in the first match. */
+ expanded_dir = g.gl_pathv[0];
+ globfree (&g);
+
+ return expanded_dir;
+}
+
+/* See gdb_chdir.h. */
+
+void
+gdb_chdir (const char *dir)
+{
+ std::string expanded_dir = expand_path (dir);
+
+ if (chdir (expanded_dir.c_str ()) < 0)
+ perror_with_name (expanded_dir.c_str ());
+}
diff --git a/gdb/common/gdb_chdir.h b/gdb/common/gdb_chdir.h
new file mode 100644
index 0000000000..5e6253e3b5
--- /dev/null
+++ b/gdb/common/gdb_chdir.h
@@ -0,0 +1,26 @@
+/* chdir(2) wrapper for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef HAVE_GDB_CHDIR_H
+#define HAVE_GDB_CHDIR_H
+
+/* Perform a "chdir" to DIR, doing the proper tilde expansion before. */
+extern void gdb_chdir (const char *dir);
+
+#endif /* ! HAVE_GDB_CHDIR_H */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1bbe515629..ecd12a7dcc 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -205,6 +205,7 @@ SFILES = \
$(srcdir)/common/fileio.c \
$(srcdir)/common/filestuff.c \
$(srcdir)/common/job-control.c \
+ $(srcdir)/common/gdb_chdir.c \
$(srcdir)/common/gdb_vecs.c \
$(srcdir)/common/new-op.c \
$(srcdir)/common/print-utils.c \
@@ -247,6 +248,7 @@ OBS = \
fileio.o \
filestuff.o \
format.o \
+ gdb_chdir.o \
gdb_vecs.o \
hostio.o \
inferiors.o \
--
2.13.3
Eli Zaretskii
2017-09-12 14:53:33 UTC
Permalink
Date: Tue, 12 Sep 2017 00:23:24 -0400
In order to be able to change the inferior's directory before its
execution, it is necessary to perform a tilde expansion of the
directory provided by the user and then chdir into the resulting dir.
This is what gdb_chdir does.
Unfortunately it is not possible to use "tilde_expand" from readline
because this is common code and gdbserver doesn't use readline. For
that reason I decided to go with "glob" and its GNU extension,
GLOB_TILDE. With the import of the "glob" module from gnulib, this is
a no-brainer.
Why not simply 'getenv("HOME")'?
Sergio Durigan Junior
2017-09-13 22:59:56 UTC
Permalink
Post by Eli Zaretskii
Date: Tue, 12 Sep 2017 00:23:24 -0400
In order to be able to change the inferior's directory before its
execution, it is necessary to perform a tilde expansion of the
directory provided by the user and then chdir into the resulting dir.
This is what gdb_chdir does.
Unfortunately it is not possible to use "tilde_expand" from readline
because this is common code and gdbserver doesn't use readline. For
that reason I decided to go with "glob" and its GNU extension,
GLOB_TILDE. With the import of the "glob" module from gnulib, this is
a no-brainer.
Why not simply 'getenv("HOME")'?
Tilde expansion can be more complicated than that. If you're just using
"~/test", then yeah, you can use $HOME. However, the user can specify a
directory like "~someone/test", and in that case you have to where is
"someone's $HOME" before you can expand the tilde. glob takes care of
that for us.
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-13 16:07:02 UTC
Permalink
Post by Sergio Durigan Junior
+#include "common-defs.h"
+#include <glob.h>
+#include "gdb_chdir.h"
As per the guidelines, the module's own header should be
included first thing right after "common-defs.h". That
allows exposing unsatisfied dependencies (missing includes)
in the header, if any is missing.
Post by Sergio Durigan Junior
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+
+static std::string
+expand_path (const char *dir)
Since this is particularly about tilde expansion,
and a replacement for "tilde_expand", did you consider calling
it gdb_tilde_expand and using it throughout? If this were an
extern function, I'd press for having "tilde" in its name,
to make the call sites a bit more obvious.
Post by Sergio Durigan Junior
+{
+ glob_t g;
+ std::string expanded_dir;
Move declaration further below to the initialization line,
to avoid pointlessly default-constructing the string:

std::string expanded_dir = g.gl_pathv[0];
Post by Sergio Durigan Junior
+ int err = glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL, &g);
+
+ if (err != 0)
+ {
+ if (err == GLOB_NOMATCH)
+ error (_("No such directory '%s'. Failure to set cwd."), dir);
The "Failure to set cwd" string doesn't seem like an error that
should be in "expand_path"? OK, not really an issue since this
is a single-use static function...
Post by Sergio Durigan Junior
+
+ error (_("Could not process directory '%s'."), dir);
+ }
+
+ gdb_assert (g.gl_pathc > 0);
+ /* "glob" may return more than one match to the path provided by the
+ user, but we are only interested in the first match. */
+ expanded_dir = g.gl_pathv[0];
+ globfree (&g);
Pedantically, this isn't strictly exception safe, since
either the gdb_assert or the expanded_dir initialization
(a string dup which can fail with out of memory) could throw.

I think I'd write a thin RAII wrapper around glob that'd have a
single "glob_t m_g;" field, that'd call glob in the ctor, and
globfree in the dtor.
Post by Sergio Durigan Junior
+
+ return expanded_dir;
+}
+
Sergio Durigan Junior
2017-09-14 15:14:42 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
+#include "common-defs.h"
+#include <glob.h>
+#include "gdb_chdir.h"
As per the guidelines, the module's own header should be
included first thing right after "common-defs.h". That
allows exposing unsatisfied dependencies (missing includes)
in the header, if any is missing.
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+
+static std::string
+expand_path (const char *dir)
Since this is particularly about tilde expansion,
and a replacement for "tilde_expand", did you consider calling
it gdb_tilde_expand and using it throughout? If this were an
extern function, I'd press for having "tilde" in its name,
to make the call sites a bit more obvious.
Sure, no problem in renaming it. Just to clarify: when you mean "use it
throughout", are saying that this should be used to replace readline's
"tilde_expand" elsewhere on GDB?
Post by Pedro Alves
Post by Sergio Durigan Junior
+{
+ glob_t g;
+ std::string expanded_dir;
Move declaration further below to the initialization line,
std::string expanded_dir = g.gl_pathv[0];
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+ int err = glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR,
NULL, &g);
Post by Sergio Durigan Junior
+
+ if (err != 0)
+ {
+ if (err == GLOB_NOMATCH)
+ error (_("No such directory '%s'. Failure to set cwd."), dir);
The "Failure to set cwd" string doesn't seem like an error that
should be in "expand_path"? OK, not really an issue since this
is a single-use static function...
You're right. I'll make sure to display this error on "gdb_chdir"
instead.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+ error (_("Could not process directory '%s'."), dir);
+ }
+
+ gdb_assert (g.gl_pathc > 0);
+ /* "glob" may return more than one match to the path provided by the
+ user, but we are only interested in the first match. */
+ expanded_dir = g.gl_pathv[0];
+ globfree (&g);
Pedantically, this isn't strictly exception safe, since
either the gdb_assert or the expanded_dir initialization
(a string dup which can fail with out of memory) could throw.
I think I'd write a thin RAII wrapper around glob that'd have a
single "glob_t m_g;" field, that'd call glob in the ctor, and
globfree in the dtor.
OK, I can do that, no problem.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-14 15:23:16 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+
+static std::string
+expand_path (const char *dir)
Since this is particularly about tilde expansion,
and a replacement for "tilde_expand", did you consider calling
it gdb_tilde_expand and using it throughout? If this were an
extern function, I'd press for having "tilde" in its name,
to make the call sites a bit more obvious.
Sure, no problem in renaming it. Just to clarify: when you mean "use it
throughout", are saying that this should be used to replace readline's
"tilde_expand" elsewhere on GDB?
Yes, and no. Yes, by 'throughout' I meant elsewhere in GDB.
But no, I'm not _saying_ it should. I'm really asking if you
considered/thought about that.

I think what I'm really wondering is whether tilde_expand
and this new function behave exactly the same, or whether
glob behaves a little different in some cases. If it behaves
differently [and the differences are benign), then I get to
wonder whether we should use it throughout so that different
commands don't behave differently.

E.g., does "cd *" behave the same before/after ? Or does
'glob' expand '*' while tilde_expand didn't?

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-14 15:33:00 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+
+static std::string
+expand_path (const char *dir)
Since this is particularly about tilde expansion,
and a replacement for "tilde_expand", did you consider calling
it gdb_tilde_expand and using it throughout? If this were an
extern function, I'd press for having "tilde" in its name,
to make the call sites a bit more obvious.
Sure, no problem in renaming it. Just to clarify: when you mean "use it
throughout", are saying that this should be used to replace readline's
"tilde_expand" elsewhere on GDB?
Yes, and no. Yes, by 'throughout' I meant elsewhere in GDB.
But no, I'm not _saying_ it should. I'm really asking if you
considered/thought about that.
I thought about that while I was making the patch.

My very initial plan was to actually use 'wordexp', but I gave up on
that when I noticed that the function is not implemented in many targets
and gnulib doesn't provide a module for it. So I went ahead and decided
to use glob, but left the "cd_command" untouched just because it is
"already working" (TM).
Post by Pedro Alves
I think what I'm really wondering is whether tilde_expand
and this new function behave exactly the same, or whether
glob behaves a little different in some cases. If it behaves
differently [and the differences are benign), then I get to
wonder whether we should use it throughout so that different
commands don't behave differently.
E.g., does "cd *" behave the same before/after ? Or does
'glob' expand '*' while tilde_expand didn't?
From my initial tests I can see that "glob" and "tilde_expand" behave
the same, but I'll try to test more corner cases and see the results.
Apparently it'll be fine to just replace "tilde_expand".
--
Sergio GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible http://sergiodj.net/
Sergio Durigan Junior
2017-09-12 04:23:25 UTC
Permalink
This is the actual implementation of the "set/show cwd" commands. The
way they work is:

- If the user sets the inferior's cwd by using "set cwd", then this
directory is saved into current_inferior ()->cwd and is used when
the inferior is started (see below).

- If the user doesn't set the inferior's cwd by using "set cwd", but
rather use the "cd" command as before, the this directory is
inherited by the inferior because GDB will have chdir'd into it.

The way the directory is changed before the inferior execution is by
calling "gdb_chdir" after the call to fork/vfork on "fork_inferior",
but before the actual execution. This way, we'll make sure that GDB's
cwd is not affected by the user set cwd.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* NEWS (New commands): Mention "set/show cwd".
* cli/cli-cmds.c (_initialize_cli_cmds): Mention "set cwd" on
"cd" command's help text.
* common/common-inferior.h (get_inferior_cwd): New prototype.
* infcmd.c: Include "gdb_chdir.h" and "readline/tilde.h".
(inferior_cwd_scratch): New global variable.
(set_inferior_cwd): New function.
(get_inferior_cwd): Likewise.
(set_cwd_command): Likewise.
(show_cwd_command): Likewise.
(_initialize_infcmd): Add "set/show cwd" commands.
* inferior.h (class inferior) <cwd>: New field.
* nat/fork-inferior.c: Include "gdb_chdir.h".
(fork_inferior): Change inferior's cwd before its execution.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* inferiors.c (get_inferior_cwd): New function.
* inferiors.h (struct process_info) <cwd>: New field.

gdb/doc/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.texinfo (The working directory): Mention new "set cwd"
command.
(Your Program's Working Directory): Likewise.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.base/set-cwd.c: New file.
* gdb.base/set-cwd.exp: Likewise.
---
gdb/NEWS | 3 ++
gdb/cli/cli-cmds.c | 6 +--
gdb/common/common-inferior.h | 4 ++
gdb/doc/gdb.texinfo | 25 +++++++++--
gdb/gdbserver/inferiors.c | 11 +++++
gdb/infcmd.c | 75 +++++++++++++++++++++++++++++++
gdb/inferior.h | 4 ++
gdb/nat/fork-inferior.c | 17 +++++++
gdb/testsuite/gdb.base/set-cwd.c | 29 ++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 90 ++++++++++++++++++++++++++++++++++++++
10 files changed, 257 insertions(+), 7 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/set-cwd.c
create mode 100644 gdb/testsuite/gdb.base/set-cwd.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 2e6d48c016..bf81ce0270 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -61,6 +61,9 @@ QStartupWithShell

* New commands

+set|show cwd
+ Set and show the current working directory for the inferior.
+
set|show compile-gcc
Set and show compilation command used for compiling and injecting code
with the 'compile' commands.
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 64e893c784..57975fc587 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1716,9 +1716,9 @@ The commands below can be used to select other frames by number or address."),
Print working directory. This is used for your program as well."));

c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
set_cmd_completer (c, filename_completer);

add_com ("echo", class_support, echo_command, _("\
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 87c13009ed..515a8c0f4e 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -30,4 +30,8 @@ extern const char *get_exec_wrapper ();
otherwise return 0 in that case. */
extern char *get_exec_file (int err);

+/* Return the inferior's current working directory. If nothing has
+ been set, then return NULL. */
+extern const char *get_inferior_cwd ();
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8282dae7c3..14f85f97fd 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2057,10 +2057,11 @@ environment} to change parts of the environment that affect
your program. @xref{Environment, ,Your Program's Environment}.

@item The @emph{working directory.}
-Your program inherits its working directory from @value{GDBN}. You can set
-the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}.
+Your program inherits its working directory from @value{GDBN}. This
+can be changed by using the @code{set cwd} command in @value{GDBN}.
@xref{Working Directory, ,Your Program's Working Directory}.

+
@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
standard output as @value{GDBN} is using. You can redirect input and output
@@ -2427,14 +2428,30 @@ variables to files that are only run when you sign on, such as
Each time you start your program with @code{run}, it inherits its
working directory from the current working directory of @value{GDBN}.
The @value{GDBN} working directory is initially whatever it inherited
-from its parent process (typically the shell), but you can specify a new
-working directory in @value{GDBN} with the @code{cd} command.
+from its parent process (typically the shell), but you can specify a
+new working directory in @value{GDBN} with the @code{cd} command. You
+can specify a working directory especifically for the inferior with
+the @code{set cwd} command.

The @value{GDBN} working directory also serves as a default for the commands
that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to
Specify Files}.

@table @code
+@kindex set cwd
+@cindex change inferior's working directory
+@item set cwd @r{[}@var{directory}@r{]}
+Set the inferior's working directory to @var{directory}. If not
+given, @var{directory} uses @file{'~'}. This has no effect on
+@value{GDBN}'s working directory.
+
+@kindex show cwd
+@cindex show inferior's working directory
+@item show cwd
+Show the inferior's working directory. If no directory has been
+specified by @code{set cwd}, then the default inferior's working
+directory is the same as @value{GDBN}'s working directory.
+
@kindex cd
@cindex change working directory
@item cd @r{[}@var{directory}@r{]}
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 3c171a179e..47307c913e 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,9 @@ struct thread_info *current_thread;

#define get_thread(inf) ((struct thread_info *)(inf))

+/* The current working directory used to start the inferior. */
+static const char *current_inferior_cwd = NULL;
+
void
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
@@ -471,3 +474,11 @@ switch_to_thread (ptid_t ptid)
if (!ptid_equal (ptid, minus_one_ptid))
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 25cf025426..804bb25101 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -59,6 +59,8 @@
#include "top.h"
#include "interps.h"
#include "common/gdb_optional.h"
+#include "gdb_chdir.h"
+#include "readline/tilde.h"

/* Local functions: */

@@ -111,6 +113,10 @@ static void run_command (char *, int);

static char *inferior_args_scratch;

+/* Scratch area where the new cwd will be stored by 'set cwd'. */
+
+static char *inferior_cwd_scratch;
+
/* Scratch area where 'set inferior-tty' will store user-provided value.
We'll immediate copy it into per-inferior storage. */

@@ -246,6 +252,56 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}

+/* Set the inferior current working directory. This directory will be
+ entered by GDB before executing the inferior. */
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+ xfree ((void *) inf->cwd);
+ inf->cwd = tilde_expand (*cwd != '\0' ? cwd : "~");
+}
+
+/* See inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior ()->cwd;
+}
+
+/* Handle the 'set cwd' command. */
+
+static void
+set_cwd_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_inferior_cwd (inferior_cwd_scratch);
+}
+
+/* Handle the 'show cwd' command. */
+
+static void
+show_cwd_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd == NULL)
+ {
+ /* To maintain backwards compatibility, we use
+ 'current_directory' here, which is set by the "cd"
+ command. */
+ cwd = current_directory;
+ }
+
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+

/* Compute command-line string given argument vector. This does the
same shell processing as fork_inferior. */
@@ -3214,6 +3270,25 @@ Follow this command with any number of args, to be passed to the program."),
gdb_assert (c != NULL);
set_cmd_completer (c, filename_completer);

+ cmd_name = "cwd";
+ add_setshow_string_noescape_cmd (cmd_name, class_run,
+ &inferior_cwd_scratch, _("\
+Set the current working directory to be used when the inferior is started.\n\
+Changing this setting does not have any effect on inferiors that are\n\
+already running."),
+ _("\
+Show the current working directory that is used when the inferior is started."),
+ _("\
+Use this command to change the current working directory that will be used\n\
+when the inferior is started. This setting does not affect GDB's current\n\
+working directory."),
+ set_cwd_command,
+ show_cwd_command,
+ &setlist, &showlist);
+ c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+ gdb_assert (c != NULL);
+ set_cmd_completer (c, filename_completer);
+
c = add_cmd ("environment", no_class, environment_info, _("\
The environment to give the program, or one variable's value.\n\
With an argument VAR, prints the value of environment variable VAR to\n\
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 6d020f73c4..bcd1e54a03 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -355,6 +355,10 @@ public:
should never be freed. */
char **argv = NULL;

+ /* The current working directory that will be used when starting
+ this inferior. */
+ const char *cwd = NULL;
+
/* The name of terminal device to use for I/O. */
char *terminal = NULL;

diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index 0913409e6d..6ff0c2d216 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -25,6 +25,7 @@
#include "common-inferior.h"
#include "common-gdbthread.h"
#include "signals-state-save-restore.h"
+#include "gdb_chdir.h"
#include <vector>

extern char **environ;
@@ -376,6 +377,22 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();

+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd != NULL)
+ {
+ TRY
+ {
+ gdb_chdir (cwd);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ warning ("%s", ex.message);
+ _exit (0177);
+ }
+ END_CATCH
+ }
+
if (debug_fork)
sleep (debug_fork);

diff --git a/gdb/testsuite/gdb.base/set-cwd.c b/gdb/testsuite/gdb.base/set-cwd.c
new file mode 100644
index 0000000000..488fc4e4e3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main (int argc, char *argv[])
+{
+ char dir[BUFSIZ];
+
+ getcwd (dir, BUFSIZ);
+
+ return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
new file mode 100644
index 0000000000..3a6ffd3862
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -0,0 +1,90 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if { ![isnative] || [is_remote target] || [is_remote host]
+ || [target_info gdb_protocol] == "extended-remote" } then {
+ untested "not implemented on gdbserver"
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ if { [info exists ::env(HOME)] } {
+ with_test_prefix "test tilde expansion" {
+ set home $::env(HOME)
+
+ gdb_test_no_output "set cwd ~/test" "set cwd to ~/test dir"
+
+ gdb_test "show cwd" \
+ "Current working directory that will be used when starting the inferior is \"${home}/test\"\." \
+ "show cwd shows expanded tilde"
+ }
+ }
+}
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ }
+
+ set tmpdir [standard_output_file ""]
+
+ gdb_test_no_output "set cwd $tmpdir" "set cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ }
+
+ set test "GDB cwd is unchanged after running inferior"
+ if { [string equal $gdb_cwd_before_run $gdb_cwd_after_run] } {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+}
+
+test_cd_into_dir
+test_tilde_expansion
--
2.13.3
Eli Zaretskii
2017-09-12 14:50:22 UTC
Permalink
Date: Tue, 12 Sep 2017 00:23:25 -0400
-from its parent process (typically the shell), but you can specify a new
+from its parent process (typically the shell), but you can specify a
+can specify a working directory especifically for the inferior with
^^^^^^^^^^^^^
A typo.
The quotes inside @file are redundant, please drop them.

Otherwise, the documentation parts are OK, thanks.
Sergio Durigan Junior
2017-09-12 04:23:23 UTC
Permalink
This module is necessary because of the rework that will be done in
the "change directory" logic on GDB/gdbserver in the next commit.

We will have a way to "cd" to a directory also on gdbserver, but in
order to do that uniformly, there must be a way to do tilde expansion
on directories provided by the user. Currently, GDB uses
"tilde_expand" from readline to do that, but gdbserver doesn't link
against readline and therefore cannot use this function. The solution
is to use "glob" instead, which can perform tilde expansion as a GNU
extension. Therefore, we need gnulib's version of "glob".

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gnulib/aclocal.m4: Regenerate.
* gnulib/config.in: Likewise.
* gnulib/configure: Likewise.
* gnulib/import/Makefile.am: Likewise.
* gnulib/import/Makefile.in: Likewise.
* gnulib/import/closedir.c: New file.
* gnulib/import/dirent-private.h: Likewise.
* gnulib/import/filename.h: Likewise.
* gnulib/import/getlogin_r.c: Likewise.
* gnulib/import/glob-libc.h: Likewise.
* gnulib/import/glob.c: Likewise.
* gnulib/import/glob.in.h: Likewise.
* gnulib/import/m4/closedir.m4: Likewise.
* gnulib/import/m4/d-type.m4: Likewise.
* gnulib/import/m4/getlogin_r.m4: Likewise.
* gnulib/import/m4/glob.m4: Likewise.
* gnulib/import/m4/gnulib-cache.m4: Regenerate.
* gnulib/import/m4/gnulib-comp.m4: Likewise.
* gnulib/import/m4/mempcpy.m4: New file.
* gnulib/import/m4/opendir.m4: Likewise.
* gnulib/import/m4/readdir.m4: Likewise.
* gnulib/import/mempcpy.c: Likewise.
* gnulib/import/opendir.c: Likewise.
* gnulib/import/readdir.c: Likewise.
* gnulib/update-gnulib.sh (IMPORTED_GNULIB_MODULES): Add glob.
---
gdb/gnulib/aclocal.m4 | 7 +
gdb/gnulib/config.in | 51 +
gdb/gnulib/configure | 523 +++++++++-
gdb/gnulib/import/Makefile.am | 83 +-
gdb/gnulib/import/Makefile.in | 93 +-
gdb/gnulib/import/closedir.c | 71 ++
gdb/gnulib/import/dirent-private.h | 40 +
gdb/gnulib/import/filename.h | 54 +
gdb/gnulib/import/getlogin_r.c | 87 ++
gdb/gnulib/import/glob-libc.h | 212 ++++
gdb/gnulib/import/glob.c | 1808 ++++++++++++++++++++++++++++++++++
gdb/gnulib/import/glob.in.h | 93 ++
gdb/gnulib/import/m4/closedir.m4 | 30 +
gdb/gnulib/import/m4/d-type.m4 | 32 +
gdb/gnulib/import/m4/getlogin_r.m4 | 88 ++
gdb/gnulib/import/m4/glob.m4 | 76 ++
gdb/gnulib/import/m4/gnulib-cache.m4 | 3 +-
gdb/gnulib/import/m4/gnulib-comp.m4 | 58 ++
gdb/gnulib/import/m4/mempcpy.m4 | 26 +
gdb/gnulib/import/m4/opendir.m4 | 31 +
gdb/gnulib/import/m4/readdir.m4 | 15 +
gdb/gnulib/import/mempcpy.c | 28 +
gdb/gnulib/import/opendir.c | 169 ++++
gdb/gnulib/import/readdir.c | 98 ++
gdb/gnulib/update-gnulib.sh | 1 +
25 files changed, 3743 insertions(+), 34 deletions(-)
create mode 100644 gdb/gnulib/import/closedir.c
create mode 100644 gdb/gnulib/import/dirent-private.h
create mode 100644 gdb/gnulib/import/filename.h
create mode 100644 gdb/gnulib/import/getlogin_r.c
create mode 100644 gdb/gnulib/import/glob-libc.h
create mode 100644 gdb/gnulib/import/glob.c
create mode 100644 gdb/gnulib/import/glob.in.h
create mode 100644 gdb/gnulib/import/m4/closedir.m4
create mode 100644 gdb/gnulib/import/m4/d-type.m4
create mode 100644 gdb/gnulib/import/m4/getlogin_r.m4
create mode 100644 gdb/gnulib/import/m4/glob.m4
create mode 100644 gdb/gnulib/import/m4/mempcpy.m4
create mode 100644 gdb/gnulib/import/m4/opendir.m4
create mode 100644 gdb/gnulib/import/m4/readdir.m4
create mode 100644 gdb/gnulib/import/mempcpy.c
create mode 100644 gdb/gnulib/import/opendir.c
create mode 100644 gdb/gnulib/import/readdir.c

diff --git a/gdb/gnulib/aclocal.m4 b/gdb/gnulib/aclocal.m4
index a4ce6a6b47..e9e0be9d71 100644
--- a/gdb/gnulib/aclocal.m4
+++ b/gdb/gnulib/aclocal.m4
@@ -1016,8 +1016,10 @@ m4_include([import/m4/00gnulib.m4])
m4_include([import/m4/absolute-header.m4])
m4_include([import/m4/alloca.m4])
m4_include([import/m4/canonicalize.m4])
+m4_include([import/m4/closedir.m4])
m4_include([import/m4/codeset.m4])
m4_include([import/m4/configmake.m4])
+m4_include([import/m4/d-type.m4])
m4_include([import/m4/dirent_h.m4])
m4_include([import/m4/dirfd.m4])
m4_include([import/m4/dirname.m4])
@@ -1036,8 +1038,10 @@ m4_include([import/m4/fnmatch.m4])
m4_include([import/m4/fpieee.m4])
m4_include([import/m4/frexp.m4])
m4_include([import/m4/frexpl.m4])
+m4_include([import/m4/getlogin_r.m4])
m4_include([import/m4/gettimeofday.m4])
m4_include([import/m4/glibc21.m4])
+m4_include([import/m4/glob.m4])
m4_include([import/m4/gnulib-common.m4])
m4_include([import/m4/gnulib-comp.m4])
m4_include([import/m4/hard-locale.m4])
@@ -1063,12 +1067,15 @@ m4_include([import/m4/mbsrtowcs.m4])
m4_include([import/m4/mbstate_t.m4])
m4_include([import/m4/memchr.m4])
m4_include([import/m4/memmem.m4])
+m4_include([import/m4/mempcpy.m4])
m4_include([import/m4/mmap-anon.m4])
m4_include([import/m4/multiarch.m4])
m4_include([import/m4/nocrash.m4])
m4_include([import/m4/off_t.m4])
+m4_include([import/m4/opendir.m4])
m4_include([import/m4/pathmax.m4])
m4_include([import/m4/rawmemchr.m4])
+m4_include([import/m4/readdir.m4])
m4_include([import/m4/readlink.m4])
m4_include([import/m4/rename.m4])
m4_include([import/m4/rmdir.m4])
diff --git a/gdb/gnulib/config.in b/gdb/gnulib/config.in
index 6061520f0a..b78df1a46f 100644
--- a/gdb/gnulib/config.in
+++ b/gdb/gnulib/config.in
@@ -92,6 +92,9 @@
/* Define to 1 when the gnulib module chdir should be tested. */
#undef GNULIB_TEST_CHDIR

+/* Define to 1 when the gnulib module closedir should be tested. */
+#undef GNULIB_TEST_CLOSEDIR
+
/* Define to 1 when the gnulib module dirfd should be tested. */
#undef GNULIB_TEST_DIRFD

@@ -104,6 +107,9 @@
/* Define to 1 when the gnulib module frexpl should be tested. */
#undef GNULIB_TEST_FREXPL

+/* Define to 1 when the gnulib module getlogin_r should be tested. */
+#undef GNULIB_TEST_GETLOGIN_R
+
/* Define to 1 when the gnulib module gettimeofday should be tested. */
#undef GNULIB_TEST_GETTIMEOFDAY

@@ -128,9 +134,18 @@
/* Define to 1 when the gnulib module memmem should be tested. */
#undef GNULIB_TEST_MEMMEM

+/* Define to 1 when the gnulib module mempcpy should be tested. */
+#undef GNULIB_TEST_MEMPCPY
+
+/* Define to 1 when the gnulib module opendir should be tested. */
+#undef GNULIB_TEST_OPENDIR
+
/* Define to 1 when the gnulib module rawmemchr should be tested. */
#undef GNULIB_TEST_RAWMEMCHR

+/* Define to 1 when the gnulib module readdir should be tested. */
+#undef GNULIB_TEST_READDIR
+
/* Define to 1 when the gnulib module readlink should be tested. */
#undef GNULIB_TEST_READLINK

@@ -178,6 +193,9 @@
/* Define to 1 if you have the `canonicalize_file_name' function. */
#undef HAVE_CANONICALIZE_FILE_NAME

+/* Define to 1 if you have the `closedir' function. */
+#undef HAVE_CLOSEDIR
+
/* Define to 1 if you have the declaration of `alarm', and to 0 if you don't.
*/
#undef HAVE_DECL_ALARM
@@ -190,6 +208,14 @@
don't. */
#undef HAVE_DECL_GETC_UNLOCKED

+/* Define to 1 if you have the declaration of `getlogin', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN
+
+/* Define to 1 if you have the declaration of `getlogin_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN_R
+
/* Define to 1 if you have the declaration of `isblank', and to 0 if you
don't. */
#undef HAVE_DECL_ISBLANK
@@ -244,12 +270,24 @@
/* Define if the frexpl() function is available. */
#undef HAVE_FREXPL

+/* Define to 1 if you have the `fstatat' function. */
+#undef HAVE_FSTATAT
+
/* Define to 1 if you have the `getcwd' function. */
#undef HAVE_GETCWD

+/* Define to 1 if you have the `getlogin_r' function. */
+#undef HAVE_GETLOGIN_R
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY

+/* Define to 1 if you have the <glob.h> header file. */
+#undef HAVE_GLOB_H
+
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H

@@ -317,6 +355,9 @@
/* Define to 1 if you have the `mprotect' function. */
#undef HAVE_MPROTECT

+/* Define to 1 if you have the `opendir' function. */
+#undef HAVE_OPENDIR
+
/* Define to 1 if you have the `rawmemchr' function. */
#undef HAVE_RAWMEMCHR

@@ -1137,6 +1178,9 @@
/* Define to 1 if _Exit is declared even after undefining macros. */
#undef HAVE_RAW_DECL__EXIT

+/* Define to 1 if you have the `readdir' function. */
+#undef HAVE_READDIR
+
/* Define to 1 if you have the `readlink' function. */
#undef HAVE_READLINK

@@ -1182,12 +1226,19 @@
/* Define to 1 if you have the `strtok_r' function. */
#undef HAVE_STRTOK_R

+/* Define if there is a member named d_type in the struct describing directory
+ headers. */
+#undef HAVE_STRUCT_DIRENT_D_TYPE
+
/* Define to 1 if you have the `symlink' function. */
#undef HAVE_SYMLINK

/* Define to 1 if you have the <sys/bitypes.h> header file. */
#undef HAVE_SYS_BITYPES_H

+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
/* Define to 1 if you have the <sys/inttypes.h> header file. */
#undef HAVE_SYS_INTTYPES_H

diff --git a/gdb/gnulib/configure b/gdb/gnulib/configure
index 2a0dfc2d66..7d72e22bbd 100644
--- a/gdb/gnulib/configure
+++ b/gdb/gnulib/configure
@@ -1078,6 +1078,10 @@ GL_GENERATE_LIMITS_H_TRUE
LIMITS_H
NEXT_AS_FIRST_DIRECTIVE_LIMITS_H
NEXT_LIMITS_H
+HAVE_SYS_CDEFS_H
+GL_GENERATE_GLOB_H_FALSE
+GL_GENERATE_GLOB_H_TRUE
+GLOB_H
HAVE_WINSOCK2_H
NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H
NEXT_SYS_TIME_H
@@ -1372,6 +1376,9 @@ PRAGMA_COLUMNS
PRAGMA_SYSTEM_HEADER
INCLUDE_NEXT_AS_FIRST_DIRECTIVE
INCLUDE_NEXT
+pkglibexecdir
+runstatedir
+lispdir
REPLACE_FDOPENDIR
REPLACE_DIRFD
REPLACE_CLOSEDIR
@@ -1393,9 +1400,6 @@ GNULIB_CLOSEDIR
GNULIB_REWINDDIR
GNULIB_READDIR
GNULIB_OPENDIR
-pkglibexecdir
-runstatedir
-lispdir
UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS
UNISTD_H_HAVE_WINSOCK2_H
REPLACE_WRITE
@@ -3318,9 +3322,13 @@ as_fn_append ac_func_list " wmemcpy"
as_fn_append ac_func_list " wmempcpy"
as_fn_append ac_header_list " wctype.h"
gl_fnmatch_required=GNU
+as_fn_append ac_func_list " getlogin_r"
as_fn_append ac_header_list " sys/time.h"
as_fn_append ac_header_list " sys/socket.h"
as_fn_append ac_func_list " gettimeofday"
+as_fn_append ac_header_list " sys/cdefs.h"
+as_fn_append ac_func_list " fstatat"
+as_fn_append ac_func_list " getpwnam_r"
as_fn_append ac_header_list " limits.h"
as_fn_append ac_header_list " wchar.h"
as_fn_append ac_header_list " stdint.h"
@@ -5306,7 +5314,9 @@ fi
# Code from module alloca-opt:
# Code from module canonicalize-lgpl:
# Code from module chdir:
+ # Code from module closedir:
# Code from module configmake:
+ # Code from module d-type:
# Code from module dirent:
# Code from module dirfd:
# Code from module dirname-lgpl:
@@ -5316,6 +5326,7 @@ fi
# Code from module errno:
# Code from module extensions:
# Code from module extern-inline:
+ # Code from module filename:
# Code from module flexmember:
# Code from module float:
# Code from module fnmatch:
@@ -5325,7 +5336,9 @@ fi
# Code from module fpucw:
# Code from module frexp:
# Code from module frexpl:
+ # Code from module getlogin_r:
# Code from module gettimeofday:
+ # Code from module glob:
# Code from module hard-locale:
# Code from module include_next:
# Code from module inttypes:
@@ -5346,10 +5359,13 @@ fi
# Code from module memchr:
# Code from module memmem:
# Code from module memmem-simple:
+ # Code from module mempcpy:
# Code from module multiarch:
# Code from module nocrash:
+ # Code from module opendir:
# Code from module pathmax:
# Code from module rawmemchr:
+ # Code from module readdir:
# Code from module readlink:
# Code from module rename:
# Code from module rmdir:
@@ -7663,6 +7679,30 @@ $as_echo "#define HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 1" >>confdefs.h
fi


+ac_fn_c_check_decl "$LINENO" "getlogin_r" "ac_cv_have_decl_getlogin_r" "$ac_includes_default"
+if test "x$ac_cv_have_decl_getlogin_r" = x""yes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLOGIN_R $ac_have_decl
+_ACEOF
+
+
+
+ac_fn_c_check_decl "$LINENO" "getlogin" "ac_cv_have_decl_getlogin" "$ac_includes_default"
+if test "x$ac_cv_have_decl_getlogin" = x""yes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLOGIN $ac_have_decl
+_ACEOF
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
$as_echo_n "checking for C/C++ restrict keyword... " >&6; }
if test "${ac_cv_c_restrict+set}" = set; then :
@@ -7979,6 +8019,12 @@ fi



+
+
+
+
+
+
if test $gl_cv_have_include_next = yes; then
gl_cv_next_limits_h='<'limits.h'>'
else
@@ -12669,6 +12715,56 @@ $as_echo "#define GNULIB_TEST_CHDIR 1" >>confdefs.h



+
+
+ for ac_func in closedir
+do :
+ ac_fn_c_check_func "$LINENO" "closedir" "ac_cv_func_closedir"
+if test "x$ac_cv_func_closedir" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_CLOSEDIR 1
+_ACEOF
+
+fi
+done
+
+ if test $ac_cv_func_closedir = no; then
+ HAVE_CLOSEDIR=0
+ fi
+
+ case $host_os,$HAVE_CLOSEDIR in
+ os2*,1)
+ REPLACE_CLOSEDIR=1;;
+ esac
+
+ if test $HAVE_CLOSEDIR = 0 || test $REPLACE_CLOSEDIR = 1; then
+
+
+
+
+
+
+
+
+ gl_LIBOBJS="$gl_LIBOBJS closedir.$ac_objext"
+
+ fi
+
+
+
+
+
+ GNULIB_CLOSEDIR=1
+
+
+
+
+
+$as_echo "#define GNULIB_TEST_CLOSEDIR 1" >>confdefs.h
+
+
+
+
if test "x$datarootdir" = x; then
datarootdir='${datadir}'

@@ -12709,6 +12805,44 @@ $as_echo "#define GNULIB_TEST_CHDIR 1" >>confdefs.h
pkglibexecdir='${libexecdir}/${PACKAGE}'


+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for d_type member in directory struct" >&5
+$as_echo_n "checking for d_type member in directory struct... " >&6; }
+if test "${gl_cv_struct_dirent_d_type+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <dirent.h>
+
+int
+main ()
+{
+struct dirent dp; dp.d_type = 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_struct_dirent_d_type=yes
+else
+ gl_cv_struct_dirent_d_type=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_struct_dirent_d_type" >&5
+$as_echo "$gl_cv_struct_dirent_d_type" >&6; }
+ if test $gl_cv_struct_dirent_d_type = yes; then
+
+$as_echo "#define HAVE_STRUCT_DIRENT_D_TYPE 1" >>confdefs.h
+
+ fi
+
+



@@ -13982,6 +14116,114 @@ $as_echo "#define GNULIB_TEST_FREXPL 1" >>confdefs.h



+ if test $ac_cv_have_decl_getlogin_r = no; then
+ HAVE_DECL_GETLOGIN_R=0
+ fi
+
+
+ if test $ac_cv_func_getlogin_r = no; then
+ HAVE_GETLOGIN_R=0
+ else
+ HAVE_GETLOGIN_R=1
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getlogin_r works with small buffers" >&5
+$as_echo_n "checking whether getlogin_r works with small buffers... " >&6; }
+if test "${gl_cv_func_getlogin_r_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ case "$host_os" in
+ # Guess no on OSF/1.
+ osf*) gl_cv_func_getlogin_r_works="guessing no" ;;
+ # Guess yes otherwise.
+ *) gl_cv_func_getlogin_r_works="guessing yes" ;;
+ esac
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stddef.h>
+#include <unistd.h>
+#if !HAVE_DECL_GETLOGIN_R
+extern
+# ifdef __cplusplus
+"C"
+# endif
+int getlogin_r (char *, size_t);
+#endif
+int
+main (void)
+{
+ int result = 0;
+ char buf[100];
+
+ if (getlogin_r (buf, 0) == 0)
+ result |= 16;
+ if (getlogin_r (buf, 1) == 0)
+ result |= 17;
+ return result;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ gl_cv_func_getlogin_r_works=yes
+else
+ case $? in
+ 16 | 17) gl_cv_func_getlogin_r_works=no ;;
+ esac
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getlogin_r_works" >&5
+$as_echo "$gl_cv_func_getlogin_r_works" >&6; }
+ case "$gl_cv_func_getlogin_r_works" in
+ *yes) ;;
+ *) REPLACE_GETLOGIN_R=1 ;;
+ esac
+ fi
+
+ if test $HAVE_GETLOGIN_R = 0 || test $REPLACE_GETLOGIN_R = 1; then
+
+
+
+
+
+
+
+
+ gl_LIBOBJS="$gl_LIBOBJS getlogin_r.$ac_objext"
+
+
+
+
+ fi
+
+
+
+
+
+ GNULIB_GETLOGIN_R=1
+
+
+
+
+
+$as_echo "#define GNULIB_TEST_GETLOGIN_R 1" >>confdefs.h
+
+
+
+
+
+
+
+
+
gl_gettimeofday_timezone=void
if test $ac_cv_func_gettimeofday != yes; then
HAVE_GETTIMEOFDAY=0
@@ -14177,6 +14419,131 @@ $as_echo "#define GNULIB_TEST_GETTIMEOFDAY 1" >>confdefs.h



+ GLOB_H=
+ for ac_header in glob.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "glob.h" "ac_cv_header_glob_h" "$ac_includes_default"
+if test "x$ac_cv_header_glob_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GLOB_H 1
+_ACEOF
+
+else
+ GLOB_H=glob.h
+fi
+
+done
+
+
+ if test -z "$GLOB_H"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU glob interface version 1" >&5
+$as_echo_n "checking for GNU glob interface version 1... " >&6; }
+if test "${gl_cv_gnu_glob_interface_version_1+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <gnu-versions.h>
+char a[_GNU_GLOB_INTERFACE_VERSION == 1 ? 1 : -1];
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ gl_cv_gnu_glob_interface_version_1=yes
+else
+ gl_cv_gnu_glob_interface_version_1=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_gnu_glob_interface_version_1" >&5
+$as_echo "$gl_cv_gnu_glob_interface_version_1" >&6; }
+
+ if test "$gl_cv_gnu_glob_interface_version_1" = "no"; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ if test -z "$GLOB_H"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether glob lists broken symlinks" >&5
+$as_echo_n "checking whether glob lists broken symlinks... " >&6; }
+if test "${gl_cv_glob_lists_symlinks+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ln -s conf-doesntexist conf$$-globtest 2>/dev/null; then
+ gl_cv_glob_lists_symlinks=maybe
+ else
+ # If we can't make a symlink, then we cannot test this issue. Be
+ # pessimistic about this.
+ gl_cv_glob_lists_symlinks=no
+ fi
+
+ if test $gl_cv_glob_lists_symlinks = maybe; then
+ if test "$cross_compiling" = yes; then :
+ gl_cv_glob_lists_symlinks=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stddef.h>
+#include <glob.h>
+int
+main ()
+{
+glob_t found;
+if (glob ("conf*-globtest", 0, NULL, &found) == GLOB_NOMATCH) return 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ gl_cv_glob_lists_symlinks=yes
+else
+ gl_cv_glob_lists_symlinks=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_glob_lists_symlinks" >&5
+$as_echo "$gl_cv_glob_lists_symlinks" >&6; }
+
+ if test $gl_cv_glob_lists_symlinks = no; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ rm -f conf$$-globtest
+
+
+ if test -n "$GLOB_H"; then
+ GL_GENERATE_GLOB_H_TRUE=
+ GL_GENERATE_GLOB_H_FALSE='#'
+else
+ GL_GENERATE_GLOB_H_TRUE='#'
+ GL_GENERATE_GLOB_H_FALSE=
+fi
+
+
+ if test -n "$GLOB_H"; then
+
+
+
+
+
+
+
+
+ gl_LIBOBJS="$gl_LIBOBJS glob.$ac_objext"
+
+
+ if test $ac_cv_header_sys_cdefs_h = yes; then
+ HAVE_SYS_CDEFS_H=1
+ else
+ HAVE_SYS_CDEFS_H=0
+ fi
+
+
+ fi

:

@@ -16665,6 +17032,107 @@ $as_echo "#define GNULIB_TEST_MEMMEM 1" >>confdefs.h



+ for ac_func in mempcpy
+do :
+ ac_fn_c_check_func "$LINENO" "mempcpy" "ac_cv_func_mempcpy"
+if test "x$ac_cv_func_mempcpy" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_MEMPCPY 1
+_ACEOF
+
+fi
+done
+
+ if test $ac_cv_func_mempcpy = no; then
+ HAVE_MEMPCPY=0
+ fi
+
+ if test $HAVE_MEMPCPY = 0; then
+
+
+
+
+
+
+
+
+ gl_LIBOBJS="$gl_LIBOBJS mempcpy.$ac_objext"
+
+
+ :
+
+ fi
+
+
+
+
+
+ GNULIB_MEMPCPY=1
+
+
+
+
+
+$as_echo "#define GNULIB_TEST_MEMPCPY 1" >>confdefs.h
+
+
+
+
+
+
+
+ for ac_func in opendir
+do :
+ ac_fn_c_check_func "$LINENO" "opendir" "ac_cv_func_opendir"
+if test "x$ac_cv_func_opendir" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_OPENDIR 1
+_ACEOF
+
+fi
+done
+
+ if test $ac_cv_func_opendir = no; then
+ HAVE_OPENDIR=0
+ fi
+
+ case $host_os,$HAVE_OPENDIR in
+ os2*,1)
+ REPLACE_OPENDIR=1;;
+ esac
+
+ if test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1; then
+
+
+
+
+
+
+
+
+ gl_LIBOBJS="$gl_LIBOBJS opendir.$ac_objext"
+
+ fi
+
+
+
+
+
+ GNULIB_OPENDIR=1
+
+
+
+
+
+$as_echo "#define GNULIB_TEST_OPENDIR 1" >>confdefs.h
+
+
+
+
+
+
+
+


for ac_func in rawmemchr
@@ -16713,6 +17181,51 @@ $as_echo "#define GNULIB_TEST_RAWMEMCHR 1" >>confdefs.h



+ for ac_func in readdir
+do :
+ ac_fn_c_check_func "$LINENO" "readdir" "ac_cv_func_readdir"
+if test "x$ac_cv_func_readdir" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_READDIR 1
+_ACEOF
+
+fi
+done
+
+ if test $ac_cv_func_readdir = no; then
+ HAVE_READDIR=0
+ fi
+
+ if test $HAVE_READDIR = 0; then
+
+
+
+
+
+
+
+
+ gl_LIBOBJS="$gl_LIBOBJS readdir.$ac_objext"
+
+ fi
+
+
+
+
+
+ GNULIB_READDIR=1
+
+
+
+
+
+$as_echo "#define GNULIB_TEST_READDIR 1" >>confdefs.h
+
+
+
+
+
+
if test $ac_cv_func_readlink = no; then
HAVE_READLINK=0
else
@@ -20526,6 +21039,10 @@ if test -z "${GL_GENERATE_FNMATCH_H_TRUE}" && test -z "${GL_GENERATE_FNMATCH_H_F
as_fn_error "conditional \"GL_GENERATE_FNMATCH_H\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${GL_GENERATE_GLOB_H_TRUE}" && test -z "${GL_GENERATE_GLOB_H_FALSE}"; then
+ as_fn_error "conditional \"GL_GENERATE_GLOB_H\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${GL_GENERATE_LIMITS_H_TRUE}" && test -z "${GL_GENERATE_LIMITS_H_FALSE}"; then
as_fn_error "conditional \"GL_GENERATE_LIMITS_H\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/gdb/gnulib/import/Makefile.am b/gdb/gnulib/import/Makefile.am
index 26f249d16a..defa7b34ca 100644
--- a/gdb/gnulib/import/Makefile.am
+++ b/gdb/gnulib/import/Makefile.am
@@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl inttypes limits-h lstat memchr memmem pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h
+# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl glob inttypes limits-h lstat memchr memmem pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h

AUTOMAKE_OPTIONS = 1.9.6 gnits

@@ -101,6 +101,15 @@ EXTRA_libgnu_a_SOURCES += canonicalize-lgpl.c

## end gnulib module canonicalize-lgpl

+## begin gnulib module closedir
+
+
+EXTRA_DIST += closedir.c dirent-private.h
+
+EXTRA_libgnu_a_SOURCES += closedir.c
+
+## end gnulib module closedir
+
## begin gnulib module configmake

# Listed in the same order as the GNU makefile conventions, and
@@ -252,6 +261,13 @@ EXTRA_DIST += errno.in.h

## end gnulib module errno

+## begin gnulib module filename
+
+
+EXTRA_DIST += filename.h
+
+## end gnulib module filename
+
## begin gnulib module flexmember


@@ -341,6 +357,15 @@ EXTRA_libgnu_a_SOURCES += frexp.c frexpl.c

## end gnulib module frexpl

+## begin gnulib module getlogin_r
+
+
+EXTRA_DIST += getlogin_r.c
+
+EXTRA_libgnu_a_SOURCES += getlogin_r.c
+
+## end gnulib module getlogin_r
+
## begin gnulib module gettimeofday


@@ -350,6 +375,35 @@ EXTRA_libgnu_a_SOURCES += gettimeofday.c

## end gnulib module gettimeofday

+## begin gnulib module glob
+
+BUILT_SOURCES += $(GLOB_H)
+
+# We need the following in order to create <glob.h> when the system
+# doesn't have one that works with the given compiler.
+if GL_GENERATE_GLOB_H
+glob.h: glob.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
+ $(AM_V_GEN)rm -f $@-t $@ && \
+ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+ sed -e 's|@''HAVE_SYS_CDEFS_H''@|$(HAVE_SYS_CDEFS_H)|g' \
+ -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
+ -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
+ -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
+ < $(srcdir)/glob.in.h; \
+ } > $@-t && \
+ mv -f $@-t $@
+else
+glob.h: $(top_builddir)/config.status
+ rm -f $@
+endif
+MOSTLYCLEANFILES += glob.h glob.h-t
+
+EXTRA_DIST += glob-libc.h glob.c glob.in.h
+
+EXTRA_libgnu_a_SOURCES += glob.c
+
+## end gnulib module glob
+
## begin gnulib module hard-locale

libgnu_a_SOURCES += hard-locale.c
@@ -878,6 +932,24 @@ EXTRA_libgnu_a_SOURCES += memmem.c

## end gnulib module memmem-simple

+## begin gnulib module mempcpy
+
+
+EXTRA_DIST += mempcpy.c
+
+EXTRA_libgnu_a_SOURCES += mempcpy.c
+
+## end gnulib module mempcpy
+
+## begin gnulib module opendir
+
+
+EXTRA_DIST += dirent-private.h opendir.c
+
+EXTRA_libgnu_a_SOURCES += opendir.c
+
+## end gnulib module opendir
+
## begin gnulib module pathmax


@@ -894,6 +966,15 @@ EXTRA_libgnu_a_SOURCES += rawmemchr.c

## end gnulib module rawmemchr

+## begin gnulib module readdir
+
+
+EXTRA_DIST += dirent-private.h readdir.c
+
+EXTRA_libgnu_a_SOURCES += readdir.c
+
+## end gnulib module readdir
+
## begin gnulib module readlink


diff --git a/gdb/gnulib/import/Makefile.in b/gdb/gnulib/import/Makefile.in
index ca7a73d970..d02fcfb9f9 100644
--- a/gdb/gnulib/import/Makefile.in
+++ b/gdb/gnulib/import/Makefile.in
@@ -36,7 +36,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl inttypes limits-h lstat memchr memmem pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h
+# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl glob inttypes limits-h lstat memchr memmem pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h



@@ -67,8 +67,10 @@ am__aclocal_m4_deps = $(top_srcdir)/import/m4/00gnulib.m4 \
$(top_srcdir)/import/m4/absolute-header.m4 \
$(top_srcdir)/import/m4/alloca.m4 \
$(top_srcdir)/import/m4/canonicalize.m4 \
+ $(top_srcdir)/import/m4/closedir.m4 \
$(top_srcdir)/import/m4/codeset.m4 \
$(top_srcdir)/import/m4/configmake.m4 \
+ $(top_srcdir)/import/m4/d-type.m4 \
$(top_srcdir)/import/m4/dirent_h.m4 \
$(top_srcdir)/import/m4/dirfd.m4 \
$(top_srcdir)/import/m4/dirname.m4 \
@@ -87,8 +89,10 @@ am__aclocal_m4_deps = $(top_srcdir)/import/m4/00gnulib.m4 \
$(top_srcdir)/import/m4/fpieee.m4 \
$(top_srcdir)/import/m4/frexp.m4 \
$(top_srcdir)/import/m4/frexpl.m4 \
+ $(top_srcdir)/import/m4/getlogin_r.m4 \
$(top_srcdir)/import/m4/gettimeofday.m4 \
$(top_srcdir)/import/m4/glibc21.m4 \
+ $(top_srcdir)/import/m4/glob.m4 \
$(top_srcdir)/import/m4/gnulib-common.m4 \
$(top_srcdir)/import/m4/gnulib-comp.m4 \
$(top_srcdir)/import/m4/hard-locale.m4 \
@@ -114,12 +118,15 @@ am__aclocal_m4_deps = $(top_srcdir)/import/m4/00gnulib.m4 \
$(top_srcdir)/import/m4/mbstate_t.m4 \
$(top_srcdir)/import/m4/memchr.m4 \
$(top_srcdir)/import/m4/memmem.m4 \
+ $(top_srcdir)/import/m4/mempcpy.m4 \
$(top_srcdir)/import/m4/mmap-anon.m4 \
$(top_srcdir)/import/m4/multiarch.m4 \
$(top_srcdir)/import/m4/nocrash.m4 \
$(top_srcdir)/import/m4/off_t.m4 \
+ $(top_srcdir)/import/m4/opendir.m4 \
$(top_srcdir)/import/m4/pathmax.m4 \
$(top_srcdir)/import/m4/rawmemchr.m4 \
+ $(top_srcdir)/import/m4/readdir.m4 \
$(top_srcdir)/import/m4/readlink.m4 \
$(top_srcdir)/import/m4/rename.m4 \
$(top_srcdir)/import/m4/rmdir.m4 \
@@ -256,6 +263,7 @@ FNMATCH_H = @FNMATCH_H@
FREXPL_LIBM = @FREXPL_LIBM@
FREXP_LIBM = @FREXP_LIBM@
GLIBC21 = @GLIBC21@
+GLOB_H = @GLOB_H@
GNULIB_ACOSF = @GNULIB_ACOSF@
GNULIB_ACOSL = @GNULIB_ACOSL@
GNULIB_ALPHASORT = @GNULIB_ALPHASORT@
@@ -856,6 +864,7 @@ HAVE_STRVERSCMP = @HAVE_STRVERSCMP@
HAVE_SYMLINK = @HAVE_SYMLINK@
HAVE_SYMLINKAT = @HAVE_SYMLINKAT@
HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@
HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@
HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@
@@ -1281,17 +1290,20 @@ noinst_HEADERS =
noinst_LIBRARIES = libgnu.a
noinst_LTLIBRARIES =
EXTRA_DIST = m4/gnulib-cache.m4 alloca.c alloca.in.h \
- canonicalize-lgpl.c dirent.in.h dirfd.c dirname.h dosname.h \
- errno.in.h flexmember.h float.c float.in.h itold.c fnmatch.c \
- fnmatch.in.h fnmatch_loop.c fpucw.h frexp.c frexp.c frexpl.c \
- gettimeofday.c hard-locale.h inttypes.in.h float+.h isnan.c \
- isnand-nolibm.h isnand.c float+.h isnan.c isnanl-nolibm.h \
- isnanl.c limits.in.h config.charset ref-add.sin ref-del.sin \
- lstat.c malloc.c malloca.h malloca.valgrind math.in.h \
- mbrtowc.c mbsinit.c mbsrtowcs-impl.h mbsrtowcs-state.c \
- mbsrtowcs.c memchr.c memchr.valgrind memmem.c str-two-way.h \
- pathmax.h rawmemchr.c rawmemchr.valgrind readlink.c rename.c \
- rmdir.c same-inode.h setenv.c signal.in.h \
+ canonicalize-lgpl.c closedir.c dirent-private.h dirent.in.h \
+ dirfd.c dirname.h dosname.h errno.in.h filename.h flexmember.h \
+ float.c float.in.h itold.c fnmatch.c fnmatch.in.h \
+ fnmatch_loop.c fpucw.h frexp.c frexp.c frexpl.c getlogin_r.c \
+ gettimeofday.c glob-libc.h glob.c glob.in.h hard-locale.h \
+ inttypes.in.h float+.h isnan.c isnand-nolibm.h isnand.c \
+ float+.h isnan.c isnanl-nolibm.h isnanl.c limits.in.h \
+ config.charset ref-add.sin ref-del.sin lstat.c malloc.c \
+ malloca.h malloca.valgrind math.in.h mbrtowc.c mbsinit.c \
+ mbsrtowcs-impl.h mbsrtowcs-state.c mbsrtowcs.c memchr.c \
+ memchr.valgrind memmem.c str-two-way.h mempcpy.c \
+ dirent-private.h opendir.c pathmax.h rawmemchr.c \
+ rawmemchr.valgrind dirent-private.h readdir.c readlink.c \
+ rename.c rmdir.c same-inode.h setenv.c signal.in.h \
$(top_srcdir)/import/extra/snippet/_Noreturn.h \
$(top_srcdir)/import/extra/snippet/arg-nonnull.h \
$(top_srcdir)/import/extra/snippet/c++defs.h \
@@ -1313,21 +1325,22 @@ EXTRA_DIST = m4/gnulib-cache.m4 alloca.c alloca.in.h \
# present in all Makefile.am that need it. This is ensured by the applicability
# 'all' defined above.
BUILT_SOURCES = $(ALLOCA_H) configmake.h dirent.h $(ERRNO_H) \
- $(FLOAT_H) $(FNMATCH_H) inttypes.h $(LIMITS_H) math.h signal.h \
- arg-nonnull.h c++defs.h warn-on-use.h $(STDBOOL_H) $(STDDEF_H) \
- $(STDINT_H) stdio.h stdlib.h string.h sys/stat.h sys/time.h \
- sys/types.h time.h unistd.h wchar.h wctype.h
+ $(FLOAT_H) $(FNMATCH_H) $(GLOB_H) inttypes.h $(LIMITS_H) \
+ math.h signal.h arg-nonnull.h c++defs.h warn-on-use.h \
+ $(STDBOOL_H) $(STDDEF_H) $(STDINT_H) stdio.h stdlib.h string.h \
+ sys/stat.h sys/time.h sys/types.h time.h unistd.h wchar.h \
+ wctype.h
SUFFIXES = .sed .sin
MOSTLYCLEANFILES = core *.stackdump alloca.h alloca.h-t dirent.h \
dirent.h-t errno.h errno.h-t float.h float.h-t fnmatch.h \
- fnmatch.h-t inttypes.h inttypes.h-t limits.h limits.h-t math.h \
- math.h-t signal.h signal.h-t arg-nonnull.h arg-nonnull.h-t \
- c++defs.h c++defs.h-t warn-on-use.h warn-on-use.h-t stdbool.h \
- stdbool.h-t stddef.h stddef.h-t stdint.h stdint.h-t stdio.h \
- stdio.h-t stdlib.h stdlib.h-t string.h string.h-t sys/stat.h \
- sys/stat.h-t sys/time.h sys/time.h-t sys/types.h sys/types.h-t \
- time.h time.h-t unistd.h unistd.h-t wchar.h wchar.h-t wctype.h \
- wctype.h-t
+ fnmatch.h-t glob.h glob.h-t inttypes.h inttypes.h-t limits.h \
+ limits.h-t math.h math.h-t signal.h signal.h-t arg-nonnull.h \
+ arg-nonnull.h-t c++defs.h c++defs.h-t warn-on-use.h \
+ warn-on-use.h-t stdbool.h stdbool.h-t stddef.h stddef.h-t \
+ stdint.h stdint.h-t stdio.h stdio.h-t stdlib.h stdlib.h-t \
+ string.h string.h-t sys/stat.h sys/stat.h-t sys/time.h \
+ sys/time.h-t sys/types.h sys/types.h-t time.h time.h-t \
+ unistd.h unistd.h-t wchar.h wchar.h-t wctype.h wctype.h-t
MOSTLYCLEANDIRS = sys
CLEANFILES = configmake.h configmake.h-t charset.alias ref-add.sed \
ref-del.sed
@@ -1340,11 +1353,12 @@ libgnu_a_SOURCES = dirname-lgpl.c basename-lgpl.c stripslash.c \
strnlen1.h strnlen1.c unistd.c wctype-h.c
libgnu_a_LIBADD = $(gl_LIBOBJS) @ALLOCA@
libgnu_a_DEPENDENCIES = $(gl_LIBOBJS) @ALLOCA@
-EXTRA_libgnu_a_SOURCES = alloca.c canonicalize-lgpl.c dirfd.c float.c \
- itold.c fnmatch.c fnmatch_loop.c frexp.c frexp.c frexpl.c \
- gettimeofday.c isnan.c isnand.c isnan.c isnanl.c lstat.c \
- malloc.c mbrtowc.c mbsinit.c mbsrtowcs-state.c mbsrtowcs.c \
- memchr.c memmem.c rawmemchr.c readlink.c rename.c rmdir.c \
+EXTRA_libgnu_a_SOURCES = alloca.c canonicalize-lgpl.c closedir.c \
+ dirfd.c float.c itold.c fnmatch.c fnmatch_loop.c frexp.c \
+ frexp.c frexpl.c getlogin_r.c gettimeofday.c glob.c isnan.c \
+ isnand.c isnan.c isnanl.c lstat.c malloc.c mbrtowc.c mbsinit.c \
+ mbsrtowcs-state.c mbsrtowcs.c memchr.c memmem.c mempcpy.c \
+ opendir.c rawmemchr.c readdir.c readlink.c rename.c rmdir.c \
setenv.c stat.c strchrnul.c strstr.c strtok_r.c unsetenv.c

# Use this preprocessor expression to decide whether #include_next works.
@@ -1423,6 +1437,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/basename-***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/canonicalize-***@am__quote@
+@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/dirname-***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@@ -1430,7 +1445,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
+@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
+@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/hard-***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@@ -1447,7 +1464,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
+@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
+@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
+@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@AMDEP_TRUE@@am__include@ @***@./$(DEPDIR)/***@am__quote@
@@ -1936,6 +1956,21 @@ dirent.h: dirent.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
@***@fnmatch.h: $(top_builddir)/config.status
@GL_GENERATE_FNMATCH_H_FALSE@ rm -f $@

+# We need the following in order to create <glob.h> when the system
+# doesn't have one that works with the given compiler.
+@***@glob.h: glob.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
+@GL_GENERATE_GLOB_H_TRUE@ $(AM_V_GEN)rm -f $@-t $@ && \
+@GL_GENERATE_GLOB_H_TRUE@ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+@GL_GENERATE_GLOB_H_TRUE@ sed -e 's|@''HAVE_SYS_CDEFS_H''@|$(HAVE_SYS_CDEFS_H)|g' \
+@GL_GENERATE_GLOB_H_TRUE@ -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
+@GL_GENERATE_GLOB_H_TRUE@ -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
+@GL_GENERATE_GLOB_H_TRUE@ -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
+@GL_GENERATE_GLOB_H_TRUE@ < $(srcdir)/glob.in.h; \
+@GL_GENERATE_GLOB_H_TRUE@ } > $@-t && \
+@GL_GENERATE_GLOB_H_TRUE@ mv -f $@-t $@
+@***@glob.h: $(top_builddir)/config.status
+@GL_GENERATE_GLOB_H_FALSE@ rm -f $@
+
# We need the following in order to create <inttypes.h> when the system
# doesn't have one that works with the given compiler.
inttypes.h: inttypes.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H) $(ARG_NONNULL_H)
diff --git a/gdb/gnulib/import/closedir.c b/gdb/gnulib/import/closedir.c
new file mode 100644
index 0000000000..30d1290351
--- /dev/null
+++ b/gdb/gnulib/import/closedir.c
@@ -0,0 +1,71 @@
+/* Stop reading the entries of a directory.
+ Copyright (C) 2006-2016 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <dirent.h>
+
+#if REPLACE_FCHDIR
+# include <unistd.h>
+#endif
+
+#if HAVE_CLOSEDIR
+
+/* Override closedir(), to keep track of the open file descriptors.
+ Needed because there is a function dirfd(). */
+
+#else
+
+# include <stdlib.h>
+
+# include "dirent-private.h"
+
+#endif
+
+int
+closedir (DIR *dirp)
+{
+# if REPLACE_FCHDIR || REPLACE_DIRFD
+ int fd = dirfd (dirp);
+# endif
+ int retval;
+
+#if HAVE_CLOSEDIR
+# undef closedir
+
+ retval = closedir (dirp);
+
+# ifdef __KLIBC__
+ if (!retval)
+ _gl_unregister_dirp_fd (fd);
+# endif
+#else
+
+ if (dirp->current != INVALID_HANDLE_VALUE)
+ FindClose (dirp->current);
+ free (dirp);
+
+ retval = 0;
+
+#endif
+
+#if REPLACE_FCHDIR
+ if (retval >= 0)
+ _gl_unregister_fd (fd);
+#endif
+ return retval;
+}
diff --git a/gdb/gnulib/import/dirent-private.h b/gdb/gnulib/import/dirent-private.h
new file mode 100644
index 0000000000..9b200f30da
--- /dev/null
+++ b/gdb/gnulib/import/dirent-private.h
@@ -0,0 +1,40 @@
+/* Private details of the DIR type.
+ Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _DIRENT_PRIVATE_H
+#define _DIRENT_PRIVATE_H 1
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+struct gl_directory
+{
+ /* Status, or error code to produce in next readdir() call.
+ -2 means the end of the directory is already reached,
+ -1 means the entry was already filled by FindFirstFile,
+ 0 means the entry needs to be filled using FindNextFile.
+ A positive value is an error code. */
+ int status;
+ /* Handle, reading the directory, at current position. */
+ HANDLE current;
+ /* Found directory entry. */
+ WIN32_FIND_DATA entry;
+ /* Argument to pass to FindFirstFile. It consists of the absolutized
+ directory name, followed by a directory separator and the wildcards. */
+ char dir_name_mask[1];
+};
+
+#endif /* _DIRENT_PRIVATE_H */
diff --git a/gdb/gnulib/import/filename.h b/gdb/gnulib/import/filename.h
new file mode 100644
index 0000000000..7d2c31a8c3
--- /dev/null
+++ b/gdb/gnulib/import/filename.h
@@ -0,0 +1,54 @@
+/* Basic filename support macros.
+ Copyright (C) 2001-2004, 2007-2016 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _FILENAME_H
+#define _FILENAME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Pathname support.
+ ISSLASH(C) tests whether C is a directory separator character.
+ IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
+ it may be concatenated to a directory pathname.
+ IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
+ */
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
+ /* Native Windows, Cygwin, OS/2, DOS */
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+# define HAS_DEVICE(P) \
+ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
+ && (P)[1] == ':')
+# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
+# define IS_PATH_WITH_DIR(P) \
+ (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
+# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
+#else
+ /* Unix */
+# define ISSLASH(C) ((C) == '/')
+# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
+# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
+# define FILE_SYSTEM_PREFIX_LEN(P) 0
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FILENAME_H */
diff --git a/gdb/gnulib/import/getlogin_r.c b/gdb/gnulib/import/getlogin_r.c
new file mode 100644
index 0000000000..2bafb55fb1
--- /dev/null
+++ b/gdb/gnulib/import/getlogin_r.c
@@ -0,0 +1,87 @@
+/* Provide a working getlogin_r for systems which lack it.
+
+ Copyright (C) 2005-2007, 2010-2016 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert, Derek Price, and Bruno Haible. */
+
+#include <config.h>
+
+/* Specification. */
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#else
+# if !HAVE_DECL_GETLOGIN
+extern char *getlogin (void);
+# endif
+#endif
+
+/* See unistd.in.h for documentation. */
+int
+getlogin_r (char *name, size_t size)
+{
+#undef getlogin_r
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* Native Windows platform. */
+ DWORD sz;
+
+ /* When size > 0x7fff, the doc says that GetUserName will fail.
+ Actually, on Windows XP SP3, it succeeds. But let's be safe,
+ for the sake of older Windows versions. */
+ if (size > 0x7fff)
+ size = 0x7fff;
+ sz = size;
+ if (!GetUserName (name, &sz))
+ {
+ if (GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+ /* In this case, the doc says that sz contains the required size, but
+ actually, on Windows XP SP3, it contains 2 * the required size. */
+ return ERANGE;
+ else
+ return ENOENT;
+ }
+ return 0;
+#elif HAVE_GETLOGIN_R
+ /* Platform with a getlogin_r() function. */
+ int ret = getlogin_r (name, size);
+
+ if (ret == 0 && memchr (name, '\0', size) == NULL)
+ /* name contains a truncated result. */
+ return ERANGE;
+ return ret;
+#else
+ /* Platform with a getlogin() function. */
+ char *n;
+ size_t nlen;
+
+ errno = 0;
+ n = getlogin ();
+ if (!n)
+ /* ENOENT is a reasonable errno value if getlogin returns NULL. */
+ return (errno != 0 ? errno : ENOENT);
+
+ nlen = strlen (n);
+ if (size <= nlen)
+ return ERANGE;
+ memcpy (name, n, nlen + 1);
+ return 0;
+#endif
+}
diff --git a/gdb/gnulib/import/glob-libc.h b/gdb/gnulib/import/glob-libc.h
new file mode 100644
index 0000000000..6256077f70
--- /dev/null
+++ b/gdb/gnulib/import/glob-libc.h
@@ -0,0 +1,212 @@
+/* Copyright (C) 1991-1992, 1995-1998, 2000-2001, 2004-2007, 2009-2016 Free
+ Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _GLOB_H
+#define _GLOB_H 1
+
+#ifndef __GLOB_GNULIB
+# include <sys/cdefs.h>
+#endif
+
+/* GCC 2.95 and later have "__restrict"; C99 compilers have
+ "restrict", and "configure" may have defined "restrict".
+ Other compilers use __restrict, __restrict__, and _Restrict, and
+ 'configure' might #define 'restrict' to those words, so pick a
+ different name. */
+#ifndef _Restrict_
+# if 199901L <= __STDC_VERSION__
+# define _Restrict_ restrict
+# elif 2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)
+# define _Restrict_ __restrict
+# else
+# define _Restrict_
+# endif
+#endif
+
+__BEGIN_DECLS
+
+/* We need 'size_t' for the following definitions. */
+#ifndef __size_t
+# if defined __GNUC__ && __GNUC__ >= 2
+typedef __SIZE_TYPE__ __size_t;
+# ifdef __USE_XOPEN
+typedef __SIZE_TYPE__ size_t;
+# endif
+# else
+# include <stddef.h>
+# ifndef __size_t
+# define __size_t size_t
+# endif
+# endif
+#else
+/* The GNU CC stddef.h version defines __size_t as empty. We need a real
+ definition. */
+# undef __size_t
+# define __size_t size_t
+#endif
+
+/* Bits set in the FLAGS argument to 'glob'. */
+#define GLOB_ERR (1 << 0)/* Return on read errors. */
+#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
+#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
+#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
+#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
+#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
+#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
+#define GLOB_PERIOD (1 << 7)/* Leading '.' can be matched by metachars. */
+
+#if !defined __USE_POSIX2 || defined __USE_BSD || defined __USE_GNU
+# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
+# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
+# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
+# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
+# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
+# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
+# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
+ if the user name is not available. */
+# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+ GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
+ GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
+#else
+# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+ GLOB_PERIOD)
+#endif
+
+/* Error returns from 'glob'. */
+#define GLOB_NOSPACE 1 /* Ran out of memory. */
+#define GLOB_ABORTED 2 /* Read error. */
+#define GLOB_NOMATCH 3 /* No matches found. */
+#define GLOB_NOSYS 4 /* Not implemented. */
+#ifdef __USE_GNU
+/* Previous versions of this file defined GLOB_ABEND instead of
+ GLOB_ABORTED. Provide a compatibility definition here. */
+# define GLOB_ABEND GLOB_ABORTED
+#endif
+
+/* Structure describing a globbing run. */
+#ifdef __USE_GNU
+struct stat;
+#endif
+typedef struct
+ {
+ __size_t gl_pathc; /* Count of paths matched by the pattern. */
+ char **gl_pathv; /* List of matched pathnames. */
+ __size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
+ int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
+
+ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+ are used instead of the normal file access functions. */
+ void (*gl_closedir) (void *);
+#ifdef __USE_GNU
+ struct dirent *(*gl_readdir) (void *);
+#else
+ void *(*gl_readdir) (void *);
+#endif
+ void *(*gl_opendir) (const char *);
+#ifdef __USE_GNU
+ int (*gl_lstat) (const char *_Restrict_, struct stat *_Restrict_);
+ int (*gl_stat) (const char *_Restrict_, struct stat *_Restrict_);
+#else
+ int (*gl_lstat) (const char *_Restrict_, void *_Restrict_);
+ int (*gl_stat) (const char *_Restrict_, void *_Restrict_);
+#endif
+ } glob_t;
+
+#if defined __USE_LARGEFILE64 && !defined __GLOB_GNULIB
+# ifdef __USE_GNU
+struct stat64;
+# endif
+typedef struct
+ {
+ __size_t gl_pathc;
+ char **gl_pathv;
+ __size_t gl_offs;
+ int gl_flags;
+
+ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+ are used instead of the normal file access functions. */
+ void (*gl_closedir) (void *);
+# ifdef __USE_GNU
+ struct dirent64 *(*gl_readdir) (void *);
+# else
+ void *(*gl_readdir) (void *);
+# endif
+ void *(*gl_opendir) (const char *);
+# ifdef __USE_GNU
+ int (*gl_lstat) (const char *_Restrict_, struct stat64 *_Restrict_);
+ int (*gl_stat) (const char *_Restrict_, struct stat64 *_Restrict_);
+# else
+ int (*gl_lstat) (const char *_Restrict_, void *_Restrict_);
+ int (*gl_stat) (const char *_Restrict_, void *_Restrict_);
+# endif
+ } glob64_t;
+#endif
+
+#if __USE_FILE_OFFSET64 && __GNUC__ < 2 && !defined __GLOB_GNULIB
+# define glob glob64
+# define globfree globfree64
+#endif
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ 'errno' value from the failing call; if it returns non-zero
+ 'glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, 'glob' returns zero. */
+#if !defined __USE_FILE_OFFSET64 || __GNUC__ < 2 || defined __GLOB_GNULIB
+extern int glob (const char *_Restrict_ __pattern, int __flags,
+ int (*__errfunc) (const char *, int),
+ glob_t *_Restrict_ __pglob) __THROW _GL_ARG_NONNULL ((1, 4));
+
+/* Free storage allocated in PGLOB by a previous 'glob' call. */
+extern void globfree (glob_t *__pglob) __THROW _GL_ARG_NONNULL ((1));
+#else
+extern int __REDIRECT_NTH (glob, (const char *_Restrict_ __pattern,
+ int __flags,
+ int (*__errfunc) (const char *, int),
+ glob_t *_Restrict_ __pglob), glob64);
+
+extern void __REDIRECT_NTH (globfree, (glob_t *__pglob), globfree64);
+#endif
+
+#if defined __USE_LARGEFILE64 && !defined __GLOB_GNULIB
+extern int glob64 (const char *_Restrict_ __pattern, int __flags,
+ int (*__errfunc) (const char *, int),
+ glob64_t *_Restrict_ __pglob)
+ __THROW _GL_ARG_NONNULL ((1, 4));
+
+extern void globfree64 (glob64_t *__pglob) __THROW _GL_ARG_NONNULL ((1));
+#endif
+
+
+#ifdef __USE_GNU
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero.
+
+ This function is not part of the interface specified by POSIX.2
+ but several programs want to use it. */
+extern int glob_pattern_p (const char *__pattern, int __quote)
+ __THROW _GL_ARG_NONNULL ((1));
+#endif
+
+__END_DECLS
+
+#endif /* glob.h */
diff --git a/gdb/gnulib/import/glob.c b/gdb/gnulib/import/glob.c
new file mode 100644
index 0000000000..4b04b902e5
--- /dev/null
+++ b/gdb/gnulib/import/glob.c
@@ -0,0 +1,1808 @@
+/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC
+/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
+ optimizes away the pattern == NULL || pglob == NULL tests below. */
+# define _GL_ARG_NONNULL(params)
+# include <config.h>
+#endif
+
+#include <glob.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Outcomment the following line for production quality code. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include <stdio.h> /* Needed on stupid SunOS for assert. */
+
+#ifndef GLOB_ONLY_P
+
+#include <unistd.h>
+#if !defined POSIX && defined _POSIX_VERSION
+# define POSIX
+#endif
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WINDOWS32
+#endif
+
+#ifndef WINDOWS32
+# include <pwd.h>
+#endif
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+
+#ifdef _LIBC
+# undef strdup
+# define strdup(str) __strdup (str)
+# define sysconf(id) __sysconf (id)
+# define closedir(dir) __closedir (dir)
+# define opendir(name) __opendir (name)
+# define readdir(str) __readdir64 (str)
+# define getpwnam_r(name, bufp, buf, len, res) \
+ __getpwnam_r (name, bufp, buf, len, res)
+# ifndef __stat64
+# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
+# endif
+# define struct_stat64 struct stat64
+#else /* !_LIBC */
+# define __getlogin_r(buf, len) getlogin_r (buf, len)
+# define __stat64(fname, buf) stat (fname, buf)
+# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
+# define struct_stat64 struct stat
+# ifndef __MVS__
+# define __alloca alloca
+# endif
+# define __readdir readdir
+# define __glob_pattern_p glob_pattern_p
+# define COMPILE_GLOB64
+#endif /* _LIBC */
+
+#include <fnmatch.h>
+
+#include "flexmember.h"
+
+#ifdef _SC_GETPW_R_SIZE_MAX
+# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX)
+#else
+# define GETPW_R_SIZE_MAX() (-1)
+#endif
+#ifdef _SC_LOGIN_NAME_MAX
+# define GET_LOGIN_NAME_MAX() sysconf (_SC_LOGIN_NAME_MAX)
+#else
+# define GET_LOGIN_NAME_MAX() (-1)
+#endif
+
+static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
+
+/* A representation of a directory entry which does not depend on the
+ layout of struct dirent, or the size of ino_t. */
+struct readdir_result
+{
+ const char *name;
+# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+ uint8_t type;
+# endif
+ bool skip_entry;
+};
+
+# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+/* Initializer based on the d_type member of struct dirent. */
+# define D_TYPE_TO_RESULT(source) (source)->d_type,
+
+/* True if the directory entry D might be a symbolic link. */
+static bool
+readdir_result_might_be_symlink (struct readdir_result d)
+{
+ return d.type == DT_UNKNOWN || d.type == DT_LNK;
+}
+
+/* True if the directory entry D might be a directory. */
+static bool
+readdir_result_might_be_dir (struct readdir_result d)
+{
+ return d.type == DT_DIR || readdir_result_might_be_symlink (d);
+}
+# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
+# define D_TYPE_TO_RESULT(source)
+
+/* If we do not have type information, symbolic links and directories
+ are always a possibility. */
+
+static bool
+readdir_result_might_be_symlink (struct readdir_result d)
+{
+ return true;
+}
+
+static bool
+readdir_result_might_be_dir (struct readdir_result d)
+{
+ return true;
+}
+
+# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
+
+# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+/* Initializer for skip_entry. POSIX does not require that the d_ino
+ field be present, and some systems do not provide it. */
+# define D_INO_TO_RESULT(source) false,
+# else
+# define D_INO_TO_RESULT(source) (source)->d_ino == 0,
+# endif
+
+/* Construct an initializer for a struct readdir_result object from a
+ struct dirent *. No copy of the name is made. */
+#define READDIR_RESULT_INITIALIZER(source) \
+ { \
+ source->d_name, \
+ D_TYPE_TO_RESULT (source) \
+ D_INO_TO_RESULT (source) \
+ }
+
+#endif /* !defined GLOB_ONLY_P */
+
+/* Call gl_readdir on STREAM. This macro can be overridden to reduce
+ type safety if an old interface version needs to be supported. */
+#ifndef GL_READDIR
+# define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream))
+#endif
+
+/* Extract name and type from directory entry. No copy of the name is
+ made. If SOURCE is NULL, result name is NULL. Keep in sync with
+ convert_dirent64 below. */
+static struct readdir_result
+convert_dirent (const struct dirent *source)
+{
+ if (source == NULL)
+ {
+ struct readdir_result result = { NULL, };
+ return result;
+ }
+ struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
+ return result;
+}
+
+#ifndef COMPILE_GLOB64
+/* Like convert_dirent, but works on struct dirent64 instead. Keep in
+ sync with convert_dirent above. */
+static struct readdir_result
+convert_dirent64 (const struct dirent64 *source)
+{
+ if (source == NULL)
+ {
+ struct readdir_result result = { NULL, };
+ return result;
+ }
+ struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
+ return result;
+}
+#endif
+
+
+#ifndef attribute_hidden
+# define attribute_hidden
+#endif
+
+#ifndef __attribute_noinline__
+# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 1)
+# define __attribute_noinline__ /* Ignore */
+#else
+# define __attribute_noinline__ __attribute__ ((__noinline__))
+# endif
+#endif
+
+#if ! defined __builtin_expect && __GNUC__ < 3
+# define __builtin_expect(expr, expected) (expr)
+#endif
+
+#ifndef __glibc_unlikely
+# define __glibc_unlikely(expr) __builtin_expect (expr, 0)
+#endif
+
+#ifndef _LIBC
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+ and we do not leak fds to any single-threaded code that could use stdio,
+ therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
+ FIXME - if the kernel ever adds support for multi-thread safety for
+ avoiding standard fds, then we should use opendir_safer. */
+# ifdef GNULIB_defined_opendir
+# undef opendir
+# endif
+# ifdef GNULIB_defined_closedir
+# undef closedir
+# endif
+
+/* Just use malloc. */
+# define __libc_use_alloca(n) false
+# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
+# define extend_alloca_account(buf, len, newlen, avar) \
+ ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+/* Set *R = A + B. Return true if the answer is mathematically
+ incorrect due to overflow; in this case, *R is the low order
+ bits of the correct answer.. */
+
+static bool
+size_add_wrapv (size_t a, size_t b, size_t *r)
+{
+#if 5 <= __GNUC__ || __has_builtin (__builtin_add_overflow)
+ return __builtin_add_overflow (a, b, r);
+#else
+ *r = a + b;
+ return *r < a;
+#endif
+}
+
+static bool
+glob_use_alloca (size_t alloca_used, size_t len)
+{
+ size_t size;
+ return (!size_add_wrapv (alloca_used, len, &size)
+ && __libc_use_alloca (size));
+}
+
+static int glob_in_dir (const char *pattern, const char *directory,
+ int flags, int (*errfunc) (const char *, int),
+ glob_t *pglob, size_t alloca_used);
+extern int __glob_pattern_type (const char *pattern, int quote)
+ attribute_hidden;
+
+#ifndef GLOB_ONLY_P
+static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
+static int collated_compare (const void *, const void *) __THROWNL;
+
+
+/* Find the end of the sub-pattern in a brace expression. */
+static const char *
+next_brace_sub (const char *cp, int flags)
+{
+ size_t depth = 0;
+ while (*cp != '\0')
+ if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
+ {
+ if (*++cp == '\0')
+ break;
+ ++cp;
+ }
+ else
+ {
+ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+ break;
+
+ if (*cp++ == '{')
+ depth++;
+ }
+
+ return *cp != '\0' ? cp : NULL;
+}
+
+#endif /* !defined GLOB_ONLY_P */
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ 'errno' value from the failing call; if it returns non-zero
+ 'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, 'glob' returns zero. */
+int
+#ifdef GLOB_ATTRIBUTE
+GLOB_ATTRIBUTE
+#endif
+glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
+ glob_t *pglob)
+{
+ const char *filename;
+ char *dirname = NULL;
+ size_t dirlen;
+ int status;
+ size_t oldcount;
+ int meta;
+ int dirname_modified;
+ int malloc_dirname = 0;
+ glob_t dirs;
+ int retval = 0;
+ size_t alloca_used = 0;
+
+ if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* POSIX requires all slashes to be matched. This means that with
+ a trailing slash we must match only directories. */
+ if (pattern[0] && pattern[strlen (pattern) - 1] == '/')
+ flags |= GLOB_ONLYDIR;
+
+ if (!(flags & GLOB_DOOFFS))
+ /* Have to do this so 'globfree' knows where to start freeing. It
+ also makes all the code that uses gl_offs simpler. */
+ pglob->gl_offs = 0;
+
+ if (flags & GLOB_BRACE)
+ {
+ const char *begin;
+
+ if (flags & GLOB_NOESCAPE)
+ begin = strchr (pattern, '{');
+ else
+ {
+ begin = pattern;
+ while (1)
+ {
+ if (*begin == '\0')
+ {
+ begin = NULL;
+ break;
+ }
+
+ if (*begin == '\\' && begin[1] != '\0')
+ ++begin;
+ else if (*begin == '{')
+ break;
+
+ ++begin;
+ }
+ }
+
+ if (begin != NULL)
+ {
+ /* Allocate working buffer large enough for our work. Note that
+ we have at least an opening and closing brace. */
+ size_t firstc;
+ char *alt_start;
+ const char *p;
+ const char *next;
+ const char *rest;
+ size_t rest_len;
+ char *onealt;
+ size_t pattern_len = strlen (pattern) - 1;
+ int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
+ if (alloca_onealt)
+ onealt = alloca_account (pattern_len, alloca_used);
+ else
+ {
+ onealt = malloc (pattern_len);
+ if (onealt == NULL)
+ {
+ if (!(flags & GLOB_APPEND))
+ {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ }
+ return GLOB_NOSPACE;
+ }
+ }
+
+ /* We know the prefix for all sub-patterns. */
+ alt_start = mempcpy (onealt, pattern, begin - pattern);
+
+ /* Find the first sub-pattern and at the same time find the
+ rest after the closing brace. */
+ next = next_brace_sub (begin + 1, flags);
+ if (next == NULL)
+ {
+ /* It is an invalid expression. */
+ illegal_brace:
+ if (__glibc_unlikely (!alloca_onealt))
+ free (onealt);
+ return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+ }
+
+ /* Now find the end of the whole brace expression. */
+ rest = next;
+ while (*rest != '}')
+ {
+ rest = next_brace_sub (rest + 1, flags);
+ if (rest == NULL)
+ /* It is an illegal expression. */
+ goto illegal_brace;
+ }
+ /* Please note that we now can be sure the brace expression
+ is well-formed. */
+ rest_len = strlen (++rest) + 1;
+
+ /* We have a brace expression. BEGIN points to the opening {,
+ NEXT points past the terminator of the first element, and END
+ points past the final }. We will accumulate result names from
+ recursive runs for each brace alternative in the buffer using
+ GLOB_APPEND. */
+
+ if (!(flags & GLOB_APPEND))
+ {
+ /* This call is to set a new vector, so clear out the
+ vector so we can append to it. */
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ }
+ firstc = pglob->gl_pathc;
+
+ p = begin + 1;
+ while (1)
+ {
+ int result;
+
+ /* Construct the new glob expression. */
+ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+
+ result = glob (onealt,
+ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+ | GLOB_APPEND), errfunc, pglob);
+
+ /* If we got an error, return it. */
+ if (result && result != GLOB_NOMATCH)
+ {
+ if (__glibc_unlikely (!alloca_onealt))
+ free (onealt);
+ if (!(flags & GLOB_APPEND))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ }
+ return result;
+ }
+
+ if (*next == '}')
+ /* We saw the last entry. */
+ break;
+
+ p = next + 1;
+ next = next_brace_sub (p, flags);
+ assert (next != NULL);
+ }
+
+ if (__glibc_unlikely (!alloca_onealt))
+ free (onealt);
+
+ if (pglob->gl_pathc != firstc)
+ /* We found some entries. */
+ return 0;
+ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ return GLOB_NOMATCH;
+ }
+ }
+
+ if (!(flags & GLOB_APPEND))
+ {
+ pglob->gl_pathc = 0;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_pathv = NULL;
+ else
+ {
+ size_t i;
+
+ if (pglob->gl_offs >= SIZE_MAX / sizeof (char *))
+ return GLOB_NOSPACE;
+
+ pglob->gl_pathv = malloc ((pglob->gl_offs + 1) * sizeof (char *));
+ if (pglob->gl_pathv == NULL)
+ return GLOB_NOSPACE;
+
+ for (i = 0; i <= pglob->gl_offs; ++i)
+ pglob->gl_pathv[i] = NULL;
+ }
+ }
+
+ oldcount = pglob->gl_pathc + pglob->gl_offs;
+
+ /* Find the filename. */
+ filename = strrchr (pattern, '/');
+#if defined __MSDOS__ || defined WINDOWS32
+ /* The case of "d:pattern". Since ':' is not allowed in
+ file names, we can safely assume that wherever it
+ happens in pattern, it signals the filename part. This
+ is so we could some day support patterns like "[a-z]:foo". */
+ if (filename == NULL)
+ filename = strchr (pattern, ':');
+#endif /* __MSDOS__ || WINDOWS32 */
+ dirname_modified = 0;
+ if (filename == NULL)
+ {
+ /* This can mean two things: a simple name or "~name". The latter
+ case is nothing but a notation for a directory. */
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
+ {
+ dirname = (char *) pattern;
+ dirlen = strlen (pattern);
+
+ /* Set FILENAME to NULL as a special flag. This is ugly but
+ other solutions would require much more code. We test for
+ this special case below. */
+ filename = NULL;
+ }
+ else
+ {
+ if (__glibc_unlikely (pattern[0] == '\0'))
+ {
+ dirs.gl_pathv = NULL;
+ goto no_matches;
+ }
+
+ filename = pattern;
+#ifdef _AMIGA
+ dirname = (char *) "";
+#else
+ dirname = (char *) ".";
+#endif
+ dirlen = 0;
+ }
+ }
+ else if (filename == pattern
+ || (filename == pattern + 1 && pattern[0] == '\\'
+ && (flags & GLOB_NOESCAPE) == 0))
+ {
+ /* "/pattern" or "\\/pattern". */
+ dirname = (char *) "/";
+ dirlen = 1;
+ ++filename;
+ }
+ else
+ {
+ char *newp;
+ dirlen = filename - pattern;
+#if defined __MSDOS__ || defined WINDOWS32
+ if (*filename == ':'
+ || (filename > pattern + 1 && filename[-1] == ':'))
+ {
+ char *drive_spec;
+
+ ++dirlen;
+ drive_spec = __alloca (dirlen + 1);
+ *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
+ /* For now, disallow wildcards in the drive spec, to
+ prevent infinite recursion in glob. */
+ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
+ return GLOB_NOMATCH;
+ /* If this is "d:pattern", we need to copy ':' to DIRNAME
+ as well. If it's "d:/pattern", don't remove the slash
+ from "d:/", since "d:" and "d:/" are not the same.*/
+ }
+#endif
+ if (glob_use_alloca (alloca_used, dirlen + 1))
+ newp = alloca_account (dirlen + 1, alloca_used);
+ else
+ {
+ newp = malloc (dirlen + 1);
+ if (newp == NULL)
+ return GLOB_NOSPACE;
+ malloc_dirname = 1;
+ }
+ *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
+ dirname = newp;
+ ++filename;
+
+ if (filename[0] == '\0'
+#if defined __MSDOS__ || defined WINDOWS32
+ && dirname[dirlen - 1] != ':'
+ && (dirlen < 3 || dirname[dirlen - 2] != ':'
+ || dirname[dirlen - 1] != '/')
+#endif
+ && dirlen > 1)
+ /* "pattern/". Expand "pattern", appending slashes. */
+ {
+ int orig_flags = flags;
+ int val;
+ if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
+ {
+ /* "pattern\\/". Remove the final backslash if it hasn't
+ been quoted. */
+ char *p = (char *) &dirname[dirlen - 1];
+
+ while (p > dirname && p[-1] == '\\') --p;
+ if ((&dirname[dirlen] - p) & 1)
+ {
+ *(char *) &dirname[--dirlen] = '\0';
+ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
+ }
+ }
+ val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+ if (val == 0)
+ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
+ | (flags & GLOB_MARK));
+ else if (val == GLOB_NOMATCH && flags != orig_flags)
+ {
+ /* Make sure globfree (&dirs); is a nop. */
+ dirs.gl_pathv = NULL;
+ flags = orig_flags;
+ oldcount = pglob->gl_pathc + pglob->gl_offs;
+ goto no_matches;
+ }
+ retval = val;
+ goto out;
+ }
+ }
+
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
+ {
+ if (dirname[1] == '\0' || dirname[1] == '/'
+ || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\'
+ && (dirname[2] == '\0' || dirname[2] == '/')))
+ {
+ /* Look up home directory. */
+ char *home_dir = getenv ("HOME");
+ int malloc_home_dir = 0;
+# ifdef _AMIGA
+ if (home_dir == NULL || home_dir[0] == '\0')
+ home_dir = "SYS:";
+# else
+# ifdef WINDOWS32
+ /* Windows NT defines HOMEDRIVE and HOMEPATH. But give preference
+ to HOME, because the user can change HOME. */
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ const char *home_drive = getenv ("HOMEDRIVE");
+ const char *home_path = getenv ("HOMEPATH");
+
+ if (home_drive != NULL && home_path != NULL)
+ {
+ size_t home_drive_len = strlen (home_drive);
+ size_t home_path_len = strlen (home_path);
+ char *mem = alloca (home_drive_len + home_path_len + 1);
+
+ memcpy (mem, home_drive, home_drive_len);
+ memcpy (mem + home_drive_len, home_path, home_path_len + 1);
+ home_dir = mem;
+ }
+ else
+ home_dir = "c:/users/default"; /* poor default */
+ }
+# else
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ int success;
+ char *name;
+ int malloc_name = 0;
+ size_t buflen = GET_LOGIN_NAME_MAX () + 1;
+
+ if (buflen == 0)
+ /* 'sysconf' does not support _SC_LOGIN_NAME_MAX. Try
+ a moderate value. */
+ buflen = 20;
+ if (glob_use_alloca (alloca_used, buflen))
+ name = alloca_account (buflen, alloca_used);
+ else
+ {
+ name = malloc (buflen);
+ if (name == NULL)
+ {
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_name = 1;
+ }
+
+ success = __getlogin_r (name, buflen) == 0;
+ if (success)
+ {
+ struct passwd *p;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int pwbuflenmax = GETPW_R_SIZE_MAX ();
+ size_t pwbuflen = pwbuflenmax;
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ char *malloc_pwtmpbuf = NULL;
+ int save = errno;
+
+# ifndef _LIBC
+ if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX))
+ /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+ Try a moderate value. */
+ pwbuflen = 1024;
+# endif
+ if (glob_use_alloca (alloca_used, pwbuflen))
+ pwtmpbuf = alloca_account (pwbuflen, alloca_used);
+ else
+ {
+ pwtmpbuf = malloc (pwbuflen);
+ if (pwtmpbuf == NULL)
+ {
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_pwtmpbuf = pwtmpbuf;
+ }
+
+ while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+ != 0)
+ {
+ size_t newlen;
+ bool v;
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+ v = size_add_wrapv (pwbuflen, pwbuflen, &newlen);
+ if (!v && malloc_pwtmpbuf == NULL
+ && glob_use_alloca (alloca_used, newlen))
+ pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
+ newlen, alloca_used);
+ else
+ {
+ char *newp = (v ? NULL
+ : realloc (malloc_pwtmpbuf, newlen));
+ if (newp == NULL)
+ {
+ free (malloc_pwtmpbuf);
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_pwtmpbuf = pwtmpbuf = newp;
+ }
+ pwbuflen = newlen;
+ __set_errno (save);
+ }
+# else
+ p = getpwnam (name);
+# endif
+ if (__glibc_unlikely (malloc_name))
+ free (name);
+ if (p != NULL)
+ {
+ if (malloc_pwtmpbuf == NULL)
+ home_dir = p->pw_dir;
+ else
+ {
+ size_t home_dir_len = strlen (p->pw_dir) + 1;
+ if (glob_use_alloca (alloca_used, home_dir_len))
+ home_dir = alloca_account (home_dir_len,
+ alloca_used);
+ else
+ {
+ home_dir = malloc (home_dir_len);
+ if (home_dir == NULL)
+ {
+ free (pwtmpbuf);
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_home_dir = 1;
+ }
+ memcpy (home_dir, p->pw_dir, home_dir_len);
+
+ free (pwtmpbuf);
+ }
+ }
+ }
+ }
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ if (flags & GLOB_TILDE_CHECK)
+ {
+ if (__glibc_unlikely (malloc_home_dir))
+ free (home_dir);
+ retval = GLOB_NOMATCH;
+ goto out;
+ }
+ else
+ home_dir = (char *) "~"; /* No luck. */
+ }
+# endif /* WINDOWS32 */
+# endif
+ /* Now construct the full directory. */
+ if (dirname[1] == '\0')
+ {
+ if (__glibc_unlikely (malloc_dirname))
+ free (dirname);
+
+ dirname = home_dir;
+ dirlen = strlen (dirname);
+ malloc_dirname = malloc_home_dir;
+ }
+ else
+ {
+ char *newp;
+ size_t home_len = strlen (home_dir);
+ int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
+ if (use_alloca)
+ newp = alloca_account (home_len + dirlen, alloca_used);
+ else
+ {
+ newp = malloc (home_len + dirlen);
+ if (newp == NULL)
+ {
+ if (__glibc_unlikely (malloc_home_dir))
+ free (home_dir);
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ }
+
+ mempcpy (mempcpy (newp, home_dir, home_len),
+ &dirname[1], dirlen);
+
+ if (__glibc_unlikely (malloc_dirname))
+ free (dirname);
+
+ dirname = newp;
+ dirlen += home_len - 1;
+ malloc_dirname = !use_alloca;
+ }
+ dirname_modified = 1;
+ }
+# if !defined _AMIGA && !defined WINDOWS32
+ else
+ {
+ char *end_name = strchr (dirname, '/');
+ char *user_name;
+ int malloc_user_name = 0;
+ char *unescape = NULL;
+
+ if (!(flags & GLOB_NOESCAPE))
+ {
+ if (end_name == NULL)
+ {
+ unescape = strchr (dirname, '\\');
+ if (unescape)
+ end_name = strchr (unescape, '\0');
+ }
+ else
+ unescape = memchr (dirname, '\\', end_name - dirname);
+ }
+ if (end_name == NULL)
+ user_name = dirname + 1;
+ else
+ {
+ char *newp;
+ if (glob_use_alloca (alloca_used, end_name - dirname))
+ newp = alloca_account (end_name - dirname, alloca_used);
+ else
+ {
+ newp = malloc (end_name - dirname);
+ if (newp == NULL)
+ {
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_user_name = 1;
+ }
+ if (unescape != NULL)
+ {
+ char *p = mempcpy (newp, dirname + 1,
+ unescape - dirname - 1);
+ char *q = unescape;
+ while (*q != '\0')
+ {
+ if (*q == '\\')
+ {
+ if (q[1] == '\0')
+ {
+ /* "~fo\\o\\" unescape to user_name "foo\\",
+ but "~fo\\o\\/" unescape to user_name
+ "foo". */
+ if (filename == NULL)
+ *p++ = '\\';
+ break;
+ }
+ ++q;
+ }
+ *p++ = *q++;
+ }
+ *p = '\0';
+ }
+ else
+ *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+ = '\0';
+ user_name = newp;
+ }
+
+ /* Look up specific user's home directory. */
+ {
+ struct passwd *p;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int buflenmax = GETPW_R_SIZE_MAX ();
+ size_t buflen = buflenmax;
+ char *pwtmpbuf;
+ char *malloc_pwtmpbuf = NULL;
+ struct passwd pwbuf;
+ int save = errno;
+
+# ifndef _LIBC
+ if (! (0 <= buflenmax && buflenmax <= SIZE_MAX))
+ /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
+ moderate value. */
+ buflen = 1024;
+# endif
+ if (glob_use_alloca (alloca_used, buflen))
+ pwtmpbuf = alloca_account (buflen, alloca_used);
+ else
+ {
+ pwtmpbuf = malloc (buflen);
+ if (pwtmpbuf == NULL)
+ {
+ nomem_getpw:
+ if (__glibc_unlikely (malloc_user_name))
+ free (user_name);
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_pwtmpbuf = pwtmpbuf;
+ }
+
+ while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+ {
+ size_t newlen;
+ bool v;
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+ v = size_add_wrapv (buflen, buflen, &newlen);
+ if (!v && malloc_pwtmpbuf == NULL
+ && glob_use_alloca (alloca_used, newlen))
+ pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
+ newlen, alloca_used);
+ else
+ {
+ char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen);
+ if (newp == NULL)
+ {
+ free (malloc_pwtmpbuf);
+ goto nomem_getpw;
+ }
+ malloc_pwtmpbuf = pwtmpbuf = newp;
+ }
+ __set_errno (save);
+ }
+# else
+ p = getpwnam (user_name);
+# endif
+
+ if (__glibc_unlikely (malloc_user_name))
+ free (user_name);
+
+ /* If we found a home directory use this. */
+ if (p != NULL)
+ {
+ size_t home_len = strlen (p->pw_dir);
+ size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+
+ if (__glibc_unlikely (malloc_dirname))
+ free (dirname);
+ malloc_dirname = 0;
+
+ if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
+ dirname = alloca_account (home_len + rest_len + 1,
+ alloca_used);
+ else
+ {
+ dirname = malloc (home_len + rest_len + 1);
+ if (dirname == NULL)
+ {
+ free (malloc_pwtmpbuf);
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_dirname = 1;
+ }
+ *((char *) mempcpy (mempcpy (dirname, p->pw_dir, home_len),
+ end_name, rest_len)) = '\0';
+
+ dirlen = home_len + rest_len;
+ dirname_modified = 1;
+
+ free (malloc_pwtmpbuf);
+ }
+ else
+ {
+ free (malloc_pwtmpbuf);
+
+ if (flags & GLOB_TILDE_CHECK)
+ /* We have to regard it as an error if we cannot find the
+ home directory. */
+ return GLOB_NOMATCH;
+ }
+ }
+ }
+# endif /* Not Amiga && not WINDOWS32. */
+ }
+
+ /* Now test whether we looked for "~" or "~NAME". In this case we
+ can give the answer now. */
+ if (filename == NULL)
+ {
+ struct stat st;
+ struct_stat64 st64;
+
+ /* Return the directory if we don't check for error or if it exists. */
+ if ((flags & GLOB_NOCHECK)
+ || (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+ ? ((*pglob->gl_stat) (dirname, &st) == 0
+ && S_ISDIR (st.st_mode))
+ : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
+ {
+ size_t newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ if (newcount > SIZE_MAX / sizeof (char *) - 2)
+ {
+ nospace:
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+
+ new_gl_pathv = realloc (pglob->gl_pathv,
+ (newcount + 2) * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ goto nospace;
+ pglob->gl_pathv = new_gl_pathv;
+
+ if (flags & GLOB_MARK)
+ {
+ char *p;
+ pglob->gl_pathv[newcount] = malloc (dirlen + 2);
+ if (pglob->gl_pathv[newcount] == NULL)
+ goto nospace;
+ p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
+ p[0] = '/';
+ p[1] = '\0';
+ }
+ else
+ {
+ pglob->gl_pathv[newcount] = strdup (dirname);
+ if (pglob->gl_pathv[newcount] == NULL)
+ goto nospace;
+ }
+ pglob->gl_pathv[++newcount] = NULL;
+ ++pglob->gl_pathc;
+ pglob->gl_flags = flags;
+
+ return 0;
+ }
+
+ /* Not found. */
+ return GLOB_NOMATCH;
+ }
+
+ meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
+ /* meta is 1 if correct glob pattern containing metacharacters.
+ If meta has bit (1 << 2) set, it means there was an unterminated
+ [ which we handle the same, using fnmatch. Broken unterminated
+ pattern bracket expressions ought to be rare enough that it is
+ not worth special casing them, fnmatch will do the right thing. */
+ if (meta & 5)
+ {
+ /* The directory name contains metacharacters, so we
+ have to glob for the directory, and then glob for
+ the pattern in each directory found. */
+ size_t i;
+
+ if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\')
+ {
+ /* "foo\\/bar". Remove the final backslash from dirname
+ if it has not been quoted. */
+ char *p = (char *) &dirname[dirlen - 1];
+
+ while (p > dirname && p[-1] == '\\') --p;
+ if ((&dirname[dirlen] - p) & 1)
+ *(char *) &dirname[--dirlen] = '\0';
+ }
+
+ if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0))
+ {
+ /* Use the alternative access functions also in the recursive
+ call. */
+ dirs.gl_opendir = pglob->gl_opendir;
+ dirs.gl_readdir = pglob->gl_readdir;
+ dirs.gl_closedir = pglob->gl_closedir;
+ dirs.gl_stat = pglob->gl_stat;
+ dirs.gl_lstat = pglob->gl_lstat;
+ }
+
+ status = glob (dirname,
+ ((flags & (GLOB_ERR | GLOB_NOESCAPE
+ | GLOB_ALTDIRFUNC))
+ | GLOB_NOSORT | GLOB_ONLYDIR),
+ errfunc, &dirs);
+ if (status != 0)
+ {
+ if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
+ return status;
+ goto no_matches;
+ }
+
+ /* We have successfully globbed the preceding directory name.
+ For each name we found, call glob_in_dir on it and FILENAME,
+ appending the results to PGLOB. */
+ for (i = 0; i < dirs.gl_pathc; ++i)
+ {
+ size_t old_pathc;
+
+#ifdef SHELL
+ {
+ /* Make globbing interruptible in the bash shell. */
+ extern int interrupt_state;
+
+ if (interrupt_state)
+ {
+ globfree (&dirs);
+ return GLOB_ABORTED;
+ }
+ }
+#endif /* SHELL. */
+
+ old_pathc = pglob->gl_pathc;
+ status = glob_in_dir (filename, dirs.gl_pathv[i],
+ ((flags | GLOB_APPEND)
+ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
+ errfunc, pglob, alloca_used);
+ if (status == GLOB_NOMATCH)
+ /* No matches in this directory. Try the next. */
+ continue;
+
+ if (status != 0)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return status;
+ }
+
+ /* Stick the directory on the front of each name. */
+ if (prefix_array (dirs.gl_pathv[i],
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+
+ flags |= GLOB_MAGCHAR;
+
+ /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
+ But if we have not found any matching entry and the GLOB_NOCHECK
+ flag was set we must return the input pattern itself. */
+ if (pglob->gl_pathc + pglob->gl_offs == oldcount)
+ {
+ no_matches:
+ /* No matches. */
+ if (flags & GLOB_NOCHECK)
+ {
+ size_t newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ if (newcount > SIZE_MAX / sizeof (char *) - 2)
+ {
+ nospace2:
+ globfree (&dirs);
+ return GLOB_NOSPACE;
+ }
+
+ new_gl_pathv = realloc (pglob->gl_pathv,
+ (newcount + 2) * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ goto nospace2;
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = strdup (pattern);
+ if (pglob->gl_pathv[newcount] == NULL)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+
+ ++pglob->gl_pathc;
+ ++newcount;
+
+ pglob->gl_pathv[newcount] = NULL;
+ pglob->gl_flags = flags;
+ }
+ else
+ {
+ globfree (&dirs);
+ return GLOB_NOMATCH;
+ }
+ }
+
+ globfree (&dirs);
+ }
+ else
+ {
+ size_t old_pathc = pglob->gl_pathc;
+ int orig_flags = flags;
+
+ if (meta & 2)
+ {
+ char *p = strchr (dirname, '\\'), *q;
+ /* We need to unescape the dirname string. It is certainly
+ allocated by alloca, as otherwise filename would be NULL
+ or dirname wouldn't contain backslashes. */
+ q = p;
+ do
+ {
+ if (*p == '\\')
+ {
+ *q = *++p;
+ --dirlen;
+ }
+ else
+ *q = *p;
+ ++q;
+ }
+ while (*p++ != '\0');
+ dirname_modified = 1;
+ }
+ if (dirname_modified)
+ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
+ status = glob_in_dir (filename, dirname, flags, errfunc, pglob,
+ alloca_used);
+ if (status != 0)
+ {
+ if (status == GLOB_NOMATCH && flags != orig_flags
+ && pglob->gl_pathc + pglob->gl_offs == oldcount)
+ {
+ /* Make sure globfree (&dirs); is a nop. */
+ dirs.gl_pathv = NULL;
+ flags = orig_flags;
+ goto no_matches;
+ }
+ return status;
+ }
+
+ if (dirlen > 0)
+ {
+ /* Stick the directory on the front of each name. */
+ if (prefix_array (dirname,
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+ }
+
+ if (flags & GLOB_MARK)
+ {
+ /* Append slashes to directory names. */
+ size_t i;
+ struct stat st;
+ struct_stat64 st64;
+
+ for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
+ if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+ ? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0
+ && S_ISDIR (st.st_mode))
+ : (__stat64 (pglob->gl_pathv[i], &st64) == 0
+ && S_ISDIR (st64.st_mode))))
+ {
+ size_t len = strlen (pglob->gl_pathv[i]) + 2;
+ char *new = realloc (pglob->gl_pathv[i], len);
+ if (new == NULL)
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ strcpy (&new[len - 2], "/");
+ pglob->gl_pathv[i] = new;
+ }
+ }
+
+ if (!(flags & GLOB_NOSORT))
+ {
+ /* Sort the vector. */
+ qsort (&pglob->gl_pathv[oldcount],
+ pglob->gl_pathc + pglob->gl_offs - oldcount,
+ sizeof (char *), collated_compare);
+ }
+
+ out:
+ if (__glibc_unlikely (malloc_dirname))
+ free (dirname);
+
+ return retval;
+}
+#if defined _LIBC && !defined glob
+libc_hidden_def (glob)
+#endif
+
+
+#ifndef GLOB_ONLY_P
+
+/* Free storage allocated in PGLOB by a previous 'glob' call. */
+void
+globfree (glob_t *pglob)
+{
+ if (pglob->gl_pathv != NULL)
+ {
+ size_t i;
+ for (i = 0; i < pglob->gl_pathc; ++i)
+ free (pglob->gl_pathv[pglob->gl_offs + i]);
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+#if defined _LIBC && !defined globfree
+libc_hidden_def (globfree)
+#endif
+
+
+/* Do a collated comparison of A and B. */
+static int
+collated_compare (const void *a, const void *b)
+{
+ char *const *ps1 = a; char *s1 = *ps1;
+ char *const *ps2 = b; char *s2 = *ps2;
+
+ if (s1 == s2)
+ return 0;
+ if (s1 == NULL)
+ return 1;
+ if (s2 == NULL)
+ return -1;
+ return strcoll (s1, s2);
+}
+
+
+/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
+ elements in place. Return nonzero if out of memory, zero if successful.
+ A slash is inserted between DIRNAME and each elt of ARRAY,
+ unless DIRNAME is just "/". Each old element of ARRAY is freed. */
+static int
+prefix_array (const char *dirname, char **array, size_t n)
+{
+ size_t i;
+ size_t dirlen = strlen (dirname);
+#if defined __MSDOS__ || defined WINDOWS32
+ int sep_char = '/';
+# define DIRSEP_CHAR sep_char
+#else
+# define DIRSEP_CHAR '/'
+#endif
+
+ if (dirlen == 1 && dirname[0] == '/')
+ /* DIRNAME is just "/", so normal prepending would get us "//foo".
+ We want "/foo" instead, so don't prepend any chars from DIRNAME. */
+ dirlen = 0;
+#if defined __MSDOS__ || defined WINDOWS32
+ else if (dirlen > 1)
+ {
+ if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
+ /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
+ --dirlen;
+ else if (dirname[dirlen - 1] == ':')
+ {
+ /* DIRNAME is "d:". Use ':' instead of '/'. */
+ --dirlen;
+ sep_char = ':';
+ }
+ }
+#endif
+
+ for (i = 0; i < n; ++i)
+ {
+ size_t eltlen = strlen (array[i]) + 1;
+ char *new = malloc (dirlen + 1 + eltlen);
+ if (new == NULL)
+ {
+ while (i > 0)
+ free (array[--i]);
+ return 1;
+ }
+
+ {
+ char *endp = mempcpy (new, dirname, dirlen);
+ *endp++ = DIRSEP_CHAR;
+ mempcpy (endp, array[i], eltlen);
+ }
+ free (array[i]);
+ array[i] = new;
+ }
+
+ return 0;
+}
+
+
+/* We must not compile this function twice. */
+#ifndef NO_GLOB_PATTERN_P
+int
+__glob_pattern_type (const char *pattern, int quote)
+{
+ const char *p;
+ int ret = 0;
+
+ for (p = pattern; *p != '\0'; ++p)
+ switch (*p)
+ {
+ case '?':
+ case '*':
+ return 1;
+
+ case '\\':
+ if (quote)
+ {
+ if (p[1] != '\0')
+ ++p;
+ ret |= 2;
+ }
+ break;
+
+ case '[':
+ ret |= 4;
+ break;
+
+ case ']':
+ if (ret & 4)
+ return 1;
+ break;
+ }
+
+ return ret;
+}
+
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
+int
+__glob_pattern_p (const char *pattern, int quote)
+{
+ return __glob_pattern_type (pattern, quote) == 1;
+}
+# ifdef _LIBC
+weak_alias (__glob_pattern_p, glob_pattern_p)
+# endif
+#endif
+
+
+/* We put this in a separate function mainly to allow the memory
+ allocated with alloca to be recycled. */
+static int
+__attribute_noinline__
+link_exists2_p (const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob
+# if !defined _LIBC && !HAVE_FSTATAT
+ , int flags
+# endif
+ )
+{
+ size_t fnamelen = strlen (fname);
+ char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
+ struct stat st;
+
+ mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
+ fname, fnamelen + 1);
+
+# if !defined _LIBC && !HAVE_FSTATAT
+ if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1))
+ {
+ struct_stat64 st64;
+ return __stat64 (fullname, &st64) == 0;
+ }
+# endif
+ return (*pglob->gl_stat) (fullname, &st) == 0;
+}
+
+/* Return true if DIR/FNAME exists. */
+static int
+link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob, int flags)
+{
+# if defined _LIBC || HAVE_FSTATAT
+ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+ return link_exists2_p (dir, dirlen, fname, pglob);
+ else
+ {
+ /* dfd cannot be -1 here, because dirfd never returns -1 on
+ glibc, or on hosts that have fstatat. */
+ struct_stat64 st64;
+ return __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0;
+ }
+# else
+ return link_exists2_p (dir, dirlen, fname, pglob, flags);
+# endif
+}
+#endif /* !defined GLOB_ONLY_P */
+
+
+/* Like 'glob', but PATTERN is a final pathname component,
+ and matches are searched for in DIRECTORY.
+ The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
+ The GLOB_APPEND flag is assumed to be set (always appends). */
+static int
+glob_in_dir (const char *pattern, const char *directory, int flags,
+ int (*errfunc) (const char *, int),
+ glob_t *pglob, size_t alloca_used)
+{
+ size_t dirlen = strlen (directory);
+ void *stream = NULL;
+ struct globnames
+ {
+ struct globnames *next;
+ size_t count;
+ char *name[64];
+ };
+ struct globnames init_names;
+ struct globnames *names = &init_names;
+ struct globnames *names_alloca = &init_names;
+ size_t nfound = 0;
+ size_t cur = 0;
+ int meta;
+ int save;
+ int result;
+
+ alloca_used += sizeof (init_names);
+
+ init_names.next = NULL;
+ init_names.count = sizeof init_names.name / sizeof init_names.name[0];
+
+ meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
+ if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ {
+ /* We need not do any tests. The PATTERN contains no meta
+ characters and we must not return an error therefore the
+ result will always contain exactly one name. */
+ flags |= GLOB_NOCHECK;
+ }
+ else if (meta == 0)
+ {
+ /* Since we use the normal file functions we can also use stat()
+ to verify the file is there. */
+ union
+ {
+ struct stat st;
+ struct_stat64 st64;
+ } ust;
+ size_t patlen = strlen (pattern);
+ size_t fullsize;
+ bool alloca_fullname
+ = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
+ && glob_use_alloca (alloca_used, fullsize));
+ char *fullname;
+ if (alloca_fullname)
+ fullname = alloca_account (fullsize, alloca_used);
+ else
+ {
+ fullname = malloc (fullsize);
+ if (fullname == NULL)
+ return GLOB_NOSPACE;
+ }
+
+ mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+ "/", 1),
+ pattern, patlen + 1);
+ if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+ ? (*pglob->gl_stat) (fullname, &ust.st)
+ : __stat64 (fullname, &ust.st64)) == 0)
+ /* We found this file to be existing. Now tell the rest
+ of the function to copy this name into the result. */
+ flags |= GLOB_NOCHECK;
+
+ if (__glibc_unlikely (!alloca_fullname))
+ free (fullname);
+ }
+ else
+ {
+ stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+ ? (*pglob->gl_opendir) (directory)
+ : opendir (directory));
+ if (stream == NULL)
+ {
+ if (errno != ENOTDIR
+ && ((errfunc != NULL && (*errfunc) (directory, errno))
+ || (flags & GLOB_ERR)))
+ return GLOB_ABORTED;
+ }
+ else
+ {
+ int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+ ? -1 : dirfd ((DIR *) stream));
+ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
+#if defined _AMIGA || defined VMS
+ | FNM_CASEFOLD
+#endif
+ );
+ flags |= GLOB_MAGCHAR;
+
+ while (1)
+ {
+ struct readdir_result d;
+ {
+ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+ d = convert_dirent (GL_READDIR (pglob, stream));
+ else
+ {
+#ifdef COMPILE_GLOB64
+ d = convert_dirent (__readdir (stream));
+#else
+ d = convert_dirent64 (__readdir64 (stream));
+#endif
+ }
+ }
+ if (d.name == NULL)
+ break;
+ if (d.skip_entry)
+ continue;
+
+ /* If we shall match only directories use the information
+ provided by the dirent call if possible. */
+ if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
+ continue;
+
+ if (fnmatch (pattern, d.name, fnm_flags) == 0)
+ {
+ /* If the file we found is a symlink we have to
+ make sure the target file exists. */
+ if (!readdir_result_might_be_symlink (d)
+ || link_exists_p (dfd, directory, dirlen, d.name,
+ pglob, flags))
+ {
+ if (cur == names->count)
+ {
+ struct globnames *newnames;
+ size_t count = names->count * 2;
+ size_t nameoff = offsetof (struct globnames, name);
+ size_t size = FLEXSIZEOF (struct globnames, name,
+ count * sizeof (char *));
+ if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
+ < names->count)
+ goto memory_error;
+ if (glob_use_alloca (alloca_used, size))
+ newnames = names_alloca
+ = alloca_account (size, alloca_used);
+ else if ((newnames = malloc (size))
+ == NULL)
+ goto memory_error;
+ newnames->count = count;
+ newnames->next = names;
+ names = newnames;
+ cur = 0;
+ }
+ names->name[cur] = strdup (d.name);
+ if (names->name[cur] == NULL)
+ goto memory_error;
+ ++cur;
+ ++nfound;
+ if (SIZE_MAX - pglob->gl_offs <= nfound)
+ goto memory_error;
+ }
+ }
+ }
+ }
+ }
+
+ if (nfound == 0 && (flags & GLOB_NOCHECK))
+ {
+ size_t len = strlen (pattern);
+ nfound = 1;
+ names->name[cur] = malloc (len + 1);
+ if (names->name[cur] == NULL)
+ goto memory_error;
+ *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
+ }
+
+ result = GLOB_NOMATCH;
+ if (nfound != 0)
+ {
+ char **new_gl_pathv;
+ result = 0;
+
+ if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
+ < pglob->gl_offs + nfound + 1)
+ goto memory_error;
+
+ new_gl_pathv
+ = realloc (pglob->gl_pathv,
+ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+ * sizeof (char *));
+
+ if (new_gl_pathv == NULL)
+ {
+ memory_error:
+ while (1)
+ {
+ struct globnames *old = names;
+ size_t i;
+ for (i = 0; i < cur; ++i)
+ free (names->name[i]);
+ names = names->next;
+ /* NB: we will not leak memory here if we exit without
+ freeing the current block assigned to OLD. At least
+ the very first block is always allocated on the stack
+ and this is the block assigned to OLD here. */
+ if (names == NULL)
+ {
+ assert (old == &init_names);
+ break;
+ }
+ cur = names->count;
+ if (old == names_alloca)
+ names_alloca = names;
+ else
+ free (old);
+ }
+ result = GLOB_NOSPACE;
+ }
+ else
+ {
+ while (1)
+ {
+ struct globnames *old = names;
+ size_t i;
+ for (i = 0; i < cur; ++i)
+ new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
+ = names->name[i];
+ names = names->next;
+ /* NB: we will not leak memory here if we exit without
+ freeing the current block assigned to OLD. At least
+ the very first block is always allocated on the stack
+ and this is the block assigned to OLD here. */
+ if (names == NULL)
+ {
+ assert (old == &init_names);
+ break;
+ }
+ cur = names->count;
+ if (old == names_alloca)
+ names_alloca = names;
+ else
+ free (old);
+ }
+
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+ pglob->gl_flags = flags;
+ }
+ }
+
+ if (stream != NULL)
+ {
+ save = errno;
+ if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC))
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ __set_errno (save);
+ }
+
+ return result;
+}
diff --git a/gdb/gnulib/import/glob.in.h b/gdb/gnulib/import/glob.in.h
new file mode 100644
index 0000000000..77816bc099
--- /dev/null
+++ b/gdb/gnulib/import/glob.in.h
@@ -0,0 +1,93 @@
+/* glob.h -- Find a path matching a pattern.
+
+ Copyright (C) 2005-2007, 2009-2016 Free Software Foundation, Inc.
+
+ Written by Derek Price <***@ximbiot.com> & Paul Eggert <***@CS.UCLA.EDU>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _GL_GLOB_H
+#define _GL_GLOB_H
+
+#if @HAVE_SYS_CDEFS_H@
+# include <sys/cdefs.h>
+#endif
+
+#include <stddef.h>
+
+/* On some systems, such as AIX 5.1, <sys/stat.h> does a "#define stat stat64".
+ Make sure this definition is seen before glob-libc.h defines types that
+ rely on 'struct stat'. */
+#include <sys/stat.h>
+
+#ifndef __BEGIN_DECLS
+# ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+# else
+# define __BEGIN_DECLS
+# define __END_DECLS
+# endif
+#endif
+#ifndef __THROW
+# define __THROW
+#endif
+#ifndef __THROWNL
+# define __THROWNL
+#endif
+
+/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
+
+/* The definition of _GL_ARG_NONNULL is copied here. */
+
+/* The definition of _GL_WARN_ON_USE is copied here. */
+
+#ifndef __size_t
+# define __size_t size_t
+#endif
+#ifndef __USE_GNU
+# define __USE_GNU 1
+#endif
+
+
+#define glob rpl_glob
+#define globfree rpl_globfree
+#define glob_pattern_p rpl_glob_pattern_p
+
+#define __GLOB_GNULIB 1
+
+/* Now the standard GNU C Library header should work. */
+#include "glob-libc.h"
+
+__BEGIN_DECLS
+typedef int (*_gl_glob_errfunc_fn) (const char *, int);
+__END_DECLS
+
+#if defined __cplusplus && defined GNULIB_NAMESPACE
+# undef glob
+# undef globfree
+# undef glob_pattern_p
+_GL_CXXALIAS_RPL (glob, int, (const char *_Restrict_ __pattern, int __flags,
+ _gl_glob_errfunc_fn __errfunc,
+ glob_t *_Restrict_ __pglob));
+_GL_CXXALIAS_RPL (globfree, void, (glob_t *__pglob));
+_GL_CXXALIAS_RPL (glob_pattern_p, int, (const char *__pattern, int __quote));
+# if 0 /* The C function name is rpl_glob, not glob. */
+_GL_CXXALIASWARN (glob);
+_GL_CXXALIASWARN (globfree);
+_GL_CXXALIASWARN (glob_pattern_p);
+# endif
+#endif
+
+#endif /* _GL_GLOB_H */
diff --git a/gdb/gnulib/import/m4/closedir.m4 b/gdb/gnulib/import/m4/closedir.m4
new file mode 100644
index 0000000000..0c9fd82de2
--- /dev/null
+++ b/gdb/gnulib/import/m4/closedir.m4
@@ -0,0 +1,30 @@
+# closedir.m4 serial 5
+dnl Copyright (C) 2011-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_CLOSEDIR],
+[
+ AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+
+ AC_CHECK_FUNCS([closedir])
+ if test $ac_cv_func_closedir = no; then
+ HAVE_CLOSEDIR=0
+ fi
+ dnl Replace closedir() for supporting the gnulib-defined fchdir() function,
+ dnl to keep fchdir's bookkeeping up-to-date.
+ m4_ifdef([gl_FUNC_FCHDIR], [
+ gl_TEST_FCHDIR
+ if test $HAVE_FCHDIR = 0; then
+ if test $HAVE_CLOSEDIR = 1; then
+ REPLACE_CLOSEDIR=1
+ fi
+ fi
+ ])
+ dnl Replace closedir() for supporting the gnulib-defined dirfd() function.
+ case $host_os,$HAVE_CLOSEDIR in
+ os2*,1)
+ REPLACE_CLOSEDIR=1;;
+ esac
+])
diff --git a/gdb/gnulib/import/m4/d-type.m4 b/gdb/gnulib/import/m4/d-type.m4
new file mode 100644
index 0000000000..eda762c47f
--- /dev/null
+++ b/gdb/gnulib/import/m4/d-type.m4
@@ -0,0 +1,32 @@
+# serial 11
+
+dnl From Jim Meyering.
+dnl
+dnl Check whether struct dirent has a member named d_type.
+dnl
+
+# Copyright (C) 1997, 1999-2004, 2006, 2009-2016 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE],
+ [AC_CACHE_CHECK([for d_type member in directory struct],
+ gl_cv_struct_dirent_d_type,
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <dirent.h>
+ ]],
+ [[struct dirent dp; dp.d_type = 0;]])],
+ [gl_cv_struct_dirent_d_type=yes],
+ [gl_cv_struct_dirent_d_type=no])
+ ]
+ )
+ if test $gl_cv_struct_dirent_d_type = yes; then
+ AC_DEFINE([HAVE_STRUCT_DIRENT_D_TYPE], [1],
+ [Define if there is a member named d_type in the struct describing
+ directory headers.])
+ fi
+ ]
+)
diff --git a/gdb/gnulib/import/m4/getlogin_r.m4 b/gdb/gnulib/import/m4/getlogin_r.m4
new file mode 100644
index 0000000000..80f82f4f92
--- /dev/null
+++ b/gdb/gnulib/import/m4/getlogin_r.m4
@@ -0,0 +1,88 @@
+#serial 11
+
+# Copyright (C) 2005-2007, 2009-2016 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Derek Price
+dnl
+dnl Provide getlogin_r when the system lacks it.
+dnl
+
+AC_DEFUN([gl_FUNC_GETLOGIN_R],
+[
+ AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+
+ dnl Persuade glibc <unistd.h> to declare getlogin_r().
+ dnl Persuade Solaris <unistd.h> to provide the POSIX compliant declaration of
+ dnl getlogin_r().
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+ AC_CHECK_DECLS_ONCE([getlogin_r])
+ if test $ac_cv_have_decl_getlogin_r = no; then
+ HAVE_DECL_GETLOGIN_R=0
+ fi
+
+ AC_CHECK_FUNCS_ONCE([getlogin_r])
+ if test $ac_cv_func_getlogin_r = no; then
+ HAVE_GETLOGIN_R=0
+ else
+ HAVE_GETLOGIN_R=1
+ dnl On OSF/1 5.1, getlogin_r returns a truncated result if the buffer is
+ dnl not large enough.
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_CACHE_CHECK([whether getlogin_r works with small buffers],
+ [gl_cv_func_getlogin_r_works],
+ [
+ dnl Initial guess, used when cross-compiling.
+changequote(,)dnl
+ case "$host_os" in
+ # Guess no on OSF/1.
+ osf*) gl_cv_func_getlogin_r_works="guessing no" ;;
+ # Guess yes otherwise.
+ *) gl_cv_func_getlogin_r_works="guessing yes" ;;
+ esac
+changequote([,])dnl
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <stddef.h>
+#include <unistd.h>
+#if !HAVE_DECL_GETLOGIN_R
+extern
+# ifdef __cplusplus
+"C"
+# endif
+int getlogin_r (char *, size_t);
+#endif
+int
+main (void)
+{
+ int result = 0;
+ char buf[100];
+
+ if (getlogin_r (buf, 0) == 0)
+ result |= 16;
+ if (getlogin_r (buf, 1) == 0)
+ result |= 17;
+ return result;
+}]])],
+ [gl_cv_func_getlogin_r_works=yes],
+ [case $? in
+ 16 | 17) gl_cv_func_getlogin_r_works=no ;;
+ esac
+ ],
+ [:])
+ ])
+ case "$gl_cv_func_getlogin_r_works" in
+ *yes) ;;
+ *) REPLACE_GETLOGIN_R=1 ;;
+ esac
+ fi
+])
+
+AC_DEFUN([gl_PREREQ_GETLOGIN_R],
+[
+ AC_CHECK_DECLS_ONCE([getlogin])
+])
diff --git a/gdb/gnulib/import/m4/glob.m4 b/gdb/gnulib/import/m4/glob.m4
new file mode 100644
index 0000000000..adf5fe2865
--- /dev/null
+++ b/gdb/gnulib/import/m4/glob.m4
@@ -0,0 +1,76 @@
+# glob.m4 serial 14
+dnl Copyright (C) 2005-2007, 2009-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# The glob module assumes you want GNU glob, with glob_pattern_p etc,
+# rather than vanilla POSIX glob. This means your code should
+# always include <glob.h> for the glob prototypes.
+
+AC_DEFUN([gl_GLOB],
+[ GLOB_H=
+ AC_CHECK_HEADERS([glob.h], [], [GLOB_H=glob.h])
+
+ if test -z "$GLOB_H"; then
+ AC_CACHE_CHECK([for GNU glob interface version 1],
+ [gl_cv_gnu_glob_interface_version_1],
+[ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+[[#include <gnu-versions.h>
+char a[_GNU_GLOB_INTERFACE_VERSION == 1 ? 1 : -1];]])],
+ [gl_cv_gnu_glob_interface_version_1=yes],
+ [gl_cv_gnu_glob_interface_version_1=no])])
+
+ if test "$gl_cv_gnu_glob_interface_version_1" = "no"; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ if test -z "$GLOB_H"; then
+ AC_CACHE_CHECK([whether glob lists broken symlinks],
+ [gl_cv_glob_lists_symlinks],
+[ if ln -s conf-doesntexist conf$$-globtest 2>/dev/null; then
+ gl_cv_glob_lists_symlinks=maybe
+ else
+ # If we can't make a symlink, then we cannot test this issue. Be
+ # pessimistic about this.
+ gl_cv_glob_lists_symlinks=no
+ fi
+
+ if test $gl_cv_glob_lists_symlinks = maybe; then
+ AC_RUN_IFELSE([
+AC_LANG_PROGRAM(
+[[#include <stddef.h>
+#include <glob.h>]],
+[[glob_t found;
+if (glob ("conf*-globtest", 0, NULL, &found) == GLOB_NOMATCH) return 1;]])],
+ [gl_cv_glob_lists_symlinks=yes],
+ [gl_cv_glob_lists_symlinks=no], [gl_cv_glob_lists_symlinks=no])
+ fi])
+
+ if test $gl_cv_glob_lists_symlinks = no; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ rm -f conf$$-globtest
+
+ AC_SUBST([GLOB_H])
+ AM_CONDITIONAL([GL_GENERATE_GLOB_H], [test -n "$GLOB_H"])
+])
+
+# Prerequisites of lib/glob.*.
+AC_DEFUN([gl_PREREQ_GLOB],
+[
+ AC_REQUIRE([gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE])dnl
+ AC_REQUIRE([AC_C_RESTRICT])dnl
+ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])dnl
+ AC_CHECK_HEADERS_ONCE([sys/cdefs.h unistd.h])dnl
+ if test $ac_cv_header_sys_cdefs_h = yes; then
+ HAVE_SYS_CDEFS_H=1
+ else
+ HAVE_SYS_CDEFS_H=0
+ fi
+ AC_SUBST([HAVE_SYS_CDEFS_H])
+ AC_CHECK_FUNCS_ONCE([fstatat getlogin_r getpwnam_r])dnl
+])
diff --git a/gdb/gnulib/import/m4/gnulib-cache.m4 b/gdb/gnulib/import/m4/gnulib-cache.m4
index c4ebb73bfb..b1e6430882 100644
--- a/gdb/gnulib/import/m4/gnulib-cache.m4
+++ b/gdb/gnulib/import/m4/gnulib-cache.m4
@@ -27,7 +27,7 @@


# Specification in the form of a command-line invocation:
-# gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl inttypes limits-h lstat memchr memmem pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h
+# gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl glob inttypes limits-h lstat memchr memmem pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h

# Specification in the form of a few gnulib-tool.m4 macro invocations:
gl_LOCAL_DIR([])
@@ -39,6 +39,7 @@ gl_MODULES([
errno
fnmatch-gnu
frexpl
+ glob
inttypes
limits-h
lstat
diff --git a/gdb/gnulib/import/m4/gnulib-comp.m4 b/gdb/gnulib/import/m4/gnulib-comp.m4
index 5a3656713d..7f69c95145 100644
--- a/gdb/gnulib/import/m4/gnulib-comp.m4
+++ b/gdb/gnulib/import/m4/gnulib-comp.m4
@@ -47,7 +47,9 @@ AC_DEFUN([gl_EARLY],
# Code from module alloca-opt:
# Code from module canonicalize-lgpl:
# Code from module chdir:
+ # Code from module closedir:
# Code from module configmake:
+ # Code from module d-type:
# Code from module dirent:
# Code from module dirfd:
# Code from module dirname-lgpl:
@@ -57,6 +59,7 @@ AC_DEFUN([gl_EARLY],
# Code from module errno:
# Code from module extensions:
# Code from module extern-inline:
+ # Code from module filename:
# Code from module flexmember:
# Code from module float:
# Code from module fnmatch:
@@ -66,7 +69,9 @@ AC_DEFUN([gl_EARLY],
# Code from module fpucw:
# Code from module frexp:
# Code from module frexpl:
+ # Code from module getlogin_r:
# Code from module gettimeofday:
+ # Code from module glob:
# Code from module hard-locale:
# Code from module include_next:
# Code from module inttypes:
@@ -87,10 +92,13 @@ AC_DEFUN([gl_EARLY],
# Code from module memchr:
# Code from module memmem:
# Code from module memmem-simple:
+ # Code from module mempcpy:
# Code from module multiarch:
# Code from module nocrash:
+ # Code from module opendir:
# Code from module pathmax:
# Code from module rawmemchr:
+ # Code from module readdir:
# Code from module readlink:
# Code from module rename:
# Code from module rmdir:
@@ -152,7 +160,13 @@ AC_DEFUN([gl_INIT],
gl_STDLIB_MODULE_INDICATOR([canonicalize_file_name])
gl_STDLIB_MODULE_INDICATOR([realpath])
gl_UNISTD_MODULE_INDICATOR([chdir])
+ gl_FUNC_CLOSEDIR
+ if test $HAVE_CLOSEDIR = 0 || test $REPLACE_CLOSEDIR = 1; then
+ AC_LIBOBJ([closedir])
+ fi
+ gl_DIRENT_MODULE_INDICATOR([closedir])
gl_CONFIGMAKE_PREP
+ gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE
gl_DIRENT_H
gl_FUNC_DIRFD
if test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no \
@@ -195,12 +209,23 @@ AC_DEFUN([gl_INIT],
AC_LIBOBJ([frexpl])
fi
gl_MATH_MODULE_INDICATOR([frexpl])
+ gl_FUNC_GETLOGIN_R
+ if test $HAVE_GETLOGIN_R = 0 || test $REPLACE_GETLOGIN_R = 1; then
+ AC_LIBOBJ([getlogin_r])
+ gl_PREREQ_GETLOGIN_R
+ fi
+ gl_UNISTD_MODULE_INDICATOR([getlogin_r])
gl_FUNC_GETTIMEOFDAY
if test $HAVE_GETTIMEOFDAY = 0 || test $REPLACE_GETTIMEOFDAY = 1; then
AC_LIBOBJ([gettimeofday])
gl_PREREQ_GETTIMEOFDAY
fi
gl_SYS_TIME_MODULE_INDICATOR([gettimeofday])
+ gl_GLOB
+ if test -n "$GLOB_H"; then
+ AC_LIBOBJ([glob])
+ gl_PREREQ_GLOB
+ fi
gl_HARD_LOCALE
gl_INTTYPES_H
gl_INTTYPES_INCOMPLETE
@@ -266,7 +291,18 @@ AC_DEFUN([gl_INIT],
AC_LIBOBJ([memmem])
fi
gl_STRING_MODULE_INDICATOR([memmem])
+ gl_FUNC_MEMPCPY
+ if test $HAVE_MEMPCPY = 0; then
+ AC_LIBOBJ([mempcpy])
+ gl_PREREQ_MEMPCPY
+ fi
+ gl_STRING_MODULE_INDICATOR([mempcpy])
gl_MULTIARCH
+ gl_FUNC_OPENDIR
+ if test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1; then
+ AC_LIBOBJ([opendir])
+ fi
+ gl_DIRENT_MODULE_INDICATOR([opendir])
gl_PATHMAX
gl_FUNC_RAWMEMCHR
if test $HAVE_RAWMEMCHR = 0; then
@@ -274,6 +310,11 @@ AC_DEFUN([gl_INIT],
gl_PREREQ_RAWMEMCHR
fi
gl_STRING_MODULE_INDICATOR([rawmemchr])
+ gl_FUNC_READDIR
+ if test $HAVE_READDIR = 0; then
+ AC_LIBOBJ([readdir])
+ fi
+ gl_DIRENT_MODULE_INDICATOR([readdir])
gl_FUNC_READLINK
if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
AC_LIBOBJ([readlink])
@@ -495,13 +536,16 @@ AC_DEFUN([gl_FILE_LIST], [
lib/alloca.in.h
lib/basename-lgpl.c
lib/canonicalize-lgpl.c
+ lib/closedir.c
lib/config.charset
+ lib/dirent-private.h
lib/dirent.in.h
lib/dirfd.c
lib/dirname-lgpl.c
lib/dirname.h
lib/dosname.h
lib/errno.in.h
+ lib/filename.h
lib/flexmember.h
lib/float+.h
lib/float.c
@@ -512,7 +556,11 @@ AC_DEFUN([gl_FILE_LIST], [
lib/fpucw.h
lib/frexp.c
lib/frexpl.c
+ lib/getlogin_r.c
lib/gettimeofday.c
+ lib/glob-libc.h
+ lib/glob.c
+ lib/glob.in.h
lib/hard-locale.c
lib/hard-locale.h
lib/inttypes.in.h
@@ -540,9 +588,12 @@ AC_DEFUN([gl_FILE_LIST], [
lib/memchr.c
lib/memchr.valgrind
lib/memmem.c
+ lib/mempcpy.c
+ lib/opendir.c
lib/pathmax.h
lib/rawmemchr.c
lib/rawmemchr.valgrind
+ lib/readdir.c
lib/readlink.c
lib/ref-add.sin
lib/ref-del.sin
@@ -582,8 +633,10 @@ AC_DEFUN([gl_FILE_LIST], [
m4/absolute-header.m4
m4/alloca.m4
m4/canonicalize.m4
+ m4/closedir.m4
m4/codeset.m4
m4/configmake.m4
+ m4/d-type.m4
m4/dirent_h.m4
m4/dirfd.m4
m4/dirname.m4
@@ -602,8 +655,10 @@ AC_DEFUN([gl_FILE_LIST], [
m4/fpieee.m4
m4/frexp.m4
m4/frexpl.m4
+ m4/getlogin_r.m4
m4/gettimeofday.m4
m4/glibc21.m4
+ m4/glob.m4
m4/gnulib-common.m4
m4/hard-locale.m4
m4/include_next.m4
@@ -628,12 +683,15 @@ AC_DEFUN([gl_FILE_LIST], [
m4/mbstate_t.m4
m4/memchr.m4
m4/memmem.m4
+ m4/mempcpy.m4
m4/mmap-anon.m4
m4/multiarch.m4
m4/nocrash.m4
m4/off_t.m4
+ m4/opendir.m4
m4/pathmax.m4
m4/rawmemchr.m4
+ m4/readdir.m4
m4/readlink.m4
m4/rename.m4
m4/rmdir.m4
diff --git a/gdb/gnulib/import/m4/mempcpy.m4 b/gdb/gnulib/import/m4/mempcpy.m4
new file mode 100644
index 0000000000..6991f29f03
--- /dev/null
+++ b/gdb/gnulib/import/m4/mempcpy.m4
@@ -0,0 +1,26 @@
+# mempcpy.m4 serial 11
+dnl Copyright (C) 2003-2004, 2006-2007, 2009-2016 Free Software Foundation,
+dnl Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MEMPCPY],
+[
+ dnl Persuade glibc <string.h> to declare mempcpy().
+ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+ dnl The mempcpy() declaration in lib/string.in.h uses 'restrict'.
+ AC_REQUIRE([AC_C_RESTRICT])
+
+ AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+ AC_CHECK_FUNCS([mempcpy])
+ if test $ac_cv_func_mempcpy = no; then
+ HAVE_MEMPCPY=0
+ fi
+])
+
+# Prerequisites of lib/mempcpy.c.
+AC_DEFUN([gl_PREREQ_MEMPCPY], [
+ :
+])
diff --git a/gdb/gnulib/import/m4/opendir.m4 b/gdb/gnulib/import/m4/opendir.m4
new file mode 100644
index 0000000000..ffaa6ae3ba
--- /dev/null
+++ b/gdb/gnulib/import/m4/opendir.m4
@@ -0,0 +1,31 @@
+# opendir.m4 serial 4
+dnl Copyright (C) 2011-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_OPENDIR],
+[
+ AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+
+ AC_CHECK_FUNCS([opendir])
+ if test $ac_cv_func_opendir = no; then
+ HAVE_OPENDIR=0
+ fi
+ dnl Replace opendir() for supporting the gnulib-defined fchdir() function,
+ dnl to keep fchdir's bookkeeping up-to-date.
+ m4_ifdef([gl_FUNC_FCHDIR], [
+ gl_TEST_FCHDIR
+ if test $HAVE_FCHDIR = 0; then
+ if test $HAVE_OPENDIR = 1; then
+ REPLACE_OPENDIR=1
+ fi
+ fi
+ ])
+ dnl Replace opendir() on OS/2 kLIBC to support dirfd() function replaced
+ dnl by gnulib.
+ case $host_os,$HAVE_OPENDIR in
+ os2*,1)
+ REPLACE_OPENDIR=1;;
+ esac
+])
diff --git a/gdb/gnulib/import/m4/readdir.m4 b/gdb/gnulib/import/m4/readdir.m4
new file mode 100644
index 0000000000..eda3acf73d
--- /dev/null
+++ b/gdb/gnulib/import/m4/readdir.m4
@@ -0,0 +1,15 @@
+# readdir.m4 serial 1
+dnl Copyright (C) 2011-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_READDIR],
+[
+ AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+
+ AC_CHECK_FUNCS([readdir])
+ if test $ac_cv_func_readdir = no; then
+ HAVE_READDIR=0
+ fi
+])
diff --git a/gdb/gnulib/import/mempcpy.c b/gdb/gnulib/import/mempcpy.c
new file mode 100644
index 0000000000..d579f64a0a
--- /dev/null
+++ b/gdb/gnulib/import/mempcpy.c
@@ -0,0 +1,28 @@
+/* Copy memory area and return pointer after last written byte.
+ Copyright (C) 2003, 2007, 2009-2016 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <string.h>
+
+/* Copy N bytes of SRC to DEST, return pointer to bytes after the
+ last written byte. */
+void *
+mempcpy (void *dest, const void *src, size_t n)
+{
+ return (char *) memcpy (dest, src, n) + n;
+}
diff --git a/gdb/gnulib/import/opendir.c b/gdb/gnulib/import/opendir.c
new file mode 100644
index 0000000000..a135fd834a
--- /dev/null
+++ b/gdb/gnulib/import/opendir.c
@@ -0,0 +1,169 @@
+/* Start reading the entries of a directory.
+ Copyright (C) 2006-2016 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <dirent.h>
+
+#include <errno.h>
+#include <stddef.h>
+
+#if HAVE_OPENDIR
+
+/* Override opendir(), to keep track of the open file descriptors.
+ Needed because there is a function dirfd(). */
+
+#else
+
+# include <stdlib.h>
+
+# include "dirent-private.h"
+# include "filename.h"
+
+#endif
+
+#if REPLACE_FCHDIR
+# include <unistd.h>
+#endif
+
+#ifdef __KLIBC__
+# include <io.h>
+# include <fcntl.h>
+#endif
+
+DIR *
+opendir (const char *dir_name)
+{
+#if HAVE_OPENDIR
+# undef opendir
+ DIR *dirp;
+
+ dirp = opendir (dir_name);
+ if (dirp == NULL)
+ return NULL;
+
+# ifdef __KLIBC__
+ {
+ int fd = open (dir_name, O_RDONLY);
+ if (fd == -1 || _gl_register_dirp_fd (fd, dirp))
+ {
+ int saved_errno = errno;
+
+ close (fd);
+ closedir (dirp);
+
+ errno = saved_errno;
+
+ return NULL;
+ }
+ }
+# endif
+#else
+
+ char dir_name_mask[MAX_PATH + 1 + 1 + 1];
+ int status;
+ HANDLE current;
+ WIN32_FIND_DATA entry;
+ struct gl_directory *dirp;
+
+ if (dir_name[0] == '\0')
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ /* Make the dir_name absolute, so that we continue reading the same
+ directory if the current directory changed between this opendir()
+ call and a subsequent rewinddir() call. */
+ if (!GetFullPathName (dir_name, MAX_PATH, dir_name_mask, NULL))
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Append the mask.
+ "*" and "*.*" appear to be equivalent. */
+ {
+ char *p;
+
+ p = dir_name_mask + strlen (dir_name_mask);
+ if (p > dir_name_mask && !ISSLASH (p[-1]))
+ *p++ = '\\';
+ *p++ = '*';
+ *p = '\0';
+ }
+
+ /* Start searching the directory. */
+ status = -1;
+ current = FindFirstFile (dir_name_mask, &entry);
+ if (current == INVALID_HANDLE_VALUE)
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_FILE_NOT_FOUND:
+ status = -2;
+ break;
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ return NULL;
+ case ERROR_DIRECTORY:
+ errno = ENOTDIR;
+ return NULL;
+ case ERROR_ACCESS_DENIED:
+ errno = EACCES;
+ return NULL;
+ default:
+ errno = EIO;
+ return NULL;
+ }
+ }
+
+ /* Allocate the result. */
+ dirp =
+ (struct gl_directory *)
+ malloc (offsetof (struct gl_directory, dir_name_mask[0])
+ + strlen (dir_name_mask) + 1);
+ if (dirp == NULL)
+ {
+ if (current != INVALID_HANDLE_VALUE)
+ FindClose (current);
+ errno = ENOMEM;
+ return NULL;
+ }
+ dirp->status = status;
+ dirp->current = current;
+ if (status == -1)
+ memcpy (&dirp->entry, &entry, sizeof (WIN32_FIND_DATA));
+ strcpy (dirp->dir_name_mask, dir_name_mask);
+
+#endif
+
+#if REPLACE_FCHDIR
+ {
+ int fd = dirfd (dirp);
+ if (0 <= fd && _gl_register_fd (fd, dir_name) != fd)
+ {
+ int saved_errno = errno;
+ closedir (dirp);
+ errno = saved_errno;
+ return NULL;
+ }
+ }
+#endif
+
+ return dirp;
+}
diff --git a/gdb/gnulib/import/readdir.c b/gdb/gnulib/import/readdir.c
new file mode 100644
index 0000000000..76b7e9d819
--- /dev/null
+++ b/gdb/gnulib/import/readdir.c
@@ -0,0 +1,98 @@
+/* Read the next entry of a directory.
+ Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <dirent.h>
+
+#include <errno.h>
+#include <stddef.h>
+
+#include "dirent-private.h"
+
+struct dirent *
+readdir (DIR *dirp)
+{
+ char type;
+ struct dirent *result;
+
+ /* There is no need to add code to produce entries for "." and "..".
+ According to the POSIX:2008 section "4.12 Pathname Resolution"
+ <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html>
+ "." and ".." are syntactic entities.
+ POSIX also says:
+ "If entries for dot or dot-dot exist, one entry shall be returned
+ for dot and one entry shall be returned for dot-dot; otherwise,
+ they shall not be returned." */
+
+ switch (dirp->status)
+ {
+ case -2:
+ /* End of directory already reached. */
+ return NULL;
+ case -1:
+ break;
+ case 0:
+ if (!FindNextFile (dirp->current, &dirp->entry))
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_NO_MORE_FILES:
+ dirp->status = -2;
+ return NULL;
+ default:
+ errno = EIO;
+ return NULL;
+ }
+ }
+ break;
+ default:
+ errno = dirp->status;
+ return NULL;
+ }
+
+ dirp->status = 0;
+
+ if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ type = DT_DIR;
+ else if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ type = DT_LNK;
+ else if ((dirp->entry.dwFileAttributes
+ & ~(FILE_ATTRIBUTE_READONLY
+ | FILE_ATTRIBUTE_HIDDEN
+ | FILE_ATTRIBUTE_SYSTEM
+ | FILE_ATTRIBUTE_ARCHIVE
+ | FILE_ATTRIBUTE_NORMAL
+ | FILE_ATTRIBUTE_TEMPORARY
+ | FILE_ATTRIBUTE_SPARSE_FILE
+ | FILE_ATTRIBUTE_COMPRESSED
+ | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
+ | FILE_ATTRIBUTE_ENCRYPTED)) == 0)
+ /* Devices like COM1, LPT1, NUL would also have the attributes 0x20 but
+ they cannot occur here. */
+ type = DT_REG;
+ else
+ type = DT_UNKNOWN;
+
+ /* Reuse the memory of dirp->entry for the result. */
+ result =
+ (struct dirent *)
+ ((char *) dirp->entry.cFileName - offsetof (struct dirent, d_name[0]));
+ result->d_type = type;
+
+ return result;
+}
diff --git a/gdb/gnulib/update-gnulib.sh b/gdb/gnulib/update-gnulib.sh
index 2775dc7338..ccf603fceb 100755
--- a/gdb/gnulib/update-gnulib.sh
+++ b/gdb/gnulib/update-gnulib.sh
@@ -37,6 +37,7 @@ IMPORTED_GNULIB_MODULES="\
errno \
fnmatch-gnu \
frexpl \
+ glob \
inttypes \
lstat \
limits-h \
--
2.13.3
Eli Zaretskii
2017-09-12 14:55:28 UTC
Permalink
Date: Tue, 12 Sep 2017 00:23:21 -0400
https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html
It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
is a GDB-only command for now; its gdbserver counterpart will come
later.
Can you summarize the idea, please? (I didn't follow that
discussion.) Do we chdir into that directory each time before we
run/resume the debuggee? Or do we use the shell (in which case this
is limited to Posix hosts)? Or something else?

Thanks.
Sergio Durigan Junior
2017-09-12 16:48:05 UTC
Permalink
Post by Eli Zaretskii
Date: Tue, 12 Sep 2017 00:23:21 -0400
https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html
It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
is a GDB-only command for now; its gdbserver counterpart will come
later.
Can you summarize the idea, please? (I didn't follow that
discussion.) Do we chdir into that directory each time before we
run/resume the debuggee? Or do we use the shell (in which case this
is limited to Posix hosts)? Or something else?
Sure.

The idea is that there are other inferior commands already, like "set
args" or "set environment", which function per-inferior. However, the
current "cd" command doesn't, and this is not only a discrepancy but
also gets in the way of a future feature that will implemented: the
ability to tell gdbserver to cd into another directory before starting
the remote inferior.

GDB's cd_command uses chdir, but also uses tilde_expand, from readline,
to expand the path given by the user. It also runs right when the user
invokes "cd" from the CLI.

The new "set cwd" command also uses chdir (i.e., no shell involved), but
because it is shared code between GDB and gdbserver, and because
gdbserver doesn't link against readline, it cannot use tilde_expand.
Therefore I had to import the "glob" module from gnulib. And also, this
specific chdir is only invoked after the call to fork/vfork on
fork_inferior, but before we actually execute the binary.

I hope I could clarify this for you, but please let me know if you have
more questions.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Eli Zaretskii
2017-09-12 16:56:54 UTC
Permalink
Date: Tue, 12 Sep 2017 12:48:05 -0400
The new "set cwd" command also uses chdir (i.e., no shell involved), but
because it is shared code between GDB and gdbserver, and because
gdbserver doesn't link against readline, it cannot use tilde_expand.
Therefore I had to import the "glob" module from gnulib. And also, this
specific chdir is only invoked after the call to fork/vfork on
fork_inferior, but before we actually execute the binary.
Thanks.

The last bit means that this will only work for targets that use
fork/vfork, i.e. only for Posix targets. Right?
Sergio Durigan Junior
2017-09-12 17:51:36 UTC
Permalink
Post by Eli Zaretskii
Date: Tue, 12 Sep 2017 12:48:05 -0400
The new "set cwd" command also uses chdir (i.e., no shell involved), but
because it is shared code between GDB and gdbserver, and because
gdbserver doesn't link against readline, it cannot use tilde_expand.
Therefore I had to import the "glob" module from gnulib. And also, this
specific chdir is only invoked after the call to fork/vfork on
fork_inferior, but before we actually execute the binary.
Thanks.
The last bit means that this will only work for targets that use
fork/vfork, i.e. only for Posix targets. Right?
Well, the way it's implemented, yes. AFAIK there's nothing preventing
this feature to be implemented in non-vfork targets like Windows, except
the fact that I don't have access to those targets to test.
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-13 14:59:52 UTC
Permalink
Post by Sergio Durigan Junior
Post by Eli Zaretskii
Date: Tue, 12 Sep 2017 12:48:05 -0400
The new "set cwd" command also uses chdir (i.e., no shell involved), but
because it is shared code between GDB and gdbserver, and because
gdbserver doesn't link against readline, it cannot use tilde_expand.
Therefore I had to import the "glob" module from gnulib. And also, this
specific chdir is only invoked after the call to fork/vfork on
fork_inferior, but before we actually execute the binary.
Thanks.
The last bit means that this will only work for targets that use
fork/vfork, i.e. only for Posix targets. Right?
Well, the way it's implemented, yes. AFAIK there's nothing preventing
this feature to be implemented in non-vfork targets like Windows, except
the fact that I don't have access to those targets to test.
I think that to make "set cwd" work on Windows, gdb would be adjusted to
pass the desired current directory as argument to CreateProcess, here:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/windows-nat.c;h=ab5582d46cf3a0873ab32d9c955e95ee75371d4e;hb=HEAD#l2570

(and the equivalent in gdbserver).

From <https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx>:

~~~
lpCurrentDirectory [in, optional]

The full path to the current directory for the process. The string can also specify a UNC path.

If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
~~~

Thanks,
Pedro Alves
Eli Zaretskii
2017-09-13 15:05:52 UTC
Permalink
Date: Wed, 13 Sep 2017 15:59:52 +0100
Post by Sergio Durigan Junior
Post by Eli Zaretskii
The last bit means that this will only work for targets that use
fork/vfork, i.e. only for Posix targets. Right?
Well, the way it's implemented, yes. AFAIK there's nothing preventing
this feature to be implemented in non-vfork targets like Windows, except
the fact that I don't have access to those targets to test.
I think that to make "set cwd" work on Windows, gdb would be adjusted to
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/windows-nat.c;h=ab5582d46cf3a0873ab32d9c955e95ee75371d4e;hb=HEAD#l2570
(and the equivalent in gdbserver).
Yes.
Sergio Durigan Junior
2017-09-13 21:56:39 UTC
Permalink
Date: Wed, 13 Sep 2017 15:59:52 +0100
Post by Sergio Durigan Junior
Post by Eli Zaretskii
The last bit means that this will only work for targets that use
fork/vfork, i.e. only for Posix targets. Right?
Well, the way it's implemented, yes. AFAIK there's nothing preventing
this feature to be implemented in non-vfork targets like Windows, except
the fact that I don't have access to those targets to test.
I think that to make "set cwd" work on Windows, gdb would be adjusted to
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/windows-nat.c;h=ab5582d46cf3a0873ab32d9c955e95ee75371d4e;hb=HEAD#l2570
(and the equivalent in gdbserver).
Yes.
Thanks, that makes things easier.
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-13 14:54:01 UTC
Permalink
Post by Sergio Durigan Junior
https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html
It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
is a GDB-only command for now; its gdbserver counterpart will come
later.
I think I'd prefer that the gdbserver counterpart was included
as part of the same series. I.e., I'd like to see the gdbserver
side explored first before we change the native side and commit
to the commands/interface. Also, I think that would help make
sure that the manual documentation is adjusted in a way that
naturally reads as applying to local and remote.

For example, we currently say

"Each time you start your program with @code{run}, it inherits its
working directory from the current working directory of
@value{GDBN}.",

but you didn't change that particular sentence, which seems to leave
it a bit incorrect. I think we should say instead say that
when you start your program with run, the inferior starts with
the directory specified by "set cwd", and then mention that
if that is not set, then the inferior inherits gdb's current
directory if native debugging, and gdbserver's if remote debugging.
Right?

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-13 21:54:15 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html
It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
is a GDB-only command for now; its gdbserver counterpart will come
later.
I think I'd prefer that the gdbserver counterpart was included
as part of the same series. I.e., I'd like to see the gdbserver
side explored first before we change the native side and commit
to the commands/interface. Also, I think that would help make
sure that the manual documentation is adjusted in a way that
naturally reads as applying to local and remote.
Fair enough.

I wasn't sure if I should submit the gdbserver part as well, of just the
GDB one. I opted to just touch GDB because we usually choose to go
"baby steps" on things.
Post by Pedro Alves
For example, we currently say
working directory from the current working directory of
@value{GDBN}.",
but you didn't change that particular sentence, which seems to leave
it a bit incorrect. I think we should say instead say that
when you start your program with run, the inferior starts with
the directory specified by "set cwd", and then mention that
if that is not set, then the inferior inherits gdb's current
directory if native debugging, and gdbserver's if remote debugging.
Right?
Yeah, maybe I should rewrite this sentence indeed. It's not entirely
true. Thanks for catching that.

As I said, I will prepare a patch series containing the gdbserver
modifications and will submit it, along with the other changes you
proposed in the other e-mails.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-19 04:28:37 UTC
Permalink
Changes from v1:

- The patch is now importing the "getcwd" module from gnulib as well
as the "glob" one.

- Improved the "gdb_dirbuf removal" patch (patch #2) by making use of
"getcwd (NULL, 0)" instead of a fixed-length buffer to be passed to
"getcwd".

- Fixed and improved a few things on the "gdb_chdir patch" (patch #3),
mainly the "expand_path" function name (which is now named
"gdb_tilde_expand"), and the lack of a RAII wrapper around "glob" to
make things exception-safe. I decided not to use "gdb_tilde_expand"
globally on GDB for now; there are just too many places that use it
and I prefer to make this conversion later.

- Added gdbserver changes (patch #5), which hopefully makes it easier
to see the feature in the "bigger picture".


This patch series is a followup of the discussion that happened at:

https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html

It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
command works for both native and remote debugging scenarios.

The idea here is that "set cwd" will become the de facto way of
setting the inferior's cwd. Currently, the user can use "cd" for
that, but there are side effects: with "cd", GDB also switches to
another directory, and that can impact the loading of scripts and
other files. With "set cwd", we separate the logic into a new
command.

To maintain backward compatibility, if the user issues a "cd" command
but doesn't use "set cwd", then the inferior's cwd will still be
changed according to what the user specified. However, "set cwd" has
precedence over "cd", so it can always be used to override it.
Sergio Durigan Junior
2017-09-19 04:28:39 UTC
Permalink
Currently we have "current_directory" and "gdb_dirbuf" globals, which
means that we basically have two possible places to consult when we
want to know GDB's current working directory.

This is not ideal and can lead to confusion. Moreover, the way we're
using "gdb_difbuf" along with "getcwd" is problematic because we
declare the buffer with "1024" elements hardcoded, which does not take
into account longer pathnames that are possible in many filesystems.
Using "PATH_MAX" would also not be a solution because of portability
problems. Therefore, the best solution is to rely on the fact that
"getcwd (NULL, 0)" will "do the right thing" and return a
heap-allocated string containing the full path. With the new "getcwd"
module from gnulib, it is now possible to do that without worrying
about breaking some target.

With this patch "current_directory" is now the only place to check for
GDB's cwd.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* cli/cli-cmds.c (pwd_command): Use "getcwd (NULL, 0)".
(cd_command): Likewise. Free "current_directory" before
assigning to it.
* main.c (captured_main_1): Use "getcwd (NULL, 0)".
* mi/mi-cmd-env.c (mi_cmd_env_pwd): Likewise.
* top.c (gdb_dirbuf): Remove global declaration.
* top.h (gdb_dirbuf): Likewise.
---
gdb/cli/cli-cmds.c | 17 ++++++++++++-----
gdb/main.c | 5 ++---
gdb/mi/mi-cmd-env.c | 8 ++++----
gdb/top.c | 3 ---
gdb/top.h | 1 -
5 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 883844ee70..85d6d21113 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -382,13 +382,16 @@ pwd_command (char *args, int from_tty)
{
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+
+ if (cwd.get () == NULL)
error (_("Error finding name of working directory: %s"),
safe_strerror (errno));

- if (strcmp (gdb_dirbuf, current_directory) != 0)
+ if (strcmp (cwd.get (), current_directory) != 0)
printf_unfiltered (_("Working directory %s\n (canonically %s).\n"),
- current_directory, gdb_dirbuf);
+ current_directory, cwd.get ());
else
printf_unfiltered (_("Working directory %s.\n"), current_directory);
}
@@ -416,7 +419,8 @@ cd_command (char *dir, int from_tty)
/* There's too much mess with DOSish names like "d:", "d:.",
"d:./foo" etc. Instead of having lots of special #ifdef'ed code,
simply get the canonicalized name of the current directory. */
- dir = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ dir = cwd.get ();
#endif

len = strlen (dir);
@@ -434,7 +438,10 @@ cd_command (char *dir, int from_tty)

dir_holder.reset (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
- current_directory = dir_holder.release ();
+ {
+ xfree (current_directory);
+ current_directory = dir_holder.release ();
+ }
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
diff --git a/gdb/main.c b/gdb/main.c
index a0646edad6..8693781825 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -549,11 +549,10 @@ captured_main_1 (struct captured_main_args *context)
(xstrprintf ("%s: warning: ", gdb_program_name));
warning_pre_print = tmp_warn_preprint.get ();

- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+ current_directory = getcwd (NULL, 0);
+ if (current_directory == NULL)
perror_warning_with_name (_("error finding working directory"));

- current_directory = gdb_dirbuf;
-
/* Set the sysroot path. */
gdb_sysroot = relocate_gdb_directory (TARGET_SYSTEM_ROOT,
TARGET_SYSTEM_ROOT_RELOCATABLE);
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 977b6e274d..1e4c09352f 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -73,12 +73,12 @@ mi_cmd_env_pwd (const char *command, char **argv, int argc)
}

/* Otherwise the mi level is 2 or higher. */
-
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ if (cwd.get () == NULL)
error (_("-environment-pwd: error finding name of working directory: %s"),
safe_strerror (errno));
-
- uiout->field_string ("cwd", gdb_dirbuf);
+
+ uiout->field_string ("cwd", cwd.get ());
}

/* Change working directory. */
diff --git a/gdb/top.c b/gdb/top.c
index 742c1e7a07..0f36dce760 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -133,9 +133,6 @@ show_confirm (struct ui_file *file, int from_tty,

char *current_directory;

-/* The directory name is actually stored here (usually). */
-char gdb_dirbuf[1024];
-
/* The last command line executed on the console. Used for command
repetitions. */
char *saved_command_line;
diff --git a/gdb/top.h b/gdb/top.h
index 45798897f6..6b66083995 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -219,7 +219,6 @@ extern void ui_unregister_input_event_handler (struct ui *ui);
/* From top.c. */
extern char *saved_command_line;
extern int confirm;
-extern char gdb_dirbuf[1024];
extern int inhibit_gdbinit;
extern const char gdbinit[];
--
2.13.3
Pedro Alves
2017-09-20 12:24:41 UTC
Permalink
Post by Sergio Durigan Junior
Currently we have "current_directory" and "gdb_dirbuf" globals, which
means that we basically have two possible places to consult when we
want to know GDB's current working directory.
This is not ideal and can lead to confusion. Moreover, the way we're
using "gdb_difbuf" along with "getcwd" is problematic because we
declare the buffer with "1024" elements hardcoded, which does not take
into account longer pathnames that are possible in many filesystems.
Using "PATH_MAX" would also not be a solution because of portability
problems. Therefore, the best solution is to rely on the fact that
"getcwd (NULL, 0)" will "do the right thing" and return a
heap-allocated string containing the full path. With the new "getcwd"
module from gnulib, it is now possible to do that without worrying
about breaking some target.
s/target/host/
Post by Sergio Durigan Junior
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -382,13 +382,16 @@ pwd_command (char *args, int from_tty)
{
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+
+ if (cwd.get () == NULL)
No need for get() here:

if (cwd == NULL)
Post by Sergio Durigan Junior
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 977b6e274d..1e4c09352f 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -73,12 +73,12 @@ mi_cmd_env_pwd (const char *command, char **argv, int argc)
}
/* Otherwise the mi level is 2 or higher. */
-
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ if (cwd.get () == NULL)
Ditto.

Otherwise OK.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-20 17:02:51 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Currently we have "current_directory" and "gdb_dirbuf" globals, which
means that we basically have two possible places to consult when we
want to know GDB's current working directory.
This is not ideal and can lead to confusion. Moreover, the way we're
using "gdb_difbuf" along with "getcwd" is problematic because we
declare the buffer with "1024" elements hardcoded, which does not take
into account longer pathnames that are possible in many filesystems.
Using "PATH_MAX" would also not be a solution because of portability
problems. Therefore, the best solution is to rely on the fact that
"getcwd (NULL, 0)" will "do the right thing" and return a
heap-allocated string containing the full path. With the new "getcwd"
module from gnulib, it is now possible to do that without worrying
about breaking some target.
s/target/host/
Fixed.
Post by Pedro Alves
Post by Sergio Durigan Junior
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -382,13 +382,16 @@ pwd_command (char *args, int from_tty)
{
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+
+ if (cwd.get () == NULL)
if (cwd == NULL)
Fixed.
Post by Pedro Alves
Post by Sergio Durigan Junior
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 977b6e274d..1e4c09352f 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -73,12 +73,12 @@ mi_cmd_env_pwd (const char *command, char **argv, int argc)
}
/* Otherwise the mi level is 2 or higher. */
-
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ if (cwd.get () == NULL)
Ditto.
Fixed.
Post by Pedro Alves
Otherwise OK.
Thanks,
Pedro Alves
I'll wait until the other patches are approved to push this one, since
it depends on gnulib's getcwd.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-19 04:28:40 UTC
Permalink
In order to be able to change the inferior's directory before its
execution, it is necessary to perform a tilde expansion of the
directory provided by the user and then chdir into the resulting dir.
This is what gdb_chdir does.

Unfortunately it is not possible to use "tilde_expand" from readline
because this is common code and gdbserver doesn't use readline. For
that reason I decided to go with "glob" and its GNU extension,
GLOB_TILDE. With the import of the "glob" module from gnulib, this is
a no-brainer.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add gdb_chdir.c.
(HFILES_NO_SRCDIR): Add gdb_chdir.h.
(COMMON_OBS): Add gdb_chdir.o.
* cli/cli-cmds.c: Include "gdb_chdir.h".
(cd_command): Use "gdb_chdir" instead of "tilde_expand
plus chdir".
* common/gdb_chdir.c: New file.
* common/gdb_chdir.h: Likewise.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add $(srcdir)/common/gdb_chdir.c.
(OBS): Add gdb_chdir.o.
---
gdb/Makefile.in | 3 ++
gdb/cli/cli-cmds.c | 20 +++++-----
gdb/common/gdb_chdir.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++
gdb/common/gdb_chdir.h | 26 +++++++++++++
gdb/gdbserver/Makefile.in | 2 +
5 files changed, 136 insertions(+), 11 deletions(-)
create mode 100644 gdb/common/gdb_chdir.c
create mode 100644 gdb/common/gdb_chdir.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9dfc117b2f..1f093e6c0f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1245,6 +1245,7 @@ SFILES = \
common/filestuff.c \
common/format.c \
common/job-control.c \
+ common/gdb_chdir.c \
common/gdb_vecs.c \
common/new-op.c \
common/print-utils.c \
@@ -1529,6 +1530,7 @@ HFILES_NO_SRCDIR = \
common/fileio.h \
common/format.h \
common/gdb_assert.h \
+ common/gdb_chdir.h \
common/gdb_locale.h \
common/gdb_setjmp.h \
common/gdb_signals.h \
@@ -1734,6 +1736,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
frame-unwind.o \
gcore.o \
gdb_bfd.o \
+ gdb_chdir.o \
gdb-dlfcn.o \
gdb_obstack.o \
gdb_regex.o \
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 85d6d21113..653dd56a64 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -54,6 +54,8 @@
#include "tui/tui.h" /* For tui_active et.al. */
#endif

+#include "gdb_chdir.h"
+
#include <fcntl.h>
#include <algorithm>
#include <string>
@@ -408,12 +410,7 @@ cd_command (char *dir, int from_tty)
repeat might be useful but is more likely to be a mistake. */
dont_repeat ();

- gdb::unique_xmalloc_ptr<char> dir_holder
- (tilde_expand (dir != NULL ? dir : "~"));
- dir = dir_holder.get ();
-
- if (chdir (dir) < 0)
- perror_with_name (dir);
+ gdb_chdir (dir != NULL ? dir : "~");

#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* There's too much mess with DOSish names like "d:", "d:.",
@@ -436,20 +433,21 @@ cd_command (char *dir, int from_tty)
len--;
}

- dir_holder.reset (savestring (dir, len));
- if (IS_ABSOLUTE_PATH (dir_holder.get ()))
+ std::string newdir = std::string (dir, len);
+ const char *newdir_str = newdir.c_str ();
+ if (IS_ABSOLUTE_PATH (newdir_str))
{
xfree (current_directory);
- current_directory = dir_holder.release ();
+ current_directory = xstrdup (newdir_str);
}
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
- current_directory = concat (current_directory, dir_holder.get (),
+ current_directory = concat (current_directory, newdir_str,
(char *) NULL);
else
current_directory = concat (current_directory, SLASH_STRING,
- dir_holder.get (), (char *) NULL);
+ newdir_str, (char *) NULL);
}

/* Now simplify any occurrences of `.' and `..' in the pathname. */
diff --git a/gdb/common/gdb_chdir.c b/gdb/common/gdb_chdir.c
new file mode 100644
index 0000000000..6eebeb2d02
--- /dev/null
+++ b/gdb/common/gdb_chdir.c
@@ -0,0 +1,96 @@
+/* chdir(2) wrapper for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "common-defs.h"
+#include "gdb_chdir.h"
+#include <glob.h>
+
+/* RAII-style class wrapping "glob". */
+
+class gdb_glob
+{
+public:
+ /* Construct a "gdb_glob" object by calling "glob" with the provided
+ parameters. This function can throw if "glob" fails. */
+ gdb_glob (const char *pattern, int flags,
+ int (*errfunc) (const char *epath, int eerrno))
+ {
+ int ret = glob (pattern, flags, errfunc, &m_glob);
+
+ if (ret != 0)
+ {
+ if (ret == GLOB_NOMATCH)
+ error (_("Could not find a match for '%s'."), pattern);
+ else
+ error (_("glob could not process pattern '%s'."),
+ pattern);
+ }
+ }
+
+ /* Destroy the object and free M_GLOB. */
+ ~gdb_glob ()
+ {
+ globfree (&m_glob);
+ }
+
+ /* Return the GL_PATHC component of M_GLOB. */
+ int
+ pathc () const
+ {
+ return m_glob.gl_pathc;
+ }
+
+ /* Return the GL_PATHV component of M_GLOB. */
+ char **
+ pathv () const
+ {
+ return m_glob.gl_pathv;
+ }
+
+private:
+ /* The actual glob object we're dealing with. */
+ glob_t m_glob;
+};
+
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+
+static std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
+
+ gdb_assert (glob.pathc () > 0);
+ /* "glob" may return more than one match to the path provided by the
+ user, but we are only interested in the first match. */
+ std::string expanded_dir = glob.pathv ()[0];
+
+ return expanded_dir;
+}
+
+/* See gdb_chdir.h. */
+
+void
+gdb_chdir (const char *dir)
+{
+ std::string expanded_dir = gdb_tilde_expand (dir);
+
+ if (chdir (expanded_dir.c_str ()) < 0)
+ perror_with_name (expanded_dir.c_str ());
+}
diff --git a/gdb/common/gdb_chdir.h b/gdb/common/gdb_chdir.h
new file mode 100644
index 0000000000..5e6253e3b5
--- /dev/null
+++ b/gdb/common/gdb_chdir.h
@@ -0,0 +1,26 @@
+/* chdir(2) wrapper for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef HAVE_GDB_CHDIR_H
+#define HAVE_GDB_CHDIR_H
+
+/* Perform a "chdir" to DIR, doing the proper tilde expansion before. */
+extern void gdb_chdir (const char *dir);
+
+#endif /* ! HAVE_GDB_CHDIR_H */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1bbe515629..ecd12a7dcc 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -205,6 +205,7 @@ SFILES = \
$(srcdir)/common/fileio.c \
$(srcdir)/common/filestuff.c \
$(srcdir)/common/job-control.c \
+ $(srcdir)/common/gdb_chdir.c \
$(srcdir)/common/gdb_vecs.c \
$(srcdir)/common/new-op.c \
$(srcdir)/common/print-utils.c \
@@ -247,6 +248,7 @@ OBS = \
fileio.o \
filestuff.o \
format.o \
+ gdb_chdir.o \
gdb_vecs.o \
hostio.o \
inferiors.o \
--
2.13.3
Pedro Alves
2017-09-20 13:14:39 UTC
Permalink
Post by Sergio Durigan Junior
In order to be able to change the inferior's directory before its
execution, it is necessary to perform a tilde expansion of the
directory provided by the user and then chdir into the resulting dir.
This is what gdb_chdir does.
Unfortunately it is not possible to use "tilde_expand" from readline
because this is common code and gdbserver doesn't use readline. For
that reason I decided to go with "glob" and its GNU extension,
GLOB_TILDE. With the import of the "glob" module from gnulib, this is
a no-brainer.
* Makefile.in (SFILES): Add gdb_chdir.c.
(HFILES_NO_SRCDIR): Add gdb_chdir.h.
(COMMON_OBS): Add gdb_chdir.o.
* cli/cli-cmds.c: Include "gdb_chdir.h".
(cd_command): Use "gdb_chdir" instead of "tilde_expand
plus chdir".
* common/gdb_chdir.c: New file.
* common/gdb_chdir.h: Likewise.
* Makefile.in (SFILES): Add $(srcdir)/common/gdb_chdir.c.
(OBS): Add gdb_chdir.o.
---
gdb/Makefile.in | 3 ++
gdb/cli/cli-cmds.c | 20 +++++-----
gdb/common/gdb_chdir.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++
gdb/common/gdb_chdir.h | 26 +++++++++++++
gdb/gdbserver/Makefile.in | 2 +
5 files changed, 136 insertions(+), 11 deletions(-)
create mode 100644 gdb/common/gdb_chdir.c
create mode 100644 gdb/common/gdb_chdir.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9dfc117b2f..1f093e6c0f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1245,6 +1245,7 @@ SFILES = \
common/filestuff.c \
common/format.c \
common/job-control.c \
+ common/gdb_chdir.c \
common/gdb_vecs.c \
common/new-op.c \
common/print-utils.c \
@@ -1529,6 +1530,7 @@ HFILES_NO_SRCDIR = \
common/fileio.h \
common/format.h \
common/gdb_assert.h \
+ common/gdb_chdir.h \
common/gdb_locale.h \
common/gdb_setjmp.h \
common/gdb_signals.h \
@@ -1734,6 +1736,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
frame-unwind.o \
gcore.o \
gdb_bfd.o \
+ gdb_chdir.o \
gdb-dlfcn.o \
gdb_obstack.o \
gdb_regex.o \
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 85d6d21113..653dd56a64 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -54,6 +54,8 @@
#include "tui/tui.h" /* For tui_active et.al. */
#endif
+#include "gdb_chdir.h"
+
#include <fcntl.h>
#include <algorithm>
#include <string>
@@ -408,12 +410,7 @@ cd_command (char *dir, int from_tty)
repeat might be useful but is more likely to be a mistake. */
dont_repeat ();
- gdb::unique_xmalloc_ptr<char> dir_holder
- (tilde_expand (dir != NULL ? dir : "~"));
- dir = dir_holder.get ();
-
- if (chdir (dir) < 0)
- perror_with_name (dir);
+ gdb_chdir (dir != NULL ? dir : "~");
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* There's too much mess with DOSish names like "d:", "d:.",
@@ -436,20 +433,21 @@ cd_command (char *dir, int from_tty)
len--;
}
- dir_holder.reset (savestring (dir, len));
- if (IS_ABSOLUTE_PATH (dir_holder.get ()))
+ std::string newdir = std::string (dir, len);
+ const char *newdir_str = newdir.c_str ();
+ if (IS_ABSOLUTE_PATH (newdir_str))
{
xfree (current_directory);
- current_directory = dir_holder.release ();
+ current_directory = xstrdup (newdir_str);
This introduces one extra deep string dup. One to
construct the std::string, and another here in this xstrdup.

How about simply, above:

- dir_holder.reset (savestring (dir, len));
+ gdb::unique_xmalloc_ptr<char> dir_holder (savestring (dir, len))


But more importantly, isn't there a behavior change here?
Before, current_directory would be a copy of the the expand
path, while after the patch, it's a copy of the input string,
before expansion. Right?
Post by Sergio Durigan Junior
}
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
- current_directory = concat (current_directory, dir_holder.get (),
+ current_directory = concat (current_directory, newdir_str,
(char *) NULL);
else
current_directory = concat (current_directory, SLASH_STRING,
- dir_holder.get (), (char *) NULL);
+ newdir_str, (char *) NULL);
}
+ /* Destroy the object and free M_GLOB. */
+ ~gdb_glob ()
+ {
+ globfree (&m_glob);
+ }
+
+ /* Return the GL_PATHC component of M_GLOB. */
+ int
+ pathc () const
+ {
+ return m_glob.gl_pathc;
+ }
We've been putting type and function name in the
same line in inline member functions. That's the
de facto standard in GCC as well, AFAICS.
Post by Sergio Durigan Junior
+
+ /* Return the GL_PATHV component of M_GLOB. */
+ char **
+ pathv () const
+ {
+ return m_glob.gl_pathv;
+ }
Ditto.
Post by Sergio Durigan Junior
+#ifndef HAVE_GDB_CHDIR_H
+#define HAVE_GDB_CHDIR_H
+
+/* Perform a "chdir" to DIR, doing the proper tilde expansion before. */
+extern void gdb_chdir (const char *dir);
Nit, I'd drop "the proper", as it doesn't see to add value.
I.e., what's proper and what's not proper?

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-20 17:25:01 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
In order to be able to change the inferior's directory before its
execution, it is necessary to perform a tilde expansion of the
directory provided by the user and then chdir into the resulting dir.
This is what gdb_chdir does.
Unfortunately it is not possible to use "tilde_expand" from readline
because this is common code and gdbserver doesn't use readline. For
that reason I decided to go with "glob" and its GNU extension,
GLOB_TILDE. With the import of the "glob" module from gnulib, this is
a no-brainer.
* Makefile.in (SFILES): Add gdb_chdir.c.
(HFILES_NO_SRCDIR): Add gdb_chdir.h.
(COMMON_OBS): Add gdb_chdir.o.
* cli/cli-cmds.c: Include "gdb_chdir.h".
(cd_command): Use "gdb_chdir" instead of "tilde_expand
plus chdir".
* common/gdb_chdir.c: New file.
* common/gdb_chdir.h: Likewise.
* Makefile.in (SFILES): Add $(srcdir)/common/gdb_chdir.c.
(OBS): Add gdb_chdir.o.
---
gdb/Makefile.in | 3 ++
gdb/cli/cli-cmds.c | 20 +++++-----
gdb/common/gdb_chdir.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++
gdb/common/gdb_chdir.h | 26 +++++++++++++
gdb/gdbserver/Makefile.in | 2 +
5 files changed, 136 insertions(+), 11 deletions(-)
create mode 100644 gdb/common/gdb_chdir.c
create mode 100644 gdb/common/gdb_chdir.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9dfc117b2f..1f093e6c0f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1245,6 +1245,7 @@ SFILES = \
common/filestuff.c \
common/format.c \
common/job-control.c \
+ common/gdb_chdir.c \
common/gdb_vecs.c \
common/new-op.c \
common/print-utils.c \
@@ -1529,6 +1530,7 @@ HFILES_NO_SRCDIR = \
common/fileio.h \
common/format.h \
common/gdb_assert.h \
+ common/gdb_chdir.h \
common/gdb_locale.h \
common/gdb_setjmp.h \
common/gdb_signals.h \
@@ -1734,6 +1736,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
frame-unwind.o \
gcore.o \
gdb_bfd.o \
+ gdb_chdir.o \
gdb-dlfcn.o \
gdb_obstack.o \
gdb_regex.o \
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 85d6d21113..653dd56a64 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -54,6 +54,8 @@
#include "tui/tui.h" /* For tui_active et.al. */
#endif
+#include "gdb_chdir.h"
+
#include <fcntl.h>
#include <algorithm>
#include <string>
@@ -408,12 +410,7 @@ cd_command (char *dir, int from_tty)
repeat might be useful but is more likely to be a mistake. */
dont_repeat ();
- gdb::unique_xmalloc_ptr<char> dir_holder
- (tilde_expand (dir != NULL ? dir : "~"));
- dir = dir_holder.get ();
-
- if (chdir (dir) < 0)
- perror_with_name (dir);
+ gdb_chdir (dir != NULL ? dir : "~");
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* There's too much mess with DOSish names like "d:", "d:.",
@@ -436,20 +433,21 @@ cd_command (char *dir, int from_tty)
len--;
}
- dir_holder.reset (savestring (dir, len));
- if (IS_ABSOLUTE_PATH (dir_holder.get ()))
+ std::string newdir = std::string (dir, len);
+ const char *newdir_str = newdir.c_str ();
+ if (IS_ABSOLUTE_PATH (newdir_str))
{
xfree (current_directory);
- current_directory = dir_holder.release ();
+ current_directory = xstrdup (newdir_str);
This introduces one extra deep string dup. One to
construct the std::string, and another here in this xstrdup.
- dir_holder.reset (savestring (dir, len));
+ gdb::unique_xmalloc_ptr<char> dir_holder (savestring (dir, len))
But more importantly, isn't there a behavior change here?
Before, current_directory would be a copy of the the expand
path, while after the patch, it's a copy of the input string,
before expansion. Right?
Wow, you're right. I am sorry about letting this slip. I guess I made
so many modifications to this code that in the end I forgot that "dir"
wasn't being updated to hold the expanded path anymore. I will fix
this.

And with your review of patch #4, it is clear that we don't need
a gdb_chdir; we need a gdb_tilde_expand. Therefore I will make the
necessary modifications to export that function instead.
Post by Pedro Alves
Post by Sergio Durigan Junior
}
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
- current_directory = concat (current_directory, dir_holder.get (),
+ current_directory = concat (current_directory, newdir_str,
(char *) NULL);
else
current_directory = concat (current_directory, SLASH_STRING,
- dir_holder.get (), (char *) NULL);
+ newdir_str, (char *) NULL);
}
+ /* Destroy the object and free M_GLOB. */
+ ~gdb_glob ()
+ {
+ globfree (&m_glob);
+ }
+
+ /* Return the GL_PATHC component of M_GLOB. */
+ int
+ pathc () const
+ {
+ return m_glob.gl_pathc;
+ }
We've been putting type and function name in the
same line in inline member functions. That's the
de facto standard in GCC as well, AFAICS.
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+ /* Return the GL_PATHV component of M_GLOB. */
+ char **
+ pathv () const
+ {
+ return m_glob.gl_pathv;
+ }
Ditto.
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+#ifndef HAVE_GDB_CHDIR_H
+#define HAVE_GDB_CHDIR_H
+
+/* Perform a "chdir" to DIR, doing the proper tilde expansion before. */
+extern void gdb_chdir (const char *dir);
Nit, I'd drop "the proper", as it doesn't see to add value.
I.e., what's proper and what's not proper?
Done.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-19 04:28:41 UTC
Permalink
This is the actual implementation of the "set/show cwd" commands. The
way they work is:

- If the user sets the inferior's cwd by using "set cwd", then this
directory is saved into current_inferior ()->cwd and is used when
the inferior is started (see below).

- If the user doesn't set the inferior's cwd by using "set cwd", but
rather use the "cd" command as before, the this directory is
inherited by the inferior because GDB will have chdir'd into it.

The way the directory is changed before the inferior execution is by
calling "gdb_chdir" after the call to fork/vfork on "fork_inferior",
but before the actual execution. This way, we'll make sure that GDB's
cwd is not affected by the user set cwd.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* NEWS (New commands): Mention "set/show cwd".
* cli/cli-cmds.c (_initialize_cli_cmds): Mention "set cwd" on
"cd" command's help text.
* common/common-inferior.h (get_inferior_cwd): New prototype.
* infcmd.c: Include "gdb_chdir.h" and "readline/tilde.h".
(inferior_cwd_scratch): New global variable.
(set_inferior_cwd): New function.
(get_inferior_cwd): Likewise.
(set_cwd_command): Likewise.
(show_cwd_command): Likewise.
(_initialize_infcmd): Add "set/show cwd" commands.
* inferior.h (class inferior) <cwd>: New field.
* nat/fork-inferior.c: Include "gdb_chdir.h".
(fork_inferior): Change inferior's cwd before its execution.
* windows-nat.c (windows_create_inferior): Pass inferior's cwd
to CreateProcess.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* inferiors.c (get_inferior_cwd): New function.
* inferiors.h (struct process_info) <cwd>: New field.

gdb/doc/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.texinfo (Starting your Program) <The working directory.>:
Mention new "set cwd" command.
(Working Directory) <Your Program's Working Directory>:
Rephrase to explain that "set cwd" exists and is the default
way to change the inferior's cwd.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.base/set-cwd.c: New file.
* gdb.base/set-cwd.exp: Likewise.
---
gdb/NEWS | 3 ++
gdb/cli/cli-cmds.c | 6 +--
gdb/common/common-inferior.h | 4 ++
gdb/doc/gdb.texinfo | 34 ++++++++++----
gdb/gdbserver/inferiors.c | 11 +++++
gdb/infcmd.c | 75 +++++++++++++++++++++++++++++++
gdb/inferior.h | 4 ++
gdb/nat/fork-inferior.c | 17 +++++++
gdb/testsuite/gdb.base/set-cwd.c | 29 ++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 90 ++++++++++++++++++++++++++++++++++++++
gdb/windows-nat.c | 5 ++-
11 files changed, 265 insertions(+), 13 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/set-cwd.c
create mode 100644 gdb/testsuite/gdb.base/set-cwd.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 3244f7effe..0dcfcc98af 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -64,6 +64,9 @@ QStartupWithShell

* New commands

+set|show cwd
+ Set and show the current working directory for the inferior.
+
set|show compile-gcc
Set and show compilation command used for compiling and injecting code
with the 'compile' commands.
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 653dd56a64..f086f10aea 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1716,9 +1716,9 @@ The commands below can be used to select other frames by number or address."),
Print working directory. This is used for your program as well."));

c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
set_cmd_completer (c, filename_completer);

add_com ("echo", class_support, echo_command, _("\
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 87c13009ed..515a8c0f4e 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -30,4 +30,8 @@ extern const char *get_exec_wrapper ();
otherwise return 0 in that case. */
extern char *get_exec_file (int err);

+/* Return the inferior's current working directory. If nothing has
+ been set, then return NULL. */
+extern const char *get_inferior_cwd ();
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index af5fe6f46c..c513a49c26 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2057,8 +2057,9 @@ environment} to change parts of the environment that affect
your program. @xref{Environment, ,Your Program's Environment}.

@item The @emph{working directory.}
-Your program inherits its working directory from @value{GDBN}. You can set
-the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}.
+You can set your program's working directory with the command
+@code{set cwd}. If you do not set any working directory with this
+command, your program will inherit @value{GDBN}'s working directory.
@xref{Working Directory, ,Your Program's Working Directory}.

@item The @emph{standard input and output.}
@@ -2424,19 +2425,36 @@ variables to files that are only run when you sign on, such as
@section Your Program's Working Directory

@cindex working directory (of your program)
-Each time you start your program with @code{run}, it inherits its
-working directory from the current working directory of @value{GDBN}.
-The @value{GDBN} working directory is initially whatever it inherited
-from its parent process (typically the shell), but you can specify a new
-working directory in @value{GDBN} with the @code{cd} command.
+Each time you start your program with @code{run}, the inferior will be
+initialized with the current working directory specified by the
+@code{set cwd} command. If no directory has been specified by this
+command, then the inferior will inherit @value{GDBN}'s current working
+directory as its working directory.
+
+You can also change @value{GDBN}'s current working directory by using
+the @code{cd} command.

The @value{GDBN} working directory also serves as a default for the commands
that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to
Specify Files}.

@table @code
+@kindex set cwd
+@cindex change inferior's working directory
+@item set cwd @r{[}@var{directory}@r{]}
+Set the inferior's working directory to @var{directory}. If not
+given, @var{directory} uses @file{'~'}. This has no effect on
+@value{GDBN}'s working directory.
+
+@kindex show cwd
+@cindex show inferior's working directory
+@item show cwd
+Show the inferior's working directory. If no directory has been
+specified by @code{set cwd}, then the default inferior's working
+directory is the same as @value{GDBN}'s working directory.
+
@kindex cd
-@cindex change working directory
+@cindex change @value{GDBN}'s working directory
@item cd @r{[}@var{directory}@r{]}
Set the @value{GDBN} working directory to @var{directory}. If not
given, @var{directory} uses @file{'~'}.
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 72f0412757..e78ad4faf1 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,9 @@ struct thread_info *current_thread;

#define get_thread(inf) ((struct thread_info *)(inf))

+/* The current working directory used to start the inferior. */
+static const char *current_inferior_cwd = NULL;
+
void
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
@@ -445,3 +448,11 @@ switch_to_thread (ptid_t ptid)
if (!ptid_equal (ptid, minus_one_ptid))
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 25cf025426..178a3ca15f 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -59,6 +59,8 @@
#include "top.h"
#include "interps.h"
#include "common/gdb_optional.h"
+#include "gdb_chdir.h"
+#include "readline/tilde.h"

/* Local functions: */

@@ -111,6 +113,10 @@ static void run_command (char *, int);

static char *inferior_args_scratch;

+/* Scratch area where the new cwd will be stored by 'set cwd'. */
+
+static char *inferior_cwd_scratch;
+
/* Scratch area where 'set inferior-tty' will store user-provided value.
We'll immediate copy it into per-inferior storage. */

@@ -246,6 +252,56 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}

+/* Set the inferior current working directory. This directory will be
+ entered by GDB before executing the inferior. */
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+ xfree ((void *) inf->cwd);
+ inf->cwd = tilde_expand (*cwd != '\0' ? cwd : "~");
+}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior ()->cwd;
+}
+
+/* Handle the 'set cwd' command. */
+
+static void
+set_cwd_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_inferior_cwd (inferior_cwd_scratch);
+}
+
+/* Handle the 'show cwd' command. */
+
+static void
+show_cwd_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd == NULL)
+ {
+ /* To maintain backwards compatibility, we use
+ 'current_directory' here, which is set by the "cd"
+ command. */
+ cwd = current_directory;
+ }
+
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+

/* Compute command-line string given argument vector. This does the
same shell processing as fork_inferior. */
@@ -3214,6 +3270,25 @@ Follow this command with any number of args, to be passed to the program."),
gdb_assert (c != NULL);
set_cmd_completer (c, filename_completer);

+ cmd_name = "cwd";
+ add_setshow_string_noescape_cmd (cmd_name, class_run,
+ &inferior_cwd_scratch, _("\
+Set the current working directory to be used when the inferior is started.\n\
+Changing this setting does not have any effect on inferiors that are\n\
+already running."),
+ _("\
+Show the current working directory that is used when the inferior is started."),
+ _("\
+Use this command to change the current working directory that will be used\n\
+when the inferior is started. This setting does not affect GDB's current\n\
+working directory."),
+ set_cwd_command,
+ show_cwd_command,
+ &setlist, &showlist);
+ c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+ gdb_assert (c != NULL);
+ set_cmd_completer (c, filename_completer);
+
c = add_cmd ("environment", no_class, environment_info, _("\
The environment to give the program, or one variable's value.\n\
With an argument VAR, prints the value of environment variable VAR to\n\
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 6d020f73c4..bcd1e54a03 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -355,6 +355,10 @@ public:
should never be freed. */
char **argv = NULL;

+ /* The current working directory that will be used when starting
+ this inferior. */
+ const char *cwd = NULL;
+
/* The name of terminal device to use for I/O. */
char *terminal = NULL;

diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index 0913409e6d..6ff0c2d216 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -25,6 +25,7 @@
#include "common-inferior.h"
#include "common-gdbthread.h"
#include "signals-state-save-restore.h"
+#include "gdb_chdir.h"
#include <vector>

extern char **environ;
@@ -376,6 +377,22 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();

+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd != NULL)
+ {
+ TRY
+ {
+ gdb_chdir (cwd);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ warning ("%s", ex.message);
+ _exit (0177);
+ }
+ END_CATCH
+ }
+
if (debug_fork)
sleep (debug_fork);

diff --git a/gdb/testsuite/gdb.base/set-cwd.c b/gdb/testsuite/gdb.base/set-cwd.c
new file mode 100644
index 0000000000..488fc4e4e3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main (int argc, char *argv[])
+{
+ char dir[BUFSIZ];
+
+ getcwd (dir, BUFSIZ);
+
+ return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
new file mode 100644
index 0000000000..3a6ffd3862
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -0,0 +1,90 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if { ![isnative] || [is_remote target] || [is_remote host]
+ || [target_info gdb_protocol] == "extended-remote" } then {
+ untested "not implemented on gdbserver"
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ if { [info exists ::env(HOME)] } {
+ with_test_prefix "test tilde expansion" {
+ set home $::env(HOME)
+
+ gdb_test_no_output "set cwd ~/test" "set cwd to ~/test dir"
+
+ gdb_test "show cwd" \
+ "Current working directory that will be used when starting the inferior is \"${home}/test\"\." \
+ "show cwd shows expanded tilde"
+ }
+ }
+}
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ }
+
+ set tmpdir [standard_output_file ""]
+
+ gdb_test_no_output "set cwd $tmpdir" "set cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ }
+
+ set test "GDB cwd is unchanged after running inferior"
+ if { [string equal $gdb_cwd_before_run $gdb_cwd_after_run] } {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+}
+
+test_cd_into_dir
+test_tilde_expansion
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index ab5582d46c..9732a2d175 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2461,6 +2461,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
BOOL ret;
DWORD flags = 0;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ const char *inferior_cwd = get_inferior_cwd ();

if (!exec_file)
error (_("No executable specified, use `target exec'."));
@@ -2574,7 +2575,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32_env, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si,
&pi);
if (w32_env)
@@ -2697,7 +2698,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32env, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si,
&pi);
if (tty != INVALID_HANDLE_VALUE)
--
2.13.3
Pedro Alves
2017-09-20 14:01:13 UTC
Permalink
Post by Sergio Durigan Junior
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 653dd56a64..f086f10aea 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1716,9 +1716,9 @@ The commands below can be used to select other frames by number or address."),
Print working directory. This is used for your program as well."));
c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
I think it'd be nice to add a sentence here suggesting what the
current working directory affects.
Post by Sergio Durigan Junior
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
set_cmd_completer (c, filename_completer);
add_com ("echo", class_support, echo_command, _("\
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 87c13009ed..515a8c0f4e 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -30,4 +30,8 @@ extern const char *get_exec_wrapper ();
otherwise return 0 in that case. */
extern char *get_exec_file (int err);
+/* Return the inferior's current working directory. If nothing has
+ been set, then return NULL. */
+extern const char *get_inferior_cwd ();
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index af5fe6f46c..c513a49c26 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2057,8 +2057,9 @@ environment} to change parts of the environment that affect
@item The @emph{working directory.}
+You can set your program's working directory with the command
@xref{Working Directory, ,Your Program's Working Directory}.
@item The @emph{standard input and output.}
@@ -2424,19 +2425,36 @@ variables to files that are only run when you sign on, such as
@section Your Program's Working Directory
@cindex working directory (of your program)
-from its parent process (typically the shell), but you can specify a new
+initialized with the current working directory specified by the
+directory as its working directory.
+
Specify Files}.
@table @code
I think we're missing a sentence somewhere in the manual saying that
this setting only takes effect the next time you start the program,
like it is said in "help cd" currently.
Post by Sergio Durigan Junior
+
+Show the inferior's working directory. If no directory has been
+
@kindex cd
@item cd @r{[}@var{directory}@r{]}
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 72f0412757..e78ad4faf1 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,9 @@ struct thread_info *current_thread;
#define get_thread(inf) ((struct thread_info *)(inf))
+/* The current working directory used to start the inferior. */
+static const char *current_inferior_cwd = NULL;
+
void
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
@@ -445,3 +448,11 @@ switch_to_thread (ptid_t ptid)
if (!ptid_equal (ptid, minus_one_ptid))
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 25cf025426..178a3ca15f 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -59,6 +59,8 @@
#include "top.h"
#include "interps.h"
#include "common/gdb_optional.h"
+#include "gdb_chdir.h"
+#include "readline/tilde.h"
/* Local functions: */
@@ -111,6 +113,10 @@ static void run_command (char *, int);
static char *inferior_args_scratch;
+/* Scratch area where the new cwd will be stored by 'set cwd'. */
+
+static char *inferior_cwd_scratch;
+
/* Scratch area where 'set inferior-tty' will store user-provided value.
We'll immediate copy it into per-inferior storage. */
@@ -246,6 +252,56 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}
+/* Set the inferior current working directory. This directory will be
+ entered by GDB before executing the inferior. */
The second sentence is talking about implementation details of Unix-like
targets, which doesn't really belong here.
Post by Sergio Durigan Junior
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+ xfree ((void *) inf->cwd);
+ inf->cwd = tilde_expand (*cwd != '\0' ? cwd : "~");
So the inferior owns the string? Wouldn't it be better if
inf->cwd were a unique_ptr? I don't see anywhere releasing
the cwd string when an inferior is deleted.
Post by Sergio Durigan Junior
+
+/* Handle the 'show cwd' command. */
+
+static void
+show_cwd_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd == NULL)
+ {
+ /* To maintain backwards compatibility, we use
+ 'current_directory' here, which is set by the "cd"
+ command. */
+ cwd = current_directory;
+ }
This doesn't look like the right thing to show, to me.
It'll only make sense for native debugging, not remote debugging,
right? I mean, when remote debugging, the inferior won't inherit
gdb's cwd. Right?
Post by Sergio Durigan Junior
+
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+
index 6d020f73c4..bcd1e54a03 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
should never be freed. */
char **argv = NULL;
+ /* The current working directory that will be used when starting
+ this inferior. */
+ const char *cwd = NULL;
See comment above in set_inferior_cwd. Who owns this string?
Looks like removing the inferior leaks this?
Can this be a unique_xmalloc_ptr ?
Post by Sergio Durigan Junior
@@ -376,6 +377,22 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd != NULL)
+ {
+ TRY
+ {
+ gdb_chdir (cwd);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ warning ("%s", ex.message);
+ _exit (0177);
+ }
+ END_CATCH
+ }
This is the fork-child path, and as such we should only be calling
async-signal-safe code. And throwing C++ exceptions is not async-signal-safe.
I think an easy solution is to call gdb_tilde_expand _before_ forking, and
then call plain old chdir in the child, and then call
trace_start_error_with_name instead of perror_with_name on failure:

if (chdir (expanded_dir.c_str ()) < 0)
trace_start_error_with_name (expanded_dir.c_str ());

With that, I'm not sure whether gdb_chdir is still very useful
compared to using gdb_tilde_expand + chdir in the "cd" command too.
Post by Sergio Durigan Junior
+++ b/gdb/testsuite/gdb.base/set-cwd.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main (int argc, char *argv[])
+{
+ char dir[BUFSIZ];
+
+ getcwd (dir, BUFSIZ);
Hmm, BUFSIZ came back? :-) Please use something like PATH_MAX
with a fallback to 1024 or some such.
Post by Sergio Durigan Junior
+
+ return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
new file mode 100644
index 0000000000..3a6ffd3862
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -0,0 +1,90 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if { ![isnative] || [is_remote target] || [is_remote host]
+ || [target_info gdb_protocol] == "extended-remote" } then {
+ untested "not implemented on gdbserver"
The skip on [is_remote host] surely has nothing to do with gdbserver, right?
Please split that up to a separate untested call with a meaningful gdb.sum
output message. The rest of the checks don't look exactly right,
but I'll ignore that because surely you'll be changing it in the following
patch.
Post by Sergio Durigan Junior
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ if { [info exists ::env(HOME)] } {
+ with_test_prefix "test tilde expansion" {
+ set home $::env(HOME)
+
+ gdb_test_no_output "set cwd ~/test" "set cwd to ~/test dir"
+
+ gdb_test "show cwd" \
+ "Current working directory that will be used when starting the inferior is \"${home}/test\"\." \
+ "show cwd shows expanded tilde"
+ }
+ }
+}
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ }
Is the above fails, then gdb_cwd_before_run is left unset,
and the next reference causes a TCL error.
Post by Sergio Durigan Junior
+
+ set tmpdir [standard_output_file ""]
+
+ gdb_test_no_output "set cwd $tmpdir" "set cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ }
Likewise.
Post by Sergio Durigan Junior
+
+ set test "GDB cwd is unchanged after running inferior"
+ if { [string equal $gdb_cwd_before_run $gdb_cwd_after_run] } {
+ pass $test
+ } else {
+ fail $test
+ }
You can use gdb_assert instead of this if/else pass/fail.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-20 23:08:15 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 653dd56a64..f086f10aea 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1716,9 +1716,9 @@ The commands below can be used to select other frames by number or address."),
Print working directory. This is used for your program as well."));
c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
I think it'd be nice to add a sentence here suggesting what the
current working directory affects.
Done. Here's the new text:

c = add_cmd ("cd", class_files, cd_command, _("\
Set working directory to DIR for debugger.\n\
The debugger's current working directory specifies where scripts and other\n\
files that can be loaded by GDB are located.\n\
In order to change the inferior's current working directory, the recommended\n\
way is to use the \"set cwd\" command."), &cmdlist);
Post by Pedro Alves
Post by Sergio Durigan Junior
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
set_cmd_completer (c, filename_completer);
add_com ("echo", class_support, echo_command, _("\
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 87c13009ed..515a8c0f4e 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -30,4 +30,8 @@ extern const char *get_exec_wrapper ();
otherwise return 0 in that case. */
extern char *get_exec_file (int err);
+/* Return the inferior's current working directory. If nothing has
+ been set, then return NULL. */
+extern const char *get_inferior_cwd ();
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index af5fe6f46c..c513a49c26 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2057,8 +2057,9 @@ environment} to change parts of the environment that affect
@item The @emph{working directory.}
+You can set your program's working directory with the command
@xref{Working Directory, ,Your Program's Working Directory}.
@item The @emph{standard input and output.}
@@ -2424,19 +2425,36 @@ variables to files that are only run when you sign on, such as
@section Your Program's Working Directory
@cindex working directory (of your program)
-from its parent process (typically the shell), but you can specify a new
+initialized with the current working directory specified by the
+directory as its working directory.
+
Specify Files}.
@table @code
I think we're missing a sentence somewhere in the manual saying that
this setting only takes effect the next time you start the program,
like it is said in "help cd" currently.
Here's what the new text looks like:

@table @code
@kindex set cwd
@cindex change inferior's working directory
@item set cwd @r{[}@var{directory}@r{]}
Set the inferior's working directory to @var{directory}. If not
given, @var{directory} uses @file{'~'}. This has no effect on
@value{GDBN}'s working directory. This setting only takes effect the
next time you start the inferior.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+Show the inferior's working directory. If no directory has been
+
@kindex cd
@item cd @r{[}@var{directory}@r{]}
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 72f0412757..e78ad4faf1 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,9 @@ struct thread_info *current_thread;
#define get_thread(inf) ((struct thread_info *)(inf))
+/* The current working directory used to start the inferior. */
+static const char *current_inferior_cwd = NULL;
+
void
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
@@ -445,3 +448,11 @@ switch_to_thread (ptid_t ptid)
if (!ptid_equal (ptid, minus_one_ptid))
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 25cf025426..178a3ca15f 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -59,6 +59,8 @@
#include "top.h"
#include "interps.h"
#include "common/gdb_optional.h"
+#include "gdb_chdir.h"
+#include "readline/tilde.h"
/* Local functions: */
@@ -111,6 +113,10 @@ static void run_command (char *, int);
static char *inferior_args_scratch;
+/* Scratch area where the new cwd will be stored by 'set cwd'. */
+
+static char *inferior_cwd_scratch;
+
/* Scratch area where 'set inferior-tty' will store user-provided value.
We'll immediate copy it into per-inferior storage. */
@@ -246,6 +252,56 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}
+/* Set the inferior current working directory. This directory will be
+ entered by GDB before executing the inferior. */
The second sentence is talking about implementation details of Unix-like
targets, which doesn't really belong here.
True. I will remove it.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+ xfree ((void *) inf->cwd);
+ inf->cwd = tilde_expand (*cwd != '\0' ? cwd : "~");
So the inferior owns the string? Wouldn't it be better if
inf->cwd were a unique_ptr? I don't see anywhere releasing
the cwd string when an inferior is deleted.
Right, the inferior owns the string. And indeed, there's no place
free'ing the string when the inferior goes away. I think the unique_ptr
idea is good, I'll implement it.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+/* Handle the 'show cwd' command. */
+
+static void
+show_cwd_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd == NULL)
+ {
+ /* To maintain backwards compatibility, we use
+ 'current_directory' here, which is set by the "cd"
+ command. */
+ cwd = current_directory;
+ }
This doesn't look like the right thing to show, to me.
It'll only make sense for native debugging, not remote debugging,
right? I mean, when remote debugging, the inferior won't inherit
gdb's cwd. Right?
That's right. Maybe a better text for when cwd == NULL would be:

You have not set the inferior's current working directory. The
inferior will inherit GDB's cwd if native debugging, or gdbserver's
cwd if remote debugging.

WDYT?
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+
index 6d020f73c4..bcd1e54a03 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
should never be freed. */
char **argv = NULL;
+ /* The current working directory that will be used when starting
+ this inferior. */
+ const char *cwd = NULL;
See comment above in set_inferior_cwd. Who owns this string?
Looks like removing the inferior leaks this?
Can this be a unique_xmalloc_ptr ?
As explained above, I'll implement it as a unique_ptr.
Post by Pedro Alves
Post by Sergio Durigan Junior
@@ -376,6 +377,22 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd != NULL)
+ {
+ TRY
+ {
+ gdb_chdir (cwd);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ warning ("%s", ex.message);
+ _exit (0177);
+ }
+ END_CATCH
+ }
This is the fork-child path, and as such we should only be calling
async-signal-safe code. And throwing C++ exceptions is not async-signal-safe.
I think an easy solution is to call gdb_tilde_expand _before_ forking, and
then call plain old chdir in the child, and then call
if (chdir (expanded_dir.c_str ()) < 0)
trace_start_error_with_name (expanded_dir.c_str ());
With that, I'm not sure whether gdb_chdir is still very useful
compared to using gdb_tilde_expand + chdir in the "cd" command too.
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+++ b/gdb/testsuite/gdb.base/set-cwd.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main (int argc, char *argv[])
+{
+ char dir[BUFSIZ];
+
+ getcwd (dir, BUFSIZ);
Hmm, BUFSIZ came back? :-) Please use something like PATH_MAX
with a fallback to 1024 or some such.
Hm, right, I forgot to remove it from the testcase. I'll use 4096 (the
default for PATH_MAX), it should be enough.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+ return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
new file mode 100644
index 0000000000..3a6ffd3862
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -0,0 +1,90 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if { ![isnative] || [is_remote target] || [is_remote host]
+ || [target_info gdb_protocol] == "extended-remote" } then {
+ untested "not implemented on gdbserver"
The skip on [is_remote host] surely has nothing to do with gdbserver, right?
I think I was trying to be "overzealous" here, but "[is_remote host]"
would only make sense if this test was being run on gdbserver, right?
Having said that, I don't think it's correct to check for that here.
Post by Pedro Alves
Please split that up to a separate untested call with a meaningful gdb.sum
output message. The rest of the checks don't look exactly right,
but I'll ignore that because surely you'll be changing it in the following
patch.
What I really want to do here is to disable this test on remote
debugging. Sometimes I get the whole "target/host/native/remote" thing
right, sometimes I get confused about it.

Given your comment on patch #5, I guess I should be checking only for
[use_gdb_stub] and go from that. I'll make a few tests here to see what
works for my case.
Post by Pedro Alves
Post by Sergio Durigan Junior
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ if { [info exists ::env(HOME)] } {
+ with_test_prefix "test tilde expansion" {
+ set home $::env(HOME)
+
+ gdb_test_no_output "set cwd ~/test" "set cwd to ~/test dir"
+
+ gdb_test "show cwd" \
+ "Current working directory that will be used when starting the inferior is \"${home}/test\"\." \
+ "show cwd shows expanded tilde"
+ }
+ }
+}
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ }
Is the above fails, then gdb_cwd_before_run is left unset,
and the next reference causes a TCL error.
I've added a catch-all case after the first one, which fails and returns
-1.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+ set tmpdir [standard_output_file ""]
+
+ gdb_test_no_output "set cwd $tmpdir" "set cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ }
Likewise.
Likewise my comment above.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+ set test "GDB cwd is unchanged after running inferior"
+ if { [string equal $gdb_cwd_before_run $gdb_cwd_after_run] } {
+ pass $test
+ } else {
+ fail $test
+ }
You can use gdb_assert instead of this if/else pass/fail.
Hm, good point. Done.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-19 04:28:42 UTC
Permalink
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.

The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.

Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) the documentation.

No regressions found.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_handle_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_handle_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass "inferior_cwd" to
CreateProcess.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.base/set-cwd.exp: Make it available on gdbserver.

gdb/doc/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.texinfo (Starting your Program) <The working directory.>:
Mention remote debugging.
(Working Directory) <Your Program's Working Directory>:
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 11 ++++++++++
gdb/common/common-inferior.h | 4 ++++
gdb/doc/gdb.texinfo | 44 ++++++++++++++++++++++++++++++++++----
gdb/gdbserver/inferiors.c | 9 ++++++++
gdb/gdbserver/server.c | 18 +++++++++++++++-
gdb/gdbserver/win32-low.c | 5 +++--
gdb/infcmd.c | 5 ++---
gdb/remote.c | 35 ++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
9 files changed, 131 insertions(+), 14 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 0dcfcc98af..a0f78e4c35 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -39,6 +39,14 @@
variables that are to be set or unset from GDB. These variables
will affect the environment to be passed to the inferior.

+ ** On Unix systems, GDBserver is now able to enter a directory
+ before starting an inferior.
+
+ This is done by using the "cd" command in GDB, which instructs it
+ to tell GDBserver about this directory change the next time an
+ inferior is run. If you want to make GDBserver enter the
+ directory your GDB is currently in, you can do a "cd ." in GDB.
+
* New remote packets

QEnvironmentHexEncoded
@@ -56,6 +64,9 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.

+QSetWorkingDir
+ Tell GDBserver to enter another directory before starting the inferior.
+
* The "maintenance print c-tdesc" command now takes an optional
argument which is the file name of XML target description.

diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 515a8c0f4e..65c23a936b 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,8 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();

+/* Set the inferior current working directory. This directory will be
+ entered by the debugger before executing the inferior. */
+extern void set_inferior_cwd (const char *cwd);
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c513a49c26..fc20a74bce 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
You can set your program's working directory with the command
@code{set cwd}. If you do not set any working directory with this
-command, your program will inherit @value{GDBN}'s working directory.
-@xref{Working Directory, ,Your Program's Working Directory}.
+command, your program will inherit @value{GDBN}'s working directory if
+native debugging, or @code{gdbserver}'s working directory if remote
+debugging. @xref{Working Directory, ,Your Program's Working
+Directory}.

@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
@@ -2429,7 +2431,9 @@ Each time you start your program with @code{run}, the inferior will be
initialized with the current working directory specified by the
@code{set cwd} command. If no directory has been specified by this
command, then the inferior will inherit @value{GDBN}'s current working
-directory as its working directory.
+directory as its working directory if native debugging, or it will
+inherit @code{gdbserver}'s current working directory if remote
+debugging.

You can also change @value{GDBN}'s current working directory by using
the @code{cd} command.
@@ -2444,7 +2448,8 @@ Specify Files}.
@item set cwd @r{[}@var{directory}@r{]}
Set the inferior's working directory to @var{directory}. If not
given, @var{directory} uses @file{'~'}. This has no effect on
-@value{GDBN}'s working directory.
+@value{GDBN}'s working directory. This setting works for both native
+and remote debugging.

@kindex show cwd
@cindex show inferior's working directory
@@ -20982,6 +20987,10 @@ are:
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}

+@item @code{set-working-dir}
+@tab @code{QSetWorkingDir}
+@tab @code{cd}
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@@ -36770,6 +36779,30 @@ Reply:
@table @samp
@item OK
The request succeeded.
+
+@item QSetWorkingDir:@var{hex-value}
+@anchor{QSetWorkingDir packet}
+@cindex set working directory, remote request
+@cindex @samp{QSetWorkingDir} packet
+On UNIX-like targets, it is possible to set the current working
+directory that @command{gdbserver} will enter before starting the
+inferior. This packet is used to inform @command{gdbserver} of a
+directory into which it should enter during the startup process.
+
+The packet is composed by @var{hex-value}, an hex encoded
+representation of the directory to be entered by @command{gdbserver}.
+
+This packet is only transmitted when the user issues a @code{cd}
+command in @value{GDBN} (@pxref{Working Directory, ,Your Program's
+Working Directory}).
+
+This packet is only available in extended mode (@pxref{extended
+mode}).
+
+Reply:
+@table @samp
+@item OK
+The request succeeded.
@end table

This packet is not probed by default; the remote stub must request it,
@@ -36800,6 +36833,9 @@ Reply:
@table @samp
@item OK
The request succeeded.
+
+@item E @var{nn}
+An error occurred. The error number @var{nn} is given as hex digits.
@end table

This packet is not probed by default; the remote stub must request it,
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e78ad4faf1..326d01f4d9 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,12 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f4faff9d77..a159708632 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
return;
}

+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Changed current directory to %s]\n"),
+ path.c_str ());
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2345,7 +2360,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);

if (target_supports_catch_syscall ())
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index cc84d15c2f..b9fff29d74 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,6 +562,7 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;

#ifdef _WIN32_WCE
@@ -586,7 +587,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ inferior_cwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +600,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 178a3ca15f..a51a3d4e40 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -252,10 +252,9 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}

-/* Set the inferior current working directory. This directory will be
- entered by GDB before executing the inferior. */
+/* See common/common-inferior.h. */

-static void
+void
set_inferior_cwd (const char *cwd)
{
struct inferior *inf = current_inferior ();
diff --git a/gdb/remote.c b/gdb/remote.c
index 0963693a22..d900157ca9 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1428,6 +1428,7 @@ enum {
PACKET_QPassSignals,
PACKET_QCatchSyscalls,
PACKET_QProgramSignals,
+ PACKET_QSetWorkingDir,
PACKET_QStartupWithShell,
PACKET_QEnvironmentHexEncoded,
PACKET_QEnvironmentReset,
@@ -4637,6 +4638,8 @@ static const struct protocol_feature remote_protocol_features[] = {
PACKET_QCatchSyscalls },
{ "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QProgramSignals },
+ { "QSetWorkingDir", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QSetWorkingDir },
{ "QStartupWithShell", PACKET_DISABLE, remote_supported_packet,
PACKET_QStartupWithShell },
{ "QEnvironmentHexEncoded", PACKET_DISABLE, remote_supported_packet,
@@ -9616,6 +9619,33 @@ extended_remote_environment_support (struct remote_state *rs)
send_environment_packet (rs, "unset", "QEnvironmentUnset", el.c_str ());
}

+/* Helper function to handle the change of the current working
+ directory in the remote. */
+
+static void
+extended_remote_handle_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("\
+Remote replied unexpectedly while changing working directory: %s"),
+ rs->buf);
+ }
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9658,6 +9688,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),

extended_remote_environment_support (rs);

+ extended_remote_handle_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14126,6 +14158,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);

+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);

diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index 3a6ffd3862..d3104287a0 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,10 +15,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

-if { ![isnative] || [is_remote target] || [is_remote host]
- || [target_info gdb_protocol] == "extended-remote" } then {
- untested "not implemented on gdbserver"
- return
+if { [target_info exists gdb_protocol] } {
+ if { [target_info gdb_protocol] == "remote" } {
+ untested "not implemented on native-gdbserver"
+ return
+ }
+
+ load_lib gdbserver-support.exp
+ if { [skip_gdbserver_tests] } {
+ return
+ }
}

standard_testfile
--
2.13.3
Pedro Alves
2017-09-20 14:34:48 UTC
Permalink
Post by Sergio Durigan Junior
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.
Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) the documentation.
No regressions found.
* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_handle_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_handle_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.
* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass "inferior_cwd" to
CreateProcess.
* gdb.base/set-cwd.exp: Make it available on gdbserver.
Mention remote debugging.
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 11 ++++++++++
gdb/common/common-inferior.h | 4 ++++
gdb/doc/gdb.texinfo | 44 ++++++++++++++++++++++++++++++++++----
gdb/gdbserver/inferiors.c | 9 ++++++++
gdb/gdbserver/server.c | 18 +++++++++++++++-
gdb/gdbserver/win32-low.c | 5 +++--
gdb/infcmd.c | 5 ++---
gdb/remote.c | 35 ++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
9 files changed, 131 insertions(+), 14 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 0dcfcc98af..a0f78e4c35 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -39,6 +39,14 @@
variables that are to be set or unset from GDB. These variables
will affect the environment to be passed to the inferior.
+ ** On Unix systems, GDBserver is now able to enter a directory
+ before starting an inferior.
+
+ This is done by using the "cd" command in GDB, which instructs it
+ to tell GDBserver about this directory change the next time an
+ inferior is run. If you want to make GDBserver enter the
+ directory your GDB is currently in, you can do a "cd ." in GDB.
This all looks stale to me.
Post by Sergio Durigan Junior
+
* New remote packets
QEnvironmentHexEncoded
@@ -56,6 +64,9 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.
+QSetWorkingDir
+ Tell GDBserver to enter another directory before starting the inferior.
Should this really be described in terms of gdbserver entering a
directory? That seems like fork-child implementation detail.
Do we really want this to affect gdbserver's current directory
as well, maybe in future use cases, or just the inferior's cwd?
Post by Sergio Durigan Junior
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,8 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();
+/* Set the inferior current working directory. This directory will be
+ entered by the debugger before executing the inferior. */
+extern void set_inferior_cwd (const char *cwd);
Again described in terms of target implementation detail.
Post by Sergio Durigan Junior
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c513a49c26..fc20a74bce 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
You can set your program's working directory with the command
@code{set cwd}. If you do not set any working directory with this
+Directory}.
@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
@@ -2429,7 +2431,9 @@ Each time you start your program with @code{run}, the inferior will be
initialized with the current working directory specified by the
@code{set cwd} command. If no directory has been specified by this
-directory as its working directory.
+directory as its working directory if native debugging, or it will
+debugging.
@@ -2444,7 +2448,8 @@ Specify Files}.
@item set cwd @r{[}@var{directory}@r{]}
+and remote debugging.
Not sure we should add such a sentence for a particular command alone;
If I read the resulting manual without context of this patch, I wonder
whether this means that the other settings described above (like e.g.,
set args/environment) don't work with remote debugging.
Post by Sergio Durigan Junior
@kindex show cwd
@cindex show inferior's working directory
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}
This reference to "cd" is probably incorrect in this version and should
be "set cwd", right?
Post by Sergio Durigan Junior
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@table @samp
@item OK
The request succeeded.
+
+On UNIX-like targets, it is possible to set the current working
+directory into which it should enter during the startup process.
I don't see why this is talking about Unix-like targets in particular.
You're making it work on Windows too, right? I don't think we should
talk in terms of gdbserver, for the matter. I think the first sentence
could all go away. We should instead say that this packet is used to
inform the remote server of the intended current directory for programs
that are next run.
Post by Sergio Durigan Junior
+
+
+Working Directory}).
Reference to "cd" is stale.
Post by Sergio Durigan Junior
+
+mode}).
+
+The request succeeded.
@end table
This packet is not probed by default; the remote stub must request it,
@table @samp
@item OK
The request succeeded.
+
@end table
This packet is not probed by default; the remote stub must request it,
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e78ad4faf1..326d01f4d9 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,12 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f4faff9d77..a159708632 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
return;
}
+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Changed current directory to %s]\n"),
+ path.c_str ());
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2345,7 +2360,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);
if (target_supports_catch_syscall ())
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index cc84d15c2f..b9fff29d74 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,6 +562,7 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;
#ifdef _WIN32_WCE
@@ -586,7 +587,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ inferior_cwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
This path takes a wide string, so you'd need to
do the alloca + mbstowcs above, like done with wprogram.
Post by Sergio Durigan Junior
#else
@@ -599,7 +600,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 178a3ca15f..a51a3d4e40 100644
+/* Helper function to handle the change of the current working
+ directory in the remote. */
+
+static void
+extended_remote_handle_inferior_cwd (struct remote_state *rs)
I'd call "set", not "handle" (ditto comments). "handle" to me
indicates that you're handling a command that you received. But
here we're sending the command.
Post by Sergio Durigan Junior
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("\
+Remote replied unexpectedly while changing working directory: %s"),
+ rs->buf);
Please use packet_ok.
Post by Sergio Durigan Junior
+ }
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9658,6 +9688,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
extended_remote_environment_support (rs);
+ extended_remote_handle_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14126,6 +14158,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index 3a6ffd3862..d3104287a0 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,10 +15,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-if { ![isnative] || [is_remote target] || [is_remote host]
- || [target_info gdb_protocol] == "extended-remote" } then {
- untested "not implemented on gdbserver"
- return
+if { [target_info exists gdb_protocol] } {
+ if { [target_info gdb_protocol] == "remote" } {
+ untested "not implemented on native-gdbserver"
+ return
+ }
+
+ load_lib gdbserver-support.exp
+ if { [skip_gdbserver_tests] } {
+ return
+ }
}
This drops the is_remote host and target checks, but the test is
using "$::env(HOME)", so it really can't work when
remote-host/target testing, because that is accessing HOME in the
build machine (where dejagnu runs) not of the host machine
(where gdb runs) or the target machine (where gdbserver runs):

proc test_tilde_expansion { } {
if { [info exists ::env(HOME)] } {
with_test_prefix "test tilde expansion" {
set home $::env(HOME)


I don't understand the explicit check for gdbserver in
skip_gdbserver_tests.

Seems to me that instead of that, and the "remote" check we should skip
the test if use_gdb_stub, because that's what indicates that when you
connect to a target, you're already debugging something, like with
plain remote debugging.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-20 23:49:01 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.
Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) the documentation.
No regressions found.
* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_handle_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_handle_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.
* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass "inferior_cwd" to
CreateProcess.
* gdb.base/set-cwd.exp: Make it available on gdbserver.
Mention remote debugging.
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 11 ++++++++++
gdb/common/common-inferior.h | 4 ++++
gdb/doc/gdb.texinfo | 44 ++++++++++++++++++++++++++++++++++----
gdb/gdbserver/inferiors.c | 9 ++++++++
gdb/gdbserver/server.c | 18 +++++++++++++++-
gdb/gdbserver/win32-low.c | 5 +++--
gdb/infcmd.c | 5 ++---
gdb/remote.c | 35 ++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
9 files changed, 131 insertions(+), 14 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 0dcfcc98af..a0f78e4c35 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -39,6 +39,14 @@
variables that are to be set or unset from GDB. These variables
will affect the environment to be passed to the inferior.
+ ** On Unix systems, GDBserver is now able to enter a directory
+ before starting an inferior.
+
+ This is done by using the "cd" command in GDB, which instructs it
+ to tell GDBserver about this directory change the next time an
+ inferior is run. If you want to make GDBserver enter the
+ directory your GDB is currently in, you can do a "cd ." in GDB.
This all looks stale to me.
Indeed, sorry about this mistake. I will rewrite the entry as follows:

* New features in the GDB remote stub, GDBserver

** GDBserver is now able to enter a directory before starting an
inferior.

The user can set the desired working directory to be used by the
remote inferior on GDB, using the new "set cwd" command, which
will instruct GDB to tell GDBserver about this directory change
the next time an inferior is run.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
* New remote packets
QEnvironmentHexEncoded
@@ -56,6 +64,9 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.
+QSetWorkingDir
+ Tell GDBserver to enter another directory before starting the inferior.
Should this really be described in terms of gdbserver entering a
directory? That seems like fork-child implementation detail.
Do we really want this to affect gdbserver's current directory
as well, maybe in future use cases, or just the inferior's cwd?
I've changed the description of the packet to:

QSetWorkingDir
Tell GDBserver that the inferior to be started should use a specific
working directory.

As for your other question, I assume that if we ever want to change
gdbserver's cwd the best way would be to create a different packet, so
as not to confuse with this one.
Post by Pedro Alves
Post by Sergio Durigan Junior
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,8 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();
+/* Set the inferior current working directory. This directory will be
+ entered by the debugger before executing the inferior. */
+extern void set_inferior_cwd (const char *cwd);
Again described in terms of target implementation detail.
Removed the target-specific part.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c513a49c26..fc20a74bce 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
You can set your program's working directory with the command
@code{set cwd}. If you do not set any working directory with this
+Directory}.
@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
@@ -2429,7 +2431,9 @@ Each time you start your program with @code{run}, the inferior will be
initialized with the current working directory specified by the
@code{set cwd} command. If no directory has been specified by this
-directory as its working directory.
+directory as its working directory if native debugging, or it will
+debugging.
@@ -2444,7 +2448,8 @@ Specify Files}.
@item set cwd @r{[}@var{directory}@r{]}
+and remote debugging.
Not sure we should add such a sentence for a particular command alone;
If I read the resulting manual without context of this patch, I wonder
whether this means that the other settings described above (like e.g.,
set args/environment) don't work with remote debugging.
Good point. Here's what we say a little above:

@item The @emph{working directory.}
You can set your program's working directory with the command
@code{set cwd}. If you do not set any working directory with this
command, your program will inherit @value{GDBN}'s working directory if
native debugging, or @code{gdbserver}'s working directory if remote
debugging. @xref{Working Directory, ,Your Program's Working
Directory}.

This makes it clear that the feature works for both scenarios, so I
think it's safe to just remove the sentence on "set cwd". This is what
I'll do.
Post by Pedro Alves
Post by Sergio Durigan Junior
@kindex show cwd
@cindex show inferior's working directory
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}
This reference to "cd" is probably incorrect in this version and should
be "set cwd", right?
Right, fixed. Thanks.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@table @samp
@item OK
The request succeeded.
+
+On UNIX-like targets, it is possible to set the current working
+directory into which it should enter during the startup process.
I don't see why this is talking about Unix-like targets in particular.
You're making it work on Windows too, right? I don't think we should
talk in terms of gdbserver, for the matter. I think the first sentence
could all go away. We should instead say that this packet is used to
inform the remote server of the intended current directory for programs
that are next run.
Makes sense, now that you've pointed out many other places that are
referring to target-specific details. I'll rewrite this part as:

@item QSetWorkingDir:@var{hex-value}
@anchor{QSetWorkingDir packet}
@cindex set working directory, remote request
@cindex @samp{QSetWorkingDir} packet
This packet is used to inform @command{gdbserver} of the intended
current working directory for programs that are going to be executed.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+
+Working Directory}).
Reference to "cd" is stale.
Fixed.
Post by Pedro Alves
Post by Sergio Durigan Junior
+
+mode}).
+
+The request succeeded.
@end table
This packet is not probed by default; the remote stub must request it,
@table @samp
@item OK
The request succeeded.
+
@end table
This packet is not probed by default; the remote stub must request it,
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e78ad4faf1..326d01f4d9 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,12 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f4faff9d77..a159708632 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
return;
}
+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Changed current directory to %s]\n"),
+ path.c_str ());
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2345,7 +2360,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);
if (target_supports_catch_syscall ())
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index cc84d15c2f..b9fff29d74 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,6 +562,7 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;
#ifdef _WIN32_WCE
@@ -586,7 +587,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ inferior_cwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
This path takes a wide string, so you'd need to
do the alloca + mbstowcs above, like done with wprogram.
Ah, didn't know that. Improved the code to do it.
Post by Pedro Alves
Post by Sergio Durigan Junior
#else
@@ -599,7 +600,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 178a3ca15f..a51a3d4e40 100644
+/* Helper function to handle the change of the current working
+ directory in the remote. */
+
+static void
+extended_remote_handle_inferior_cwd (struct remote_state *rs)
I'd call "set", not "handle" (ditto comments). "handle" to me
indicates that you're handling a command that you received. But
here we're sending the command.
OK, done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("\
+Remote replied unexpectedly while changing working directory: %s"),
+ rs->buf);
Please use packet_ok.
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+ }
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9658,6 +9688,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
extended_remote_environment_support (rs);
+ extended_remote_handle_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14126,6 +14158,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index 3a6ffd3862..d3104287a0 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,10 +15,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-if { ![isnative] || [is_remote target] || [is_remote host]
- || [target_info gdb_protocol] == "extended-remote" } then {
- untested "not implemented on gdbserver"
- return
+if { [target_info exists gdb_protocol] } {
+ if { [target_info gdb_protocol] == "remote" } {
+ untested "not implemented on native-gdbserver"
+ return
+ }
+
+ load_lib gdbserver-support.exp
+ if { [skip_gdbserver_tests] } {
+ return
+ }
}
This drops the is_remote host and target checks, but the test is
using "$::env(HOME)", so it really can't work when
remote-host/target testing, because that is accessing HOME in the
build machine (where dejagnu runs) not of the host machine
proc test_tilde_expansion { } {
if { [info exists ::env(HOME)] } {
with_test_prefix "test tilde expansion" {
set home $::env(HOME)
OK, that makes sense, but I wasn't aware that there is a problem between
"host" and "build" machines. This is becoming absurdly confuse to me,
sorry.

In this case, I'd have to check for ![is_remote host], is that right?
Post by Pedro Alves
I don't understand the explicit check for gdbserver in
skip_gdbserver_tests.
I was thinking of the following scenario:

- The users wants to skip gdbserver tests

- He runs the test as "make check-gdb TESTS=gdb.base/set-cwd.exp"

- Because of the unconditional call to "skip_gdbserver_tests", the test
doesn't run at all, even though the test *should* run because the user
hasn't specified any remote board, etc.
Post by Pedro Alves
Seems to me that instead of that, and the "remote" check we should skip
the test if use_gdb_stub, because that's what indicates that when you
connect to a target, you're already debugging something, like with
plain remote debugging.
OK, so a simple check to "[use_gdb_stub]" would suffice, you say? That
doesn't solve the problem with calling ::env above, right?
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-21 01:37:51 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.
Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) the documentation.
No regressions found.
* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_handle_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_handle_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.
* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass "inferior_cwd" to
CreateProcess.
* gdb.base/set-cwd.exp: Make it available on gdbserver.
Mention remote debugging.
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 11 ++++++++++
gdb/common/common-inferior.h | 4 ++++
gdb/doc/gdb.texinfo | 44 ++++++++++++++++++++++++++++++++++----
gdb/gdbserver/inferiors.c | 9 ++++++++
gdb/gdbserver/server.c | 18 +++++++++++++++-
gdb/gdbserver/win32-low.c | 5 +++--
gdb/infcmd.c | 5 ++---
gdb/remote.c | 35 ++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
9 files changed, 131 insertions(+), 14 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 0dcfcc98af..a0f78e4c35 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -39,6 +39,14 @@
variables that are to be set or unset from GDB. These variables
will affect the environment to be passed to the inferior.
+ ** On Unix systems, GDBserver is now able to enter a directory
+ before starting an inferior.
+
+ This is done by using the "cd" command in GDB, which instructs it
+ to tell GDBserver about this directory change the next time an
+ inferior is run. If you want to make GDBserver enter the
+ directory your GDB is currently in, you can do a "cd ." in GDB.
This all looks stale to me.
* New features in the GDB remote stub, GDBserver
** GDBserver is now able to enter a directory before starting an
inferior.
The user can set the desired working directory to be used by the
remote inferior on GDB, using the new "set cwd" command, which
will instruct GDB to tell GDBserver about this directory change
the next time an inferior is run.
Actually, the first sentence is still wrong. How about:

** GDBserver is now able to set the inferior's current working
directory.

The user can set the desired working directory to be used by the
remote inferior on GDB, using the new "set cwd" command, which
will instruct GDB to tell GDBserver about this directory change
the next time an inferior is run.

?
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-22 10:47:12 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
This all looks stale to me.
* New features in the GDB remote stub, GDBserver
** GDBserver is now able to enter a directory before starting an
inferior.
The user can set the desired working directory to be used by the
remote inferior on GDB, using the new "set cwd" command, which
will instruct GDB to tell GDBserver about this directory change
the next time an inferior is run.
I still think this is talking too much in terms of implementation
detail, but I'll reply again to v3.
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,10 +15,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-if { ![isnative] || [is_remote target] || [is_remote host]
- || [target_info gdb_protocol] == "extended-remote" } then {
- untested "not implemented on gdbserver"
- return
+if { [target_info exists gdb_protocol] } {
+ if { [target_info gdb_protocol] == "remote" } {
+ untested "not implemented on native-gdbserver"
+ return
+ }
+
+ load_lib gdbserver-support.exp
+ if { [skip_gdbserver_tests] } {
+ return
+ }
}
This drops the is_remote host and target checks, but the test is
using "$::env(HOME)", so it really can't work when
remote-host/target testing, because that is accessing HOME in the
build machine (where dejagnu runs) not of the host machine
proc test_tilde_expansion { } {
if { [info exists ::env(HOME)] } {
with_test_prefix "test tilde expansion" {
set home $::env(HOME)
OK, that makes sense, but I wasn't aware that there is a problem between
"host" and "build" machines. This is becoming absurdly confuse to me,
sorry.
We've discussed this off list already.
Post by Sergio Durigan Junior
In this case, I'd have to check for ![is_remote host], is that right?
Post by Pedro Alves
I don't understand the explicit check for gdbserver in
skip_gdbserver_tests.
- The users wants to skip gdbserver tests
- He runs the test as "make check-gdb TESTS=gdb.base/set-cwd.exp"
- Because of the unconditional call to "skip_gdbserver_tests", the test
doesn't run at all, even though the test *should* run because the user
hasn't specified any remote board, etc.
And that's what I don't understand at all. skip_gdbserver_tests
is useful for the gdb.server/ tests that spawn gdbserver even
if testing with the local/unix board, i.e., the native target.
But this testcase isn't spawning gdbserver manually, unlike e.g., the
gdb.server/ tests. It just runs against whatever target is
specified by --target_board.
Post by Sergio Durigan Junior
Post by Pedro Alves
Seems to me that instead of that, and the "remote" check we should skip
the test if use_gdb_stub, because that's what indicates that when you
connect to a target, you're already debugging something, like with
plain remote debugging.
OK, so a simple check to "[use_gdb_stub]" would suffice, you say? That
doesn't solve the problem with calling ::env above, right?
Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-22 18:33:19 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
This all looks stale to me.
* New features in the GDB remote stub, GDBserver
** GDBserver is now able to enter a directory before starting an
inferior.
The user can set the desired working directory to be used by the
remote inferior on GDB, using the new "set cwd" command, which
will instruct GDB to tell GDBserver about this directory change
the next time an inferior is run.
I still think this is talking too much in terms of implementation
detail, but I'll reply again to v3.
I'm curious to know why. I'll wait for your review.
Post by Pedro Alves
Post by Sergio Durigan Junior
In this case, I'd have to check for ![is_remote host], is that right?
Post by Pedro Alves
I don't understand the explicit check for gdbserver in
skip_gdbserver_tests.
- The users wants to skip gdbserver tests
- He runs the test as "make check-gdb TESTS=gdb.base/set-cwd.exp"
- Because of the unconditional call to "skip_gdbserver_tests", the test
doesn't run at all, even though the test *should* run because the user
hasn't specified any remote board, etc.
And that's what I don't understand at all. skip_gdbserver_tests
is useful for the gdb.server/ tests that spawn gdbserver even
if testing with the local/unix board, i.e., the native target.
But this testcase isn't spawning gdbserver manually, unlike e.g., the
gdb.server/ tests. It just runs against whatever target is
specified by --target_board.
Ah. Then I *really* misunderstood these concepts. Thanks for
clarifying this to me. v3 still has the call to "skip_gdbserver_tests",
so please ignore it.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-27 13:28:14 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
This all looks stale to me.
* New features in the GDB remote stub, GDBserver
** GDBserver is now able to enter a directory before starting an
inferior.
The user can set the desired working directory to be used by the
remote inferior on GDB, using the new "set cwd" command, which
will instruct GDB to tell GDBserver about this directory change
the next time an inferior is run.
I still think this is talking too much in terms of implementation
detail, but I'll reply again to v3.
I'm curious to know why. I'll wait for your review.
Specifically:

"GDBserver is now able to enter a directory before starting an inferior."

This is Unix/fork specific.

"to tell GDBserver about this directory change"

"change" seems to imply GDBserver itself changes dir. The new inferior
never changes directory because it is started with the specified
directory in the first place.

I'll go look at v3 now.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-19 04:37:14 UTC
Permalink
[ Resending as the original e-mail got bounced because it is too long to
be posted here. ]

The full patch can be seen here:

https://git.sergiodj.net/binutils-gdb.git/commit/?h=sergiodj/set-cwd-command&id=acf35a31bac3951f81d0446564b7f910a0fee21c

These two modules are necessary because of the rework that will be
done in the "change directory" logic on GDB/gdbserver in the next
commits.

First, we will get rid of the "gdb_dirbuf" global variable and instead
rely on the fact that "getcwd (NULL, 0)" returns a heap-allocated
string with the necessary bytes to hold the full path. This is a good
practice not only because globals are not ideal but also because there
is no good way to know beforehand the size of the full pathname
allowed in the filesystem ("PATH_MAX" is not portable and does not
reflect all the possible filesystems out there).

We will also have a way to "cd" to a directory also on gdbserver, but
in order to do that uniformly, there must be a way to do tilde
expansion on directories provided by the user. Currently, GDB uses
"tilde_expand" from readline to do that, but gdbserver doesn't link
against readline and therefore cannot use this function. The solution
is to use "glob" instead, which can perform tilde expansion as a GNU
extension. Therefore, we need gnulib's version of "glob".

As a side note, we no longer need to define "close" on gdb/ser-tcp.c,
so the patch removes that.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gnulib/aclocal.m4: Regenerate.
* gnulib/config.in: Likewise.
* gnulib/configure: Likewise.
* gnulib/import/Makefile.am: Likewise.
* gnulib/import/Makefile.in: Likewise.
* gnulib/import/assure.h: New file.
* gnulib/import/at-func.c: Likewise
* gnulib/import/chdir-long.c: Likewise.
* gnulib/import/chdir-long.h: Likewise.
* gnulib/import/cloexec.c: Likewise.
* gnulib/import/cloexec.h: Likewise.
* gnulib/import/close.c: Likewise.
* gnulib/import/closedir.c: Likewise.
* gnulib/import/dirent-private.h: Likewise.
* gnulib/import/dup-safer.c: Likewise.
* gnulib/import/dup.c: Likewise.
* gnulib/import/dup2.c: Likewise.
* gnulib/import/error.c: Likewise.
* gnulib/import/error.h: Likewise.
* gnulib/import/exitfail.c: Likewise.
* gnulib/import/exitfail.h: Likewise.
* gnulib/import/fchdir.c: Likewise.
* gnulib/import/fcntl.c: Likewise.
* gnulib/import/fcntl.in.h: Likewise.
* gnulib/import/fd-hook.c: Likewise.
* gnulib/import/fd-hook.h: Likewise.
* gnulib/import/fd-safer.c: Likewise.
* gnulib/import/fdopendir.c: Likewise.
* gnulib/import/filename.h: Likewise.
* gnulib/import/filenamecat-lgpl.c: Likewise.
* gnulib/import/filenamecat.h: Likewise.
* gnulib/import/fstat.c: Likewise.
* gnulib/import/fstatat.c: Likewise.
* gnulib/import/getcwd-lgpl.c: Likewise.
* gnulib/import/getcwd.c: Likewise.
* gnulib/import/getdtablesize.c: Likewise.
* gnulib/import/getlogin_r.c: Likewise.
* gnulib/import/getprogname.c: Likewise.
* gnulib/import/getprogname.h: Likewise.
* gnulib/import/gettext.h: Likewise.
* gnulib/import/glob-libc.h: Likewise.
* gnulib/import/glob.c: Likewise.
* gnulib/import/glob.in.h: Likewise.
* gnulib/import/intprops.h: Likewise.
* gnulib/import/m4/chdir-long.m4: Likewise.
* gnulib/import/m4/close.m4: Likewise.
* gnulib/import/m4/closedir.m4: Likewise.
* gnulib/import/m4/d-ino.m4: Likewise.
* gnulib/import/m4/d-type.m4: Likewise.
* gnulib/import/m4/dup.m4: Likewise.
* gnulib/import/m4/dup2.m4: Likewise.
* gnulib/import/m4/error.m4: Likewise.
* gnulib/import/m4/fchdir.m4: Likewise.
* gnulib/import/m4/fcntl.m4: Likewise.
* gnulib/import/m4/fcntl_h.m4: Likewise.
* gnulib/import/m4/fdopendir.m4: Likewise.
* gnulib/import/m4/filenamecat.m4: Likewise.
* gnulib/import/m4/fstat.m4: Likewise.
* gnulib/import/m4/fstatat.m4: Likewise.
* gnulib/import/m4/getcwd-abort-bug.m4: Likewise.
* gnulib/import/m4/getcwd-path-max.m4: Likewise.
* gnulib/import/m4/getcwd.m4: Likewise.
* gnulib/import/m4/getdtablesize.m4: Likewise.
* gnulib/import/m4/getlogin_r.m4: Likewise.
* gnulib/import/m4/getprogname.m4: Likewise.
* gnulib/import/m4/glob.m4: Likewise.
* gnulib/import/m4/gnulib-cache.m4: Regenerate
* gnulib/import/m4/gnulib-comp.m4: Likewise.
* gnulib/import/m4/mempcpy.m4: New file.
* gnulib/import/m4/memrchr.m4: Likewise.
* gnulib/import/m4/mode_t.m4: Likewise.
* gnulib/import/m4/msvc-inval.m4: Likewise.
* gnulib/import/m4/msvc-nothrow.m4: Likewise.
* gnulib/import/m4/open.m4: Likewise.
* gnulib/import/m4/openat.m4: Likewise.
* gnulib/import/m4/opendir.m4: Likewise.
* gnulib/import/m4/readdir.m4: Likewise.
* gnulib/import/m4/realloc.m4: Likewise.
* gnulib/import/m4/rewinddir.m4: Likewise.
* gnulib/import/m4/save-cwd.m4: Likewise.
* gnulib/import/m4/strdup.m4: Likewise.
* gnulib/import/m4/strerror.m4: Likewise.
* gnulib/import/m4/unistd-safer.m4: Likewise.
* gnulib/import/mempcpy.c: Likewise.
* gnulib/import/memrchr.c: Likewise.
* gnulib/import/msvc-inval.c: Likewise.
* gnulib/import/msvc-inval.h: Likewise.
* gnulib/import/msvc-nothrow.c: Likewise.
* gnulib/import/msvc-nothrow.h: Likewise.
* gnulib/import/open.c: Likewise.
* gnulib/import/openat-die.c: Likewise.
* gnulib/import/openat-priv.h: Likewise.
* gnulib/import/openat-proc.c: Likewise.
* gnulib/import/openat.c: Likewise.
* gnulib/import/openat.h: Likewise.
* gnulib/import/opendir.c: Likewise.
* gnulib/import/pipe-safer.c: Likewise.
* gnulib/import/readdir.c: Likewise.
* gnulib/import/realloc.c: Likewise.
* gnulib/import/rewinddir.c: Likewise.
* gnulib/import/save-cwd.c: Likewise.
* gnulib/import/save-cwd.h: Likewise.
* gnulib/import/strdup.c: Likewise.
* gnulib/import/strerror-override.c: Likewise.
* gnulib/import/strerror-override.h: Likewise.
* gnulib/import/strerror.c: Likewise.
* gnulib/import/unistd--.h: Likewise.
* gnulib/import/unistd-safer.h: Likewise.
* gnulib/update-gnulib.sh (IMPORTED_GNULIB_MODULES): Add
"getcwd" and "glob".
* ser-tcp.c: Do not (re)define "close".
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-20 12:17:11 UTC
Permalink
Post by Sergio Durigan Junior
[ Resending as the original e-mail got bounced because it is too long to
be posted here. ]
https://git.sergiodj.net/binutils-gdb.git/commit/?h=sergiodj/set-cwd-command&id=acf35a31bac3951f81d0446564b7f910a0fee21c
These two modules are necessary because of the rework that will be
done in the "change directory" logic on GDB/gdbserver in the next
commits.
First, we will get rid of the "gdb_dirbuf" global variable and instead
rely on the fact that "getcwd (NULL, 0)" returns a heap-allocated
string with the necessary bytes to hold the full path.
Should mention that that's a GNU extension here.
Post by Sergio Durigan Junior
As a side note, we no longer need to define "close" on gdb/ser-tcp.c,
so the patch removes that.
* gnulib/aclocal.m4: Regenerate.
* gnulib/config.in: Likewise.
...
Post by Sergio Durigan Junior
* gnulib/import/unistd-safer.h: Likewise.
Please say "New file." for new files above, not Likewise->Regenerate.
Post by Sergio Durigan Junior
* ser-tcp.c: Do not (re)define "close".
This is:

--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -42,7 +42,6 @@
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
-#define close(fd) closesocket (fd)

Are you sure that the gnulib code that makes close work
for sockets is enabled? I guess it will if WINDOWS_SOCKETS
is defined, but it wasn't obvious to me whether it'll end
up defined with the current set of modules.

Boy, these modules sure bring in a lot of stuff.
I noticed that this is bringing in the strerror module, which was
problematic in the past on mingw [1]. Could you please try
cross building gdb for mingw (should be easy since Fedora has
cross compilers handy), to confirm that it's alright now?
It it works, we could get rid of safe_strerror in a follow up
patch.

[1] https://sourceware.org/ml/gdb-patches/2013-11/msg00597.html
I don't recall whether that's been fixed meanwhile.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-20 17:17:28 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
[ Resending as the original e-mail got bounced because it is too long to
be posted here. ]
https://git.sergiodj.net/binutils-gdb.git/commit/?h=sergiodj/set-cwd-command&id=acf35a31bac3951f81d0446564b7f910a0fee21c
These two modules are necessary because of the rework that will be
done in the "change directory" logic on GDB/gdbserver in the next
commits.
First, we will get rid of the "gdb_dirbuf" global variable and instead
rely on the fact that "getcwd (NULL, 0)" returns a heap-allocated
string with the necessary bytes to hold the full path.
Should mention that that's a GNU extension here.
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
As a side note, we no longer need to define "close" on gdb/ser-tcp.c,
so the patch removes that.
* gnulib/aclocal.m4: Regenerate.
* gnulib/config.in: Likewise.
...
Post by Sergio Durigan Junior
* gnulib/import/unistd-safer.h: Likewise.
Please say "New file." for new files above, not Likewise->Regenerate.
There's actually a "New file." in the middle, and there's also another
"Regenerate." (and yet another "New file.") also.

But I agree that specifying what happened explicitly is better for such
long ChangeLogs. Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
* ser-tcp.c: Do not (re)define "close".
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -42,7 +42,6 @@
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
-#define close(fd) closesocket (fd)
Are you sure that the gnulib code that makes close work
for sockets is enabled? I guess it will if WINDOWS_SOCKETS
is defined, but it wasn't obvious to me whether it'll end
up defined with the current set of modules.
One of the dependencies of "getcwd" is the "close" module, and whenever
I tried to compile this patch with mingw it would fail because of this
re-definition of close made by ser-tcp.c. My first approach was to
#undef close before ser-tcp.c redefined it, but then I decided to just
use "close" from gnulib. I didn't know about this WINDOWS_SOCKETS
requirement; maybe we can define it before the inclusion of <stdlib.h>?
Or maybe choose the safe side and let ser-tcp.c redefine close as
needed.
Post by Pedro Alves
Boy, these modules sure bring in a lot of stuff.
Yeah, "getcwd" did.
Post by Pedro Alves
I noticed that this is bringing in the strerror module, which was
problematic in the past on mingw [1]. Could you please try
cross building gdb for mingw (should be easy since Fedora has
cross compilers handy), to confirm that it's alright now?
It it works, we could get rid of safe_strerror in a follow up
patch.
[1] https://sourceware.org/ml/gdb-patches/2013-11/msg00597.html
I don't recall whether that's been fixed meanwhile.
Before submitting the patch I had compiled it for mingw, and everything
worked OK. I did it again just in case, and it's still working. So I
believe the issue is fixed.
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-20 17:33:24 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -42,7 +42,6 @@
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
-#define close(fd) closesocket (fd)
Are you sure that the gnulib code that makes close work
for sockets is enabled? I guess it will if WINDOWS_SOCKETS
is defined, but it wasn't obvious to me whether it'll end
up defined with the current set of modules.
One of the dependencies of "getcwd" is the "close" module, and whenever
I tried to compile this patch with mingw it would fail because of this
re-definition of close made by ser-tcp.c. My first approach was to
#undef close before ser-tcp.c redefined it, but then I decided to just
use "close" from gnulib. I didn't know about this WINDOWS_SOCKETS
requirement; maybe we can define it before the inclusion of <stdlib.h>?
Or maybe choose the safe side and let ser-tcp.c redefine close as
needed.
I don't know much about WINDOWS_SOCKETS either. I just looked
at gnulib/lib/close.c, and found:

~~~
/* Override close() to call into other gnulib modules. */

int
rpl_close (int fd)
{
#if WINDOWS_SOCKETS
int retval = execute_all_close_hooks (close_nothrow, fd);
#else
int retval = close_nothrow (fd);
#endif

#if REPLACE_FCHDIR
if (retval >= 0)
_gl_unregister_fd (fd);
#endif

return retval;
}
~~~


and then figured out that there's a close_fd_maybe_socket
close hook implemented in lib/sockets.c.

static int
close_fd_maybe_socket (const struct fd_hook *remaining_list,
gl_close_fn primary,
int fd)
{

This is all wrapped in #ifdef WINDOWS_SOCKETS, hence the question.

It should be easy for you to determine whether WINDOWS_SOCKETS
is defined in your mingw build, and thus whether all this code
is part of the build or not.
Post by Sergio Durigan Junior
Post by Pedro Alves
Boy, these modules sure bring in a lot of stuff.
Yeah, "getcwd" did.
Post by Pedro Alves
I noticed that this is bringing in the strerror module, which was
problematic in the past on mingw [1]. Could you please try
cross building gdb for mingw (should be easy since Fedora has
cross compilers handy), to confirm that it's alright now?
It it works, we could get rid of safe_strerror in a follow up
patch.
[1] https://sourceware.org/ml/gdb-patches/2013-11/msg00597.html
I don't recall whether that's been fixed meanwhile.
Before submitting the patch I had compiled it for mingw, and everything
worked OK. I did it again just in case, and it's still working. So I
believe the issue is fixed.
Alright, that's great.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-20 18:31:18 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -42,7 +42,6 @@
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
-#define close(fd) closesocket (fd)
Are you sure that the gnulib code that makes close work
for sockets is enabled? I guess it will if WINDOWS_SOCKETS
is defined, but it wasn't obvious to me whether it'll end
up defined with the current set of modules.
One of the dependencies of "getcwd" is the "close" module, and whenever
I tried to compile this patch with mingw it would fail because of this
re-definition of close made by ser-tcp.c. My first approach was to
#undef close before ser-tcp.c redefined it, but then I decided to just
use "close" from gnulib. I didn't know about this WINDOWS_SOCKETS
requirement; maybe we can define it before the inclusion of <stdlib.h>?
Or maybe choose the safe side and let ser-tcp.c redefine close as
needed.
I don't know much about WINDOWS_SOCKETS either. I just looked
~~~
/* Override close() to call into other gnulib modules. */
int
rpl_close (int fd)
{
#if WINDOWS_SOCKETS
int retval = execute_all_close_hooks (close_nothrow, fd);
#else
int retval = close_nothrow (fd);
#endif
#if REPLACE_FCHDIR
if (retval >= 0)
_gl_unregister_fd (fd);
#endif
return retval;
}
~~~
and then figured out that there's a close_fd_maybe_socket
close hook implemented in lib/sockets.c.
static int
close_fd_maybe_socket (const struct fd_hook *remaining_list,
gl_close_fn primary,
int fd)
{
This is all wrapped in #ifdef WINDOWS_SOCKETS, hence the question.
It should be easy for you to determine whether WINDOWS_SOCKETS
is defined in your mingw build, and thus whether all this code
is part of the build or not.
I will do that and report back. Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-20 20:30:42 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -42,7 +42,6 @@
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
-#define close(fd) closesocket (fd)
Are you sure that the gnulib code that makes close work
for sockets is enabled? I guess it will if WINDOWS_SOCKETS
is defined, but it wasn't obvious to me whether it'll end
up defined with the current set of modules.
One of the dependencies of "getcwd" is the "close" module, and whenever
I tried to compile this patch with mingw it would fail because of this
re-definition of close made by ser-tcp.c. My first approach was to
#undef close before ser-tcp.c redefined it, but then I decided to just
use "close" from gnulib. I didn't know about this WINDOWS_SOCKETS
requirement; maybe we can define it before the inclusion of <stdlib.h>?
Or maybe choose the safe side and let ser-tcp.c redefine close as
needed.
I don't know much about WINDOWS_SOCKETS either. I just looked
~~~
/* Override close() to call into other gnulib modules. */
int
rpl_close (int fd)
{
#if WINDOWS_SOCKETS
int retval = execute_all_close_hooks (close_nothrow, fd);
#else
int retval = close_nothrow (fd);
#endif
#if REPLACE_FCHDIR
if (retval >= 0)
_gl_unregister_fd (fd);
#endif
return retval;
}
~~~
and then figured out that there's a close_fd_maybe_socket
close hook implemented in lib/sockets.c.
static int
close_fd_maybe_socket (const struct fd_hook *remaining_list,
gl_close_fn primary,
int fd)
{
This is all wrapped in #ifdef WINDOWS_SOCKETS, hence the question.
It should be easy for you to determine whether WINDOWS_SOCKETS
is defined in your mingw build, and thus whether all this code
is part of the build or not.
I will do that and report back. Thanks,
WINDOWS_SOCKETS is not defined when building with the mingw compiler
from Fedora. This means that removing that "#define" was actually not
correct, because "close" will not work as expected even with gnulib.

My proposal is to define "close" as it was being defined before, but
actually "#undef" it if it's already defined by other headers, like:

#ifdef close
#undef close
#endif
#define close(fd) closesocket (fd)

Does that work for you?
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-20 22:43:54 UTC
Permalink
Post by Sergio Durigan Junior
Post by Sergio Durigan Junior
Post by Pedro Alves
This is all wrapped in #ifdef WINDOWS_SOCKETS, hence the question.
It should be easy for you to determine whether WINDOWS_SOCKETS
is defined in your mingw build, and thus whether all this code
is part of the build or not.
I will do that and report back. Thanks,
WINDOWS_SOCKETS is not defined when building with the mingw compiler
from Fedora. This means that removing that "#define" was actually not
correct, because "close" will not work as expected even with gnulib.
Looks like it's defined by gnulib/m4/socketlib.m4, and seemingly
we're not pulling in that module.
Post by Sergio Durigan Junior
My proposal is to define "close" as it was being defined before, but
#ifdef close
#undef close
#endif
#define close(fd) closesocket (fd)
Does that work for you?
(There's no need of wrap #undef with #ifdef/#endif. That's redundant.)

That'd #undef 'close' on all hosts, even if gnulib decides to
replace it for some reason. E.g., REPLACE_FCHDIR
check in rpl_close (see my previous email).

How about we switch close/closesocket around:

#ifndef USE_WIN32API
# define closesocket close
#endif

And then use closesocket instead of close?

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-20 23:12:35 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Sergio Durigan Junior
Post by Pedro Alves
This is all wrapped in #ifdef WINDOWS_SOCKETS, hence the question.
It should be easy for you to determine whether WINDOWS_SOCKETS
is defined in your mingw build, and thus whether all this code
is part of the build or not.
I will do that and report back. Thanks,
WINDOWS_SOCKETS is not defined when building with the mingw compiler
from Fedora. This means that removing that "#define" was actually not
correct, because "close" will not work as expected even with gnulib.
Looks like it's defined by gnulib/m4/socketlib.m4, and seemingly
we're not pulling in that module.
Post by Sergio Durigan Junior
My proposal is to define "close" as it was being defined before, but
#ifdef close
#undef close
#endif
#define close(fd) closesocket (fd)
Does that work for you?
(There's no need of wrap #undef with #ifdef/#endif. That's redundant.)
That'd #undef 'close' on all hosts, even if gnulib decides to
replace it for some reason. E.g., REPLACE_FCHDIR
check in rpl_close (see my previous email).
Not all hosts; only on hosts that define USE_WIN32API. This would
basically make sure we stick to the current behaviour, which is to
always define "close" as "closesocket" on win32.
Post by Pedro Alves
#ifndef USE_WIN32API
# define closesocket close
#endif
And then use closesocket instead of close?
That'd work, but my preference is to use "close" everywhere because
that's the de facto way of dealing with sockets. Only win32 hosts need
this "closesocket" thing, and I don't think it makes sense to base use
this name in our sources.

But that's my opinion; if you want, I can reverse the logic on the
define's.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-20 23:25:29 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
(There's no need of wrap #undef with #ifdef/#endif. That's redundant.)
That'd #undef 'close' on all hosts, even if gnulib decides to
replace it for some reason. E.g., REPLACE_FCHDIR
check in rpl_close (see my previous email).
Not all hosts; only on hosts that define USE_WIN32API. This would
basically make sure we stick to the current behaviour, which is to
always define "close" as "closesocket" on win32.
Ah, this is all wrapped in #ifdef USE_WIN32API. Missed that,
somehow.
Post by Sergio Durigan Junior
Post by Pedro Alves
#ifndef USE_WIN32API
# define closesocket close
#endif
And then use closesocket instead of close?
That'd work, but my preference is to use "close" everywhere because
that's the de facto way of dealing with sockets. Only win32 hosts need
this "closesocket" thing, and I don't think it makes sense to base use
this name in our sources.
But that's my opinion; if you want, I can reverse the logic on the
define's.
I don't see the problem. Imagine it as if struct serial had
been C++-ified already, making struct ser_tcp a class, and we
added a private method like this:

void
ser_tcp::closesocket ()
{
#ifdef USE_WIN32API
::closesocket (fd);
#else
close (fd);
#endif
}

Then we'd be calling closesocket instead of close. :-)

Actually, that's pretty much the existing net_close, and
we call it in several places instead of close directly
in very nearby code:

...
close (scb->fd);
goto retry;
}
if (err)
errno = err;
net_close (scb);
...

Eh.

But I digress...

The #undef close approach is fine with me too
since it turns out that's wrapped in #if USE_WIN32API,
and I missed it the first time.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-21 22:59:21 UTC
Permalink
v1: https://sourceware.org/ml/gdb-patches/2017-09/msg00321.html
v2: https://sourceware.org/ml/gdb-patches/2017-09/msg00458.html

Changes from v2:

* Patch #1:

- Mention that "getcwd (NULL, 0)" is a GNU extension on the commit
log.

- Rewrite ChangeLog to explicitly say "New file"/"Regenerate"
instead of "Likewise".

- Do not remove definition of "close" on gdb/ser-tcp.c; instead,
"#undef close" before (re)defining it as "closesocket".

* Patch #2:

- Fix s/target/host/ on commit log.

- Remove call to '.get ()' method on "gdb::unique_xmalloc_ptr<char>"
when checking to see if it was initialized correctly.

* Patch #3:

- This now introduces "gdb_tilde_expand" instead of "gdb_chdir".

- Improve cases when using a "gdb::unique_xmalloc_ptr<char>" would
be better.

- Fix method declaration format inside classes.

* Patch #4:

- Add sentence on "cd" command's help text explaining what the GDB's
cwd affects.

- Improve documentation and explain that cwd changes via "set cwd"
only take effect the next time the inferior is started.

- Remove implementation details that explained how UNIX-like targets
change the inferior's cwd from a few comments.

- Declare "cwd" field from "struct inferior" as
"gdb::unique_xmalloc_ptr<char>".

- Improve message displayed by "show cwd" when the user hasn't set
the cwd.

- Improve way that "fork_inferior" changes the directory before
executing the inferior, obeying the async-signal-safe restriction
of the function.

- Update Windows code to deal with wide strings.

- Remove BUFSIZ from the testcase C file.

- Fix/improve the way we detect if the testcase is running on a
remote debugging scenario.

- Based on a private conversation I had with Pedro, the
"test_tilde_expansion" method has also been rewritten to avoid
problems when we're dealing with a remote host.

- Implement failure detection when gathering information about the
cwd before/after running the inferior.

- Use gdb_assert.

* Patch #5:

- Update text on gdb/NEWS.

- Remove target-specific implementation detail from
"set_inferior_cwd"'s comment.

- Remove sentence explicitly saying that "set cwd" works for both
native and remote debugging.

- Update text of "QSetWorkingDir" packet description and make it
target-independent, as well as update a few references.

- Update Windows code to deal with wide strings.

- s/extended_remote_handle_inferior_cwd/extended_remote_set_inferior_cwd/

- Use packet_ok.

- Again, update the testcase in order to better detect when we're
dealing with gdbserver test.



This patch series is a followup of the discussion that happened at:

https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html

It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
command works for both native and remote debugging scenarios.

The idea here is that "set cwd" will become the de facto way of
setting the inferior's cwd. Currently, the user can use "cd" for
that, but there are side effects: with "cd", GDB also switches to
another directory, and that can impact the loading of scripts and
other files. With "set cwd", we separate the logic into a new
command.

To maintain backward compatibility, if the user issues a "cd" command
but doesn't use "set cwd", then the inferior's cwd will still be
changed according to what the user specified. However, "set cwd" has
precedence over "cd", so it can always be used to override it.
Sergio Durigan Junior
2017-09-21 22:59:23 UTC
Permalink
Currently we have "current_directory" and "gdb_dirbuf" globals, which
means that we basically have two possible places to consult when we
want to know GDB's current working directory.

This is not ideal and can lead to confusion. Moreover, the way we're
using "gdb_difbuf" along with "getcwd" is problematic because we
declare the buffer with "1024" elements hardcoded, which does not take
into account longer pathnames that are possible in many filesystems.
Using "PATH_MAX" would also not be a solution because of portability
problems. Therefore, the best solution is to rely on the fact that
"getcwd (NULL, 0)" will "do the right thing" and return a
heap-allocated string containing the full path. With the new "getcwd"
module from gnulib, it is now possible to do that without worrying
about breaking some host.

With this patch "current_directory" is now the only place to check for
GDB's cwd.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* cli/cli-cmds.c (pwd_command): Use "getcwd (NULL, 0)".
(cd_command): Likewise. Free "current_directory" before
assigning to it.
* main.c (captured_main_1): Use "getcwd (NULL, 0)".
* mi/mi-cmd-env.c (mi_cmd_env_pwd): Likewise.
* top.c (gdb_dirbuf): Remove global declaration.
* top.h (gdb_dirbuf): Likewise.
---
gdb/cli/cli-cmds.c | 17 ++++++++++++-----
gdb/main.c | 5 ++---
gdb/mi/mi-cmd-env.c | 8 ++++----
gdb/top.c | 3 ---
gdb/top.h | 1 -
5 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 260fd3f635..cbafb13837 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -384,13 +384,16 @@ pwd_command (char *args, int from_tty)
{
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+
+ if (cwd == NULL)
error (_("Error finding name of working directory: %s"),
safe_strerror (errno));

- if (strcmp (gdb_dirbuf, current_directory) != 0)
+ if (strcmp (cwd.get (), current_directory) != 0)
printf_unfiltered (_("Working directory %s\n (canonically %s).\n"),
- current_directory, gdb_dirbuf);
+ current_directory, cwd.get ());
else
printf_unfiltered (_("Working directory %s.\n"), current_directory);
}
@@ -418,7 +421,8 @@ cd_command (char *dir, int from_tty)
/* There's too much mess with DOSish names like "d:", "d:.",
"d:./foo" etc. Instead of having lots of special #ifdef'ed code,
simply get the canonicalized name of the current directory. */
- dir = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ dir = cwd.get ();
#endif

len = strlen (dir);
@@ -436,7 +440,10 @@ cd_command (char *dir, int from_tty)

dir_holder.reset (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
- current_directory = dir_holder.release ();
+ {
+ xfree (current_directory);
+ current_directory = dir_holder.release ();
+ }
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
diff --git a/gdb/main.c b/gdb/main.c
index fe80511243..66ba75ba21 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -549,11 +549,10 @@ captured_main_1 (struct captured_main_args *context)
(xstrprintf ("%s: warning: ", gdb_program_name));
warning_pre_print = tmp_warn_preprint.get ();

- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+ current_directory = getcwd (NULL, 0);
+ if (current_directory == NULL)
perror_warning_with_name (_("error finding working directory"));

- current_directory = gdb_dirbuf;
-
/* Set the sysroot path. */
gdb_sysroot = relocate_gdb_directory (TARGET_SYSTEM_ROOT,
TARGET_SYSTEM_ROOT_RELOCATABLE);
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 977b6e274d..db87ead33d 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -73,12 +73,12 @@ mi_cmd_env_pwd (const char *command, char **argv, int argc)
}

/* Otherwise the mi level is 2 or higher. */
-
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ if (cwd == NULL)
error (_("-environment-pwd: error finding name of working directory: %s"),
safe_strerror (errno));
-
- uiout->field_string ("cwd", gdb_dirbuf);
+
+ uiout->field_string ("cwd", cwd.get ());
}

/* Change working directory. */
diff --git a/gdb/top.c b/gdb/top.c
index 404e096755..c89e78f243 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -133,9 +133,6 @@ show_confirm (struct ui_file *file, int from_tty,

char *current_directory;

-/* The directory name is actually stored here (usually). */
-char gdb_dirbuf[1024];
-
/* The last command line executed on the console. Used for command
repetitions. */
char *saved_command_line;
diff --git a/gdb/top.h b/gdb/top.h
index 45798897f6..6b66083995 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -219,7 +219,6 @@ extern void ui_unregister_input_event_handler (struct ui *ui);
/* From top.c. */
extern char *saved_command_line;
extern int confirm;
-extern char gdb_dirbuf[1024];
extern int inhibit_gdbinit;
extern const char gdbinit[];
--
2.13.3
Pedro Alves
2017-09-22 11:19:00 UTC
Permalink
Post by Sergio Durigan Junior
* cli/cli-cmds.c (pwd_command): Use "getcwd (NULL, 0)".
(cd_command): Likewise. Free "current_directory" before
assigning to it.
* main.c (captured_main_1): Use "getcwd (NULL, 0)".
* mi/mi-cmd-env.c (mi_cmd_env_pwd): Likewise.
* top.c (gdb_dirbuf): Remove global declaration.
* top.h (gdb_dirbuf): Likewise.
OK. And trying the new thing:

Reviewed-by: Pedro Alves <***@redhat.com>

... provided the nit below is addressed.

You can push patches 1 and 2 now, without waiting for the
rest of the series.
Post by Sergio Durigan Junior
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 977b6e274d..db87ead33d 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -73,12 +73,12 @@ mi_cmd_env_pwd (const char *command, char **argv, int argc)
}
/* Otherwise the mi level is 2 or higher. */
-
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
Please leave the empty line after the comment. That comment is
logically related to the code above, not the getcwd call.
Post by Sergio Durigan Junior
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ if (cwd == NULL)
error (_("-environment-pwd: error finding name of working directory: %s"),
safe_strerror (errno));
-
- uiout->field_string ("cwd", gdb_dirbuf);
+
+ uiout->field_string ("cwd", cwd.get ());
}
Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-22 17:30:30 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
* cli/cli-cmds.c (pwd_command): Use "getcwd (NULL, 0)".
(cd_command): Likewise. Free "current_directory" before
assigning to it.
* main.c (captured_main_1): Use "getcwd (NULL, 0)".
* mi/mi-cmd-env.c (mi_cmd_env_pwd): Likewise.
* top.c (gdb_dirbuf): Remove global declaration.
* top.h (gdb_dirbuf): Likewise.
... provided the nit below is addressed.
AFAIU I had to add this to the commit log. I did this; if this wasn't
correct, I apologize.
Post by Pedro Alves
Post by Sergio Durigan Junior
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 977b6e274d..db87ead33d 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -73,12 +73,12 @@ mi_cmd_env_pwd (const char *command, char **argv, int argc)
}
/* Otherwise the mi level is 2 or higher. */
-
- if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
Please leave the empty line after the comment. That comment is
logically related to the code above, not the getcwd call.
Done.
Post by Pedro Alves
Post by Sergio Durigan Junior
+ gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ if (cwd == NULL)
error (_("-environment-pwd: error finding name of working directory: %s"),
safe_strerror (errno));
-
- uiout->field_string ("cwd", gdb_dirbuf);
+
+ uiout->field_string ("cwd", cwd.get ());
}
Thanks,
Pedro Alves
Pushed.

43573013c9836f2b91b74b9b29dac35fdb41e06b

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-21 22:59:22 UTC
Permalink
This patch is too long to send to the mailing list, so I'm making it
available here:

https://git.sergiodj.net/binutils-gdb.git/commit/?h=sergiodj/set-cwd-command&id=ba0db8beb2ee1f75aa923338639c8185afc92fe5

These two modules are necessary because of the rework that will be
done in the "change directory" logic on GDB/gdbserver in the next
commits.

First, we will get rid of the "gdb_dirbuf" global variable and instead
rely on the fact that "getcwd (NULL, 0)", which is a GNU extension,
returns a heap-allocated string with the necessary bytes to hold the
full path. This is a good practice not only because globals are not
ideal but also because there is no good way to know beforehand the
size of the full pathname allowed in the filesystem ("PATH_MAX" is not
portable and does not reflect all the possible filesystems out there).

We will also have a way to "cd" to a directory also on gdbserver, but
in order to do that uniformly, there must be a way to do tilde
expansion on directories provided by the user. Currently, GDB uses
"tilde_expand" from readline to do that, but gdbserver doesn't link
against readline and therefore cannot use this function. The solution
is to use "glob" instead, which can perform tilde expansion as a GNU
extension. Therefore, we need gnulib's version of "glob".

A special note is necessary for gdb/ser-tcp.c. It defines "close" as
"closesocket" on Win32 targets. If we leave the code as is, this
would conflict with gnulib's definition of "close". Therefore, in
order to keep the same code path from before this import, I decided to
"#undef close" first, and then let the original (re)definition of it
take place.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gnulib/aclocal.m4: Regenerate.
* gnulib/config.in: Regenerate.
* gnulib/configure: Regenerate.
* gnulib/import/Makefile.am: Regenerate.
* gnulib/import/Makefile.in: Regenerate.
* gnulib/import/assure.h: New file.
* gnulib/import/at-func.c: Likewise
* gnulib/import/chdir-long.c: New file.
* gnulib/import/chdir-long.h: New file.
* gnulib/import/cloexec.c: New file.
* gnulib/import/cloexec.h: New file.
* gnulib/import/close.c: New file.
* gnulib/import/closedir.c: New file.
* gnulib/import/dirent-private.h: New file.
* gnulib/import/dup-safer.c: New file.
* gnulib/import/dup.c: New file.
* gnulib/import/dup2.c: New file.
* gnulib/import/error.c: New file.
* gnulib/import/error.h: New file.
* gnulib/import/exitfail.c: New file.
* gnulib/import/exitfail.h: New file.
* gnulib/import/fchdir.c: New file.
* gnulib/import/fcntl.c: New file.
* gnulib/import/fcntl.in.h: New file.
* gnulib/import/fd-hook.c: New file.
* gnulib/import/fd-hook.h: New file.
* gnulib/import/fd-safer.c: New file.
* gnulib/import/fdopendir.c: New file.
* gnulib/import/filename.h: New file.
* gnulib/import/filenamecat-lgpl.c: New file.
* gnulib/import/filenamecat.h: New file.
* gnulib/import/fstat.c: New file.
* gnulib/import/fstatat.c: New file.
* gnulib/import/getcwd-lgpl.c: New file.
* gnulib/import/getcwd.c: New file.
* gnulib/import/getdtablesize.c: New file.
* gnulib/import/getlogin_r.c: New file.
* gnulib/import/getprogname.c: New file.
* gnulib/import/getprogname.h: New file.
* gnulib/import/gettext.h: New file.
* gnulib/import/glob-libc.h: New file.
* gnulib/import/glob.c: New file.
* gnulib/import/glob.in.h: New file.
* gnulib/import/intprops.h: New file.
* gnulib/import/m4/chdir-long.m4: New file.
* gnulib/import/m4/close.m4: New file.
* gnulib/import/m4/closedir.m4: New file.
* gnulib/import/m4/d-ino.m4: New file.
* gnulib/import/m4/d-type.m4: New file.
* gnulib/import/m4/dup.m4: New file.
* gnulib/import/m4/dup2.m4: New file.
* gnulib/import/m4/error.m4: New file.
* gnulib/import/m4/fchdir.m4: New file.
* gnulib/import/m4/fcntl.m4: New file.
* gnulib/import/m4/fcntl_h.m4: New file.
* gnulib/import/m4/fdopendir.m4: New file.
* gnulib/import/m4/filenamecat.m4: New file.
* gnulib/import/m4/fstat.m4: New file.
* gnulib/import/m4/fstatat.m4: New file.
* gnulib/import/m4/getcwd-abort-bug.m4: New file.
* gnulib/import/m4/getcwd-path-max.m4: New file.
* gnulib/import/m4/getcwd.m4: New file.
* gnulib/import/m4/getdtablesize.m4: New file.
* gnulib/import/m4/getlogin_r.m4: New file.
* gnulib/import/m4/getprogname.m4: New file.
* gnulib/import/m4/glob.m4: New file.
* gnulib/import/m4/gnulib-cache.m4: Regenerate
* gnulib/import/m4/gnulib-comp.m4: Regenerate.
* gnulib/import/m4/mempcpy.m4: New file.
* gnulib/import/m4/memrchr.m4: New file.
* gnulib/import/m4/mode_t.m4: New file.
* gnulib/import/m4/msvc-inval.m4: New file.
* gnulib/import/m4/msvc-nothrow.m4: New file.
* gnulib/import/m4/open.m4: New file.
* gnulib/import/m4/openat.m4: New file.
* gnulib/import/m4/opendir.m4: New file.
* gnulib/import/m4/readdir.m4: New file.
* gnulib/import/m4/realloc.m4: New file.
* gnulib/import/m4/rewinddir.m4: New file.
* gnulib/import/m4/save-cwd.m4: New file.
* gnulib/import/m4/strdup.m4: New file.
* gnulib/import/m4/strerror.m4: New file.
* gnulib/import/m4/unistd-safer.m4: New file.
* gnulib/import/mempcpy.c: New file.
* gnulib/import/memrchr.c: New file.
* gnulib/import/msvc-inval.c: New file.
* gnulib/import/msvc-inval.h: New file.
* gnulib/import/msvc-nothrow.c: New file.
* gnulib/import/msvc-nothrow.h: New file.
* gnulib/import/open.c: New file.
* gnulib/import/openat-die.c: New file.
* gnulib/import/openat-priv.h: New file.
* gnulib/import/openat-proc.c: New file.
* gnulib/import/openat.c: New file.
* gnulib/import/openat.h: New file.
* gnulib/import/opendir.c: New file.
* gnulib/import/pipe-safer.c: New file.
* gnulib/import/readdir.c: New file.
* gnulib/import/realloc.c: New file.
* gnulib/import/rewinddir.c: New file.
* gnulib/import/save-cwd.c: New file.
* gnulib/import/save-cwd.h: New file.
* gnulib/import/strdup.c: New file.
* gnulib/import/strerror-override.c: New file.
* gnulib/import/strerror-override.h: New file.
* gnulib/import/strerror.c: New file.
* gnulib/import/unistd--.h: New file.
* gnulib/import/unistd-safer.h: New file.
* gnulib/update-gnulib.sh (IMPORTED_GNULIB_MODULES): Add
"getcwd" and "glob".
* ser-tcp.c: Undefine "close" before redefining it.
---
gdb/gnulib/aclocal.m4 | 37 +
gdb/gnulib/config.in | 267 +
gdb/gnulib/configure | 12423 +++++++++++++++++++----------
gdb/gnulib/import/Makefile.am | 421 +-
gdb/gnulib/import/Makefile.in | 236 +-
gdb/gnulib/import/assure.h | 37 +
gdb/gnulib/import/at-func.c | 146 +
gdb/gnulib/import/chdir-long.c | 264 +
gdb/gnulib/import/chdir-long.h | 30 +
gdb/gnulib/import/cloexec.c | 83 +
gdb/gnulib/import/cloexec.h | 38 +
gdb/gnulib/import/close.c | 69 +
gdb/gnulib/import/closedir.c | 71 +
gdb/gnulib/import/dirent-private.h | 40 +
gdb/gnulib/import/dup-safer.c | 34 +
gdb/gnulib/import/dup.c | 86 +
gdb/gnulib/import/dup2.c | 215 +
gdb/gnulib/import/error.c | 406 +
gdb/gnulib/import/error.h | 75 +
gdb/gnulib/import/exitfail.c | 24 +
gdb/gnulib/import/exitfail.h | 18 +
gdb/gnulib/import/fchdir.c | 208 +
gdb/gnulib/import/fcntl.c | 414 +
gdb/gnulib/import/fcntl.in.h | 363 +
gdb/gnulib/import/fd-hook.c | 116 +
gdb/gnulib/import/fd-hook.h | 119 +
gdb/gnulib/import/fd-safer.c | 49 +
gdb/gnulib/import/fdopendir.c | 249 +
gdb/gnulib/import/filename.h | 54 +
gdb/gnulib/import/filenamecat-lgpl.c | 88 +
gdb/gnulib/import/filenamecat.h | 27 +
gdb/gnulib/import/fstat.c | 88 +
gdb/gnulib/import/fstatat.c | 135 +
gdb/gnulib/import/getcwd-lgpl.c | 126 +
gdb/gnulib/import/getcwd.c | 446 ++
gdb/gnulib/import/getdtablesize.c | 121 +
gdb/gnulib/import/getlogin_r.c | 87 +
gdb/gnulib/import/getprogname.c | 151 +
gdb/gnulib/import/getprogname.h | 40 +
gdb/gnulib/import/gettext.h | 292 +
gdb/gnulib/import/glob-libc.h | 212 +
gdb/gnulib/import/glob.c | 1808 +++++
gdb/gnulib/import/glob.in.h | 93 +
gdb/gnulib/import/intprops.h | 464 ++
gdb/gnulib/import/m4/chdir-long.m4 | 30 +
gdb/gnulib/import/m4/close.m4 | 33 +
gdb/gnulib/import/m4/closedir.m4 | 30 +
gdb/gnulib/import/m4/d-ino.m4 | 56 +
gdb/gnulib/import/m4/d-type.m4 | 32 +
gdb/gnulib/import/m4/dup.m4 | 45 +
gdb/gnulib/import/m4/dup2.m4 | 117 +
gdb/gnulib/import/m4/error.m4 | 27 +
gdb/gnulib/import/m4/fchdir.m4 | 61 +
gdb/gnulib/import/m4/fcntl.m4 | 126 +
gdb/gnulib/import/m4/fcntl_h.m4 | 50 +
gdb/gnulib/import/m4/fdopendir.m4 | 61 +
gdb/gnulib/import/m4/filenamecat.m4 | 16 +
gdb/gnulib/import/m4/fstat.m4 | 36 +
gdb/gnulib/import/m4/fstatat.m4 | 60 +
gdb/gnulib/import/m4/getcwd-abort-bug.m4 | 140 +
gdb/gnulib/import/m4/getcwd-path-max.m4 | 217 +
gdb/gnulib/import/m4/getcwd.m4 | 162 +
gdb/gnulib/import/m4/getdtablesize.m4 | 46 +
gdb/gnulib/import/m4/getlogin_r.m4 | 88 +
gdb/gnulib/import/m4/getprogname.m4 | 43 +
gdb/gnulib/import/m4/glob.m4 | 76 +
gdb/gnulib/import/m4/gnulib-cache.m4 | 4 +-
gdb/gnulib/import/m4/gnulib-comp.m4 | 317 +
gdb/gnulib/import/m4/mempcpy.m4 | 26 +
gdb/gnulib/import/m4/memrchr.m4 | 23 +
gdb/gnulib/import/m4/mode_t.m4 | 26 +
gdb/gnulib/import/m4/msvc-inval.m4 | 19 +
gdb/gnulib/import/m4/msvc-nothrow.m4 | 10 +
gdb/gnulib/import/m4/open.m4 | 91 +
gdb/gnulib/import/m4/openat.m4 | 36 +
gdb/gnulib/import/m4/opendir.m4 | 31 +
gdb/gnulib/import/m4/readdir.m4 | 15 +
gdb/gnulib/import/m4/realloc.m4 | 79 +
gdb/gnulib/import/m4/rewinddir.m4 | 15 +
gdb/gnulib/import/m4/save-cwd.m4 | 11 +
gdb/gnulib/import/m4/strdup.m4 | 36 +
gdb/gnulib/import/m4/strerror.m4 | 96 +
gdb/gnulib/import/m4/unistd-safer.m4 | 10 +
gdb/gnulib/import/mempcpy.c | 28 +
gdb/gnulib/import/memrchr.c | 161 +
gdb/gnulib/import/msvc-inval.c | 129 +
gdb/gnulib/import/msvc-inval.h | 222 +
gdb/gnulib/import/msvc-nothrow.c | 49 +
gdb/gnulib/import/msvc-nothrow.h | 43 +
gdb/gnulib/import/open.c | 181 +
gdb/gnulib/import/openat-die.c | 62 +
gdb/gnulib/import/openat-priv.h | 64 +
gdb/gnulib/import/openat-proc.c | 134 +
gdb/gnulib/import/openat.c | 286 +
gdb/gnulib/import/openat.h | 123 +
gdb/gnulib/import/opendir.c | 169 +
gdb/gnulib/import/pipe-safer.c | 56 +
gdb/gnulib/import/readdir.c | 98 +
gdb/gnulib/import/realloc.c | 79 +
gdb/gnulib/import/rewinddir.c | 49 +
gdb/gnulib/import/save-cwd.c | 99 +
gdb/gnulib/import/save-cwd.h | 34 +
gdb/gnulib/import/strdup.c | 54 +
gdb/gnulib/import/strerror-override.c | 302 +
gdb/gnulib/import/strerror-override.h | 56 +
gdb/gnulib/import/strerror.c | 70 +
gdb/gnulib/import/unistd--.h | 32 +
gdb/gnulib/import/unistd-safer.h | 31 +
gdb/gnulib/update-gnulib.sh | 2 +
gdb/ser-tcp.c | 1 +
110 files changed, 21324 insertions(+), 4457 deletions(-)
create mode 100644 gdb/gnulib/import/assure.h
create mode 100644 gdb/gnulib/import/at-func.c
create mode 100644 gdb/gnulib/import/chdir-long.c
create mode 100644 gdb/gnulib/import/chdir-long.h
create mode 100644 gdb/gnulib/import/cloexec.c
create mode 100644 gdb/gnulib/import/cloexec.h
create mode 100644 gdb/gnulib/import/close.c
create mode 100644 gdb/gnulib/import/closedir.c
create mode 100644 gdb/gnulib/import/dirent-private.h
create mode 100644 gdb/gnulib/import/dup-safer.c
create mode 100644 gdb/gnulib/import/dup.c
create mode 100644 gdb/gnulib/import/dup2.c
create mode 100644 gdb/gnulib/import/error.c
create mode 100644 gdb/gnulib/import/error.h
create mode 100644 gdb/gnulib/import/exitfail.c
create mode 100644 gdb/gnulib/import/exitfail.h
create mode 100644 gdb/gnulib/import/fchdir.c
create mode 100644 gdb/gnulib/import/fcntl.c
create mode 100644 gdb/gnulib/import/fcntl.in.h
create mode 100644 gdb/gnulib/import/fd-hook.c
create mode 100644 gdb/gnulib/import/fd-hook.h
create mode 100644 gdb/gnulib/import/fd-safer.c
create mode 100644 gdb/gnulib/import/fdopendir.c
create mode 100644 gdb/gnulib/import/filename.h
create mode 100644 gdb/gnulib/import/filenamecat-lgpl.c
create mode 100644 gdb/gnulib/import/filenamecat.h
create mode 100644 gdb/gnulib/import/fstat.c
create mode 100644 gdb/gnulib/import/fstatat.c
create mode 100644 gdb/gnulib/import/getcwd-lgpl.c
create mode 100644 gdb/gnulib/import/getcwd.c
create mode 100644 gdb/gnulib/import/getdtablesize.c
create mode 100644 gdb/gnulib/import/getlogin_r.c
create mode 100644 gdb/gnulib/import/getprogname.c
create mode 100644 gdb/gnulib/import/getprogname.h
create mode 100644 gdb/gnulib/import/gettext.h
create mode 100644 gdb/gnulib/import/glob-libc.h
create mode 100644 gdb/gnulib/import/glob.c
create mode 100644 gdb/gnulib/import/glob.in.h
create mode 100644 gdb/gnulib/import/intprops.h
create mode 100644 gdb/gnulib/import/m4/chdir-long.m4
create mode 100644 gdb/gnulib/import/m4/close.m4
create mode 100644 gdb/gnulib/import/m4/closedir.m4
create mode 100644 gdb/gnulib/import/m4/d-ino.m4
create mode 100644 gdb/gnulib/import/m4/d-type.m4
create mode 100644 gdb/gnulib/import/m4/dup.m4
create mode 100644 gdb/gnulib/import/m4/dup2.m4
create mode 100644 gdb/gnulib/import/m4/error.m4
create mode 100644 gdb/gnulib/import/m4/fchdir.m4
create mode 100644 gdb/gnulib/import/m4/fcntl.m4
create mode 100644 gdb/gnulib/import/m4/fcntl_h.m4
create mode 100644 gdb/gnulib/import/m4/fdopendir.m4
create mode 100644 gdb/gnulib/import/m4/filenamecat.m4
create mode 100644 gdb/gnulib/import/m4/fstat.m4
create mode 100644 gdb/gnulib/import/m4/fstatat.m4
create mode 100644 gdb/gnulib/import/m4/getcwd-abort-bug.m4
create mode 100644 gdb/gnulib/import/m4/getcwd-path-max.m4
create mode 100644 gdb/gnulib/import/m4/getcwd.m4
create mode 100644 gdb/gnulib/import/m4/getdtablesize.m4
create mode 100644 gdb/gnulib/import/m4/getlogin_r.m4
create mode 100644 gdb/gnulib/import/m4/getprogname.m4
create mode 100644 gdb/gnulib/import/m4/glob.m4
create mode 100644 gdb/gnulib/import/m4/mempcpy.m4
create mode 100644 gdb/gnulib/import/m4/memrchr.m4
create mode 100644 gdb/gnulib/import/m4/mode_t.m4
create mode 100644 gdb/gnulib/import/m4/msvc-inval.m4
create mode 100644 gdb/gnulib/import/m4/msvc-nothrow.m4
create mode 100644 gdb/gnulib/import/m4/open.m4
create mode 100644 gdb/gnulib/import/m4/openat.m4
create mode 100644 gdb/gnulib/import/m4/opendir.m4
create mode 100644 gdb/gnulib/import/m4/readdir.m4
create mode 100644 gdb/gnulib/import/m4/realloc.m4
create mode 100644 gdb/gnulib/import/m4/rewinddir.m4
create mode 100644 gdb/gnulib/import/m4/save-cwd.m4
create mode 100644 gdb/gnulib/import/m4/strdup.m4
create mode 100644 gdb/gnulib/import/m4/strerror.m4
create mode 100644 gdb/gnulib/import/m4/unistd-safer.m4
create mode 100644 gdb/gnulib/import/mempcpy.c
create mode 100644 gdb/gnulib/import/memrchr.c
create mode 100644 gdb/gnulib/import/msvc-inval.c
create mode 100644 gdb/gnulib/import/msvc-inval.h
create mode 100644 gdb/gnulib/import/msvc-nothrow.c
create mode 100644 gdb/gnulib/import/msvc-nothrow.h
create mode 100644 gdb/gnulib/import/open.c
create mode 100644 gdb/gnulib/import/openat-die.c
create mode 100644 gdb/gnulib/import/openat-priv.h
create mode 100644 gdb/gnulib/import/openat-proc.c
create mode 100644 gdb/gnulib/import/openat.c
create mode 100644 gdb/gnulib/import/openat.h
create mode 100644 gdb/gnulib/import/opendir.c
create mode 100644 gdb/gnulib/import/pipe-safer.c
create mode 100644 gdb/gnulib/import/readdir.c
create mode 100644 gdb/gnulib/import/realloc.c
create mode 100644 gdb/gnulib/import/rewinddir.c
create mode 100644 gdb/gnulib/import/save-cwd.c
create mode 100644 gdb/gnulib/import/save-cwd.h
create mode 100644 gdb/gnulib/import/strdup.c
create mode 100644 gdb/gnulib/import/strerror-override.c
create mode 100644 gdb/gnulib/import/strerror-override.h
create mode 100644 gdb/gnulib/import/strerror.c
create mode 100644 gdb/gnulib/import/unistd--.h
create mode 100644 gdb/gnulib/import/unistd-safer.h
Pedro Alves
2017-09-22 11:01:36 UTC
Permalink
Post by Sergio Durigan Junior
* gnulib/import/m4/gnulib-cache.m4: Regenerate
Missing period.
Post by Sergio Durigan Junior
* ser-tcp.c: Undefine "close" before redefining it.
diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c
index f35991c..c8be37b 100644
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -42,6 +42,7 @@
Post by Sergio Durigan Junior
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
+#undef close
#define close(fd) closesocket (fd)
#define ioctl ioctlsocket
#else
Please add a comment. Something like:

/* Gnulib defines close too, but gnulib's replacement
doesn't call closesocket unless we import the
socketlib module. */

Otherwise OK.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-22 17:29:32 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
* gnulib/import/m4/gnulib-cache.m4: Regenerate
Missing period.
Fixed.
Post by Pedro Alves
Post by Sergio Durigan Junior
* ser-tcp.c: Undefine "close" before redefining it.
diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c
index f35991c..c8be37b 100644
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -42,6 +42,7 @@
Post by Sergio Durigan Junior
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
+#undef close
#define close(fd) closesocket (fd)
#define ioctl ioctlsocket
#else
/* Gnulib defines close too, but gnulib's replacement
doesn't call closesocket unless we import the
socketlib module. */
Added.
Post by Pedro Alves
Otherwise OK.
Pushed.

6ec2e0f5bddc69d55e09fe56792edf7a109ff8ae

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-21 22:59:24 UTC
Permalink
Currently, whenever we want to handle paths provided by the user and
perform tilde expansion on GDB, we rely on "tilde_expand", which comes
from readline. This was enough for our use cases so far, but the
situation will change when we start dealing with paths on gdbserver as
well, which is what the next patches implement.

Unfortunately it is not possible to use "tilde_expand" in this case
because gdbserver doesn't use readline. For that reason I decided to
implement a new "gdb_tilde_expand" function, which is basically a
wrapper for "glob" and its GNU extension, GLOB_TILDE. With the import
of the "glob" module from gnulib, this is a no-brainer.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add gdb_tilde_expand.c.
(HFILES_NO_SRCDIR): Add gdb_tilde_expand.h.
(COMMON_OBS): Add gdb_tilde_expand.o.
* cli/cli-cmds.c: Include "gdb_tilde_expand.h".
(cd_command): Use "gdb_tilde_expand" instead of "tilde_expand".
* common/gdb_tilde_expand.c: New file.
* common/gdb_tilde_expand.h: Likewise.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add $(srcdir)/common/gdb_tilde_expand.c.
(OBS): Add gdb_tilde_expand.o.
---
gdb/Makefile.in | 3 ++
gdb/cli/cli-cmds.c | 10 +++---
gdb/common/gdb_tilde_expand.c | 82 +++++++++++++++++++++++++++++++++++++++++++
gdb/common/gdb_tilde_expand.h | 27 ++++++++++++++
gdb/gdbserver/Makefile.in | 2 ++
5 files changed, 119 insertions(+), 5 deletions(-)
create mode 100644 gdb/common/gdb_tilde_expand.c
create mode 100644 gdb/common/gdb_tilde_expand.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5740d43bb7..d0e3ed2917 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1245,6 +1245,7 @@ SFILES = \
common/filestuff.c \
common/format.c \
common/job-control.c \
+ common/gdb_tilde_expand.c \
common/gdb_vecs.c \
common/new-op.c \
common/print-utils.c \
@@ -1529,6 +1530,7 @@ HFILES_NO_SRCDIR = \
common/fileio.h \
common/format.h \
common/gdb_assert.h \
+ common/gdb_tilde_expand.h \
common/gdb_locale.h \
common/gdb_setjmp.h \
common/gdb_signals.h \
@@ -1734,6 +1736,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
frame-unwind.o \
gcore.o \
gdb_bfd.o \
+ gdb_tilde_expand.o \
gdb-dlfcn.o \
gdb_obstack.o \
gdb_regex.o \
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index cbafb13837..507fdc4120 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -54,6 +54,8 @@
#include "tui/tui.h" /* For tui_active et.al. */
#endif

+#include "gdb_tilde_expand.h"
+
#include <fcntl.h>
#include <algorithm>
#include <string>
@@ -410,10 +412,8 @@ cd_command (char *dir, int from_tty)
repeat might be useful but is more likely to be a mistake. */
dont_repeat ();

- gdb::unique_xmalloc_ptr<char> dir_holder
- (tilde_expand (dir != NULL ? dir : "~"));
- dir = dir_holder.get ();
-
+ std::string expanded_path = gdb_tilde_expand (dir != NULL ? dir : "~");
+ dir = (char *) expanded_path.c_str ();
if (chdir (dir) < 0)
perror_with_name (dir);

@@ -438,7 +438,7 @@ cd_command (char *dir, int from_tty)
len--;
}

- dir_holder.reset (savestring (dir, len));
+ gdb::unique_xmalloc_ptr<char> dir_holder (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
{
xfree (current_directory);
diff --git a/gdb/common/gdb_tilde_expand.c b/gdb/common/gdb_tilde_expand.c
new file mode 100644
index 0000000000..08ff4190d2
--- /dev/null
+++ b/gdb/common/gdb_tilde_expand.c
@@ -0,0 +1,82 @@
+/* Perform tilde expansion on paths for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "common-defs.h"
+#include "gdb_tilde_expand.h"
+#include <glob.h>
+
+/* RAII-style class wrapping "glob". */
+
+class gdb_glob
+{
+public:
+ /* Construct a "gdb_glob" object by calling "glob" with the provided
+ parameters. This function can throw if "glob" fails. */
+ gdb_glob (const char *pattern, int flags,
+ int (*errfunc) (const char *epath, int eerrno))
+ {
+ int ret = glob (pattern, flags, errfunc, &m_glob);
+
+ if (ret != 0)
+ {
+ if (ret == GLOB_NOMATCH)
+ error (_("Could not find a match for '%s'."), pattern);
+ else
+ error (_("glob could not process pattern '%s'."),
+ pattern);
+ }
+ }
+
+ /* Destroy the object and free M_GLOB. */
+ ~gdb_glob ()
+ {
+ globfree (&m_glob);
+ }
+
+ /* Return the GL_PATHC component of M_GLOB. */
+ int pathc () const
+ {
+ return m_glob.gl_pathc;
+ }
+
+ /* Return the GL_PATHV component of M_GLOB. */
+ char **pathv () const
+ {
+ return m_glob.gl_pathv;
+ }
+
+private:
+ /* The actual glob object we're dealing with. */
+ glob_t m_glob;
+};
+
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
+
+ gdb_assert (glob.pathc () > 0);
+ /* "glob" may return more than one match to the path provided by the
+ user, but we are only interested in the first match. */
+ std::string expanded_dir = glob.pathv ()[0];
+
+ return expanded_dir;
+}
diff --git a/gdb/common/gdb_tilde_expand.h b/gdb/common/gdb_tilde_expand.h
new file mode 100644
index 0000000000..a5d923d66b
--- /dev/null
+++ b/gdb/common/gdb_tilde_expand.h
@@ -0,0 +1,27 @@
+/* Perform tilde expansion on paths for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef HAVE_GDB_TILDE_EXPAND_H
+#define HAVE_GDB_TILDE_EXPAND_H
+
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+extern std::string gdb_tilde_expand (const char *dir);
+
+#endif /* ! HAVE_GDB_TILDE_EXPAND_H */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1bbe515629..6c931ba952 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -205,6 +205,7 @@ SFILES = \
$(srcdir)/common/fileio.c \
$(srcdir)/common/filestuff.c \
$(srcdir)/common/job-control.c \
+ $(srcdir)/common/gdb_tilde_expand.c \
$(srcdir)/common/gdb_vecs.c \
$(srcdir)/common/new-op.c \
$(srcdir)/common/print-utils.c \
@@ -247,6 +248,7 @@ OBS = \
fileio.o \
filestuff.o \
format.o \
+ gdb_tilde_expand.o \
gdb_vecs.o \
hostio.o \
inferiors.o \
--
2.13.3
Pedro Alves
2017-09-22 11:57:30 UTC
Permalink
Post by Sergio Durigan Junior
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index cbafb13837..507fdc4120 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -54,6 +54,8 @@
#include "tui/tui.h" /* For tui_active et.al. */
#endif
+#include "gdb_tilde_expand.h"
+
#include <fcntl.h>
#include <algorithm>
#include <string>
@@ -410,10 +412,8 @@ cd_command (char *dir, int from_tty)
repeat might be useful but is more likely to be a mistake. */
dont_repeat ();
- gdb::unique_xmalloc_ptr<char> dir_holder
- (tilde_expand (dir != NULL ? dir : "~"));
- dir = dir_holder.get ();
-
+ std::string expanded_path = gdb_tilde_expand (dir != NULL ? dir : "~");
+ dir = (char *) expanded_path.c_str ();
if (chdir (dir) < 0)
perror_with_name (dir);
@@ -438,7 +438,7 @@ cd_command (char *dir, int from_tty)
len--;
}
- dir_holder.reset (savestring (dir, len));
+ gdb::unique_xmalloc_ptr<char> dir_holder (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
{
xfree (current_directory);
I realized something: in light of the fact that "cd" is not what
is used to specify the inferior's cwd anymore since v1, patching
this particular use of tilde_expand, and not others seems arbitrary.

I.e., this now looks like kind of a spurious change to me, and
I think you should drop the changes to this file...
Post by Sergio Durigan Junior
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
By my reading of man glob, GLOB_TILDE_CHECK already implies GLOB_TILDE.

I'm not sure whether GLOB_ONLYDIR is the right thing to do in
a function whose name doesn't suggest that it concern itself
with anything other than tilde expansion. E.g., if we replaced
tilde_expand with gdb_tilde_expand in place that expect to match
files (like e.g., gdb_print_filename), then would this work as is?

Maybe you should rename this to gdb_tilde_expand_dir (leaving
the file names as is).

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-22 17:37:17 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index cbafb13837..507fdc4120 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -54,6 +54,8 @@
#include "tui/tui.h" /* For tui_active et.al. */
#endif
+#include "gdb_tilde_expand.h"
+
#include <fcntl.h>
#include <algorithm>
#include <string>
@@ -410,10 +412,8 @@ cd_command (char *dir, int from_tty)
repeat might be useful but is more likely to be a mistake. */
dont_repeat ();
- gdb::unique_xmalloc_ptr<char> dir_holder
- (tilde_expand (dir != NULL ? dir : "~"));
- dir = dir_holder.get ();
-
+ std::string expanded_path = gdb_tilde_expand (dir != NULL ? dir : "~");
+ dir = (char *) expanded_path.c_str ();
if (chdir (dir) < 0)
perror_with_name (dir);
@@ -438,7 +438,7 @@ cd_command (char *dir, int from_tty)
len--;
}
- dir_holder.reset (savestring (dir, len));
+ gdb::unique_xmalloc_ptr<char> dir_holder (savestring (dir, len));
if (IS_ABSOLUTE_PATH (dir_holder.get ()))
{
xfree (current_directory);
I realized something: in light of the fact that "cd" is not what
is used to specify the inferior's cwd anymore since v1, patching
this particular use of tilde_expand, and not others seems arbitrary.
I.e., this now looks like kind of a spurious change to me, and
I think you should drop the changes to this file...
Yeah, you're right. I still intend to keep the cleanups, if that's OK
for you.
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
By my reading of man glob, GLOB_TILDE_CHECK already implies GLOB_TILDE.
Yes, but I think it pays to be explicit in this case.
Post by Pedro Alves
I'm not sure whether GLOB_ONLYDIR is the right thing to do in
a function whose name doesn't suggest that it concern itself
with anything other than tilde expansion. E.g., if we replaced
tilde_expand with gdb_tilde_expand in place that expect to match
files (like e.g., gdb_print_filename), then would this work as is?
Maybe you should rename this to gdb_tilde_expand_dir (leaving
the file names as is).
Or I could simply remove GLOB_ONLYDIR (which is a leftover from the
previous versions of the patch) and make this function generic. In
fact, I think I prefer this approach, because according to the manpage:

GLOB_ONLYDIR
This is a hint to glob() that the caller is interested
only in directories that match the pattern. If the
implementation can easily determine file-type
information, then nondirectory files are not returned
to the caller. However, the caller must still check
that returned files are directories. (The purpose of
this flag is merely to optimize performance when the
caller is interested only in directories.)

I.e., it's only a helper flag for "glob".

I'll remove GLOB_ONLYDIR and resubmit the patch.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-22 17:41:48 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
I realized something: in light of the fact that "cd" is not what
is used to specify the inferior's cwd anymore since v1, patching
this particular use of tilde_expand, and not others seems arbitrary.
I.e., this now looks like kind of a spurious change to me, and
I think you should drop the changes to this file...
Yeah, you're right. I still intend to keep the cleanups, if that's OK
for you.
I don't know what you mean by that.
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
By my reading of man glob, GLOB_TILDE_CHECK already implies GLOB_TILDE.
Yes, but I think it pays to be explicit in this case.
I think it only adds to confusion. I did "man glob",
saw that GLOB_TILDE_CHECK implies GLOB_TILDE and then
got to wonder why is GLOB_TILDE being passed explicitly.
Post by Sergio Durigan Junior
I'll remove GLOB_ONLYDIR and resubmit the patch.
Fine with me.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-22 18:07:24 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
I realized something: in light of the fact that "cd" is not what
is used to specify the inferior's cwd anymore since v1, patching
this particular use of tilde_expand, and not others seems arbitrary.
I.e., this now looks like kind of a spurious change to me, and
I think you should drop the changes to this file...
Yeah, you're right. I still intend to keep the cleanups, if that's OK
for you.
I don't know what you mean by that.
Sorry, I hadn't really understood what you were saying. I will remove
the changes to gdb/cli/cli-cmds.c from the patch.
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
By my reading of man glob, GLOB_TILDE_CHECK already implies GLOB_TILDE.
Yes, but I think it pays to be explicit in this case.
I think it only adds to confusion. I did "man glob",
saw that GLOB_TILDE_CHECK implies GLOB_TILDE and then
got to wonder why is GLOB_TILDE being passed explicitly.
Well, I personally don't really see the reason for the confusion here
since you could have read GLOB_TILDE's entry as well and noticed that
there is nothing fancy being done here, but I respect your way of
thinking, so I will just remove GLOB_TILDE_CHECK.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-22 18:20:36 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
By my reading of man glob, GLOB_TILDE_CHECK already implies GLOB_TILDE.
Yes, but I think it pays to be explicit in this case.
I think it only adds to confusion. I did "man glob",
saw that GLOB_TILDE_CHECK implies GLOB_TILDE and then
got to wonder why is GLOB_TILDE being passed explicitly.
Well, I personally don't really see the reason for the confusion here
since you could have read GLOB_TILDE's entry as well and noticed that
there is nothing fancy being done here, but I respect your way of
thinking, so I will just remove GLOB_TILDE_CHECK.
I did not suggest to remove GLOB_TILDE_CHECK.

What I'm saying is that the man page looks like this:

GLOB_TILDE
Carry out tilde expansion. (...)

GLOB_TILDE_CHECK
This provides behavior similar to that of GLOB_TILDE. The difference is that (...)

And from reading this, my interpretation is that GLOB_TILDE
and GLOB_TILDE_CHECK are two different modes. From that
description, I'd think it reasonable for glob to reject
"GLOB_TILDE | GLOB_TILDE_CHECK" as ambiguous -- which mode
to you want with that?

Note that it says "provides behavior similar", not
"in combination with GLOB_TILDE".

With GLOB_TILDE | GLOB_TILDE_CHECK, I assumed that you
meant GLOB_TILDE_CHECK, but I have no idea whether that's
what all glob implementations actually end up interpreting
it as. But why leave that ambiguity? Just specify what
you want, exactly.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-22 18:22:01 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE | GLOB_TILDE_CHECK | GLOB_ONLYDIR, NULL);
By my reading of man glob, GLOB_TILDE_CHECK already implies GLOB_TILDE.
Yes, but I think it pays to be explicit in this case.
I think it only adds to confusion. I did "man glob",
saw that GLOB_TILDE_CHECK implies GLOB_TILDE and then
got to wonder why is GLOB_TILDE being passed explicitly.
Well, I personally don't really see the reason for the confusion here
since you could have read GLOB_TILDE's entry as well and noticed that
there is nothing fancy being done here, but I respect your way of
thinking, so I will just remove GLOB_TILDE_CHECK.
I did not suggest to remove GLOB_TILDE_CHECK.
Sorry, my bad, I meant "remove GLOB_TILDE".
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-21 22:59:25 UTC
Permalink
This is the actual implementation of the "set/show cwd" commands on
GDB. The way they work is:

- If the user sets the inferior's cwd by using "set cwd", then this
directory is saved into current_inferior ()->cwd and is used when
the inferior is started (see below).

- If the user doesn't set the inferior's cwd by using "set cwd", but
rather use the "cd" command as before, then this directory is
inherited by the inferior because GDB will have chdir'd into it.

On Unix-like hosts, the way the directory is changed before the
inferior execution is by expanding the user set directory before the
fork, and then "chdir" after the call to fork/vfork on
"fork_inferior", but before the actual execution. On Windows, the
inferior cwd set by the user is passed directly to the CreateProcess
call, which takes care of the actual chdir for us.

This way, we'll make sure that GDB's cwd is not affected by the user
set cwd.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* NEWS (New commands): Mention "set/show cwd".
* cli/cli-cmds.c (_initialize_cli_cmds): Mention "set cwd" on
"cd" command's help text.
* common/common-inferior.h (get_inferior_cwd): New prototype.
* infcmd.c (inferior_cwd_scratch): New global variable.
(set_inferior_cwd): New function.
(get_inferior_cwd): Likewise.
(set_cwd_command): Likewise.
(show_cwd_command): Likewise.
(_initialize_infcmd): Add "set/show cwd" commands.
* inferior.h (class inferior) <cwd>: New field.
* nat/fork-inferior.c: Include "gdb_tilde_expand.h".
(fork_inferior): Change inferior's cwd before its execution.
* windows-nat.c (windows_create_inferior): Pass inferior's cwd
to CreateProcess.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* inferiors.c (current_inferior_cwd): New global variable.
(get_inferior_cwd): New function.
* inferiors.h (struct process_info) <cwd>: New field.

gdb/doc/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.texinfo (Starting your Program) <The working directory.>:
Mention new "set cwd" command.
(Working Directory) <Your Program's Working Directory>:
Rephrase to explain that "set cwd" exists and is the default
way to change the inferior's cwd.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.base/set-cwd.c: New file.
* gdb.base/set-cwd.exp: Likewise.
---
gdb/NEWS | 3 +
gdb/cli/cli-cmds.c | 8 ++-
gdb/common/common-inferior.h | 4 ++
gdb/doc/gdb.texinfo | 35 +++++++---
gdb/gdbserver/inferiors.c | 11 +++
gdb/infcmd.c | 72 +++++++++++++++++++
gdb/inferior.h | 4 ++
gdb/nat/fork-inferior.c | 18 +++++
gdb/testsuite/gdb.base/set-cwd.c | 32 +++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 140 +++++++++++++++++++++++++++++++++++++
gdb/windows-nat.c | 13 +++-
11 files changed, 327 insertions(+), 13 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/set-cwd.c
create mode 100644 gdb/testsuite/gdb.base/set-cwd.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 549f511b29..c131713293 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -64,6 +64,9 @@ QStartupWithShell

* New commands

+set|show cwd
+ Set and show the current working directory for the inferior.
+
set|show compile-gcc
Set and show compilation command used for compiling and injecting code
with the 'compile' commands.
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 507fdc4120..14e6a06d68 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1731,9 +1731,11 @@ The commands below can be used to select other frames by number or address."),
Print working directory. This is used for your program as well."));

c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
+The debugger's current working directory specifies where scripts and other\n\
+files that can be loaded by GDB are located.\n\
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
set_cmd_completer (c, filename_completer);

add_com ("echo", class_support, echo_command, _("\
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 87c13009ed..515a8c0f4e 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -30,4 +30,8 @@ extern const char *get_exec_wrapper ();
otherwise return 0 in that case. */
extern char *get_exec_file (int err);

+/* Return the inferior's current working directory. If nothing has
+ been set, then return NULL. */
+extern const char *get_inferior_cwd ();
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6b320891ad..899afb92b6 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2057,8 +2057,9 @@ environment} to change parts of the environment that affect
your program. @xref{Environment, ,Your Program's Environment}.

@item The @emph{working directory.}
-Your program inherits its working directory from @value{GDBN}. You can set
-the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}.
+You can set your program's working directory with the command
+@code{set cwd}. If you do not set any working directory with this
+command, your program will inherit @value{GDBN}'s working directory.
@xref{Working Directory, ,Your Program's Working Directory}.

@item The @emph{standard input and output.}
@@ -2434,19 +2435,37 @@ variables to files that are only run when you sign on, such as
@section Your Program's Working Directory

@cindex working directory (of your program)
-Each time you start your program with @code{run}, it inherits its
-working directory from the current working directory of @value{GDBN}.
-The @value{GDBN} working directory is initially whatever it inherited
-from its parent process (typically the shell), but you can specify a new
-working directory in @value{GDBN} with the @code{cd} command.
+Each time you start your program with @code{run}, the inferior will be
+initialized with the current working directory specified by the
+@code{set cwd} command. If no directory has been specified by this
+command, then the inferior will inherit @value{GDBN}'s current working
+directory as its working directory.
+
+You can also change @value{GDBN}'s current working directory by using
+the @code{cd} command.

The @value{GDBN} working directory also serves as a default for the commands
that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to
Specify Files}.

@table @code
+@kindex set cwd
+@cindex change inferior's working directory
+@item set cwd @r{[}@var{directory}@r{]}
+Set the inferior's working directory to @var{directory}. If not
+given, @var{directory} uses @file{'~'}. This has no effect on
+@value{GDBN}'s working directory. This setting only takes effect the
+next time you start the inferior.
+
+@kindex show cwd
+@cindex show inferior's working directory
+@item show cwd
+Show the inferior's working directory. If no directory has been
+specified by @code{set cwd}, then the default inferior's working
+directory is the same as @value{GDBN}'s working directory.
+
@kindex cd
-@cindex change working directory
+@cindex change @value{GDBN}'s working directory
@item cd @r{[}@var{directory}@r{]}
Set the @value{GDBN} working directory to @var{directory}. If not
given, @var{directory} uses @file{'~'}.
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 72f0412757..e78ad4faf1 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,9 @@ struct thread_info *current_thread;

#define get_thread(inf) ((struct thread_info *)(inf))

+/* The current working directory used to start the inferior. */
+static const char *current_inferior_cwd = NULL;
+
void
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
@@ -445,3 +448,11 @@ switch_to_thread (ptid_t ptid)
if (!ptid_equal (ptid, minus_one_ptid))
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 9c0cead434..4c5bbfdbf2 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -111,6 +111,10 @@ static void run_command (char *, int);

static char *inferior_args_scratch;

+/* Scratch area where the new cwd will be stored by 'set cwd'. */
+
+static char *inferior_cwd_scratch;
+
/* Scratch area where 'set inferior-tty' will store user-provided value.
We'll immediate copy it into per-inferior storage. */

@@ -246,6 +250,55 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}

+/* Set the inferior current working directory. */
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ if (*cwd == '\0')
+ error (_("You must specify a directory."));
+
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+ inf->cwd.reset (xstrdup (cwd));
+}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior ()->cwd.get ();
+}
+
+/* Handle the 'set cwd' command. */
+
+static void
+set_cwd_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_inferior_cwd (inferior_cwd_scratch);
+}
+
+/* Handle the 'show cwd' command. */
+
+static void
+show_cwd_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd == NULL)
+ fprintf_filtered (gdb_stdout,
+ _("\
+You have not set the inferior's current working directory.\n\
+The inferior will inherit GDB's cwd.\n"));
+ else
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+

/* Compute command-line string given argument vector. This does the
same shell processing as fork_inferior. */
@@ -3262,6 +3315,25 @@ Follow this command with any number of args, to be passed to the program."),
gdb_assert (c != NULL);
set_cmd_completer (c, filename_completer);

+ cmd_name = "cwd";
+ add_setshow_string_noescape_cmd (cmd_name, class_run,
+ &inferior_cwd_scratch, _("\
+Set the current working directory to be used when the inferior is started.\n\
+Changing this setting does not have any effect on inferiors that are\n\
+already running."),
+ _("\
+Show the current working directory that is used when the inferior is started."),
+ _("\
+Use this command to change the current working directory that will be used\n\
+when the inferior is started. This setting does not affect GDB's current\n\
+working directory."),
+ set_cwd_command,
+ show_cwd_command,
+ &setlist, &showlist);
+ c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+ gdb_assert (c != NULL);
+ set_cmd_completer (c, filename_completer);
+
c = add_cmd ("environment", no_class, environment_info, _("\
The environment to give the program, or one variable's value.\n\
With an argument VAR, prints the value of environment variable VAR to\n\
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 7f2d53e5b3..498d74706a 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -355,6 +355,10 @@ public:
should never be freed. */
char **argv = NULL;

+ /* The current working directory that will be used when starting
+ this inferior. */
+ gdb::unique_xmalloc_ptr<char> cwd;
+
/* The name of terminal device to use for I/O. */
char *terminal = NULL;

diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index 6ff119768c..0ce442f162 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -25,6 +25,7 @@
#include "common-inferior.h"
#include "common-gdbthread.h"
#include "signals-state-save-restore.h"
+#include "gdb_tilde_expand.h"
#include <vector>

extern char **environ;
@@ -298,6 +299,8 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
char **save_our_env;
int i;
int save_errno;
+ const char *inferior_cwd;
+ std::string expanded_inferior_cwd;

/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
@@ -339,6 +342,13 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
the parent and child flushing the same data after the fork. */
gdb_flush_out_err ();

+ /* Check if the user wants to set a different working directory for
+ the inferior. */
+ inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ expanded_inferior_cwd = gdb_tilde_expand (inferior_cwd);
+
/* If there's any initialization of the target layers that must
happen to prepare to handle the child we're about fork, do it
now... */
@@ -374,6 +384,14 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();

+ /* Change to the requested working directory if the user
+ requested it. */
+ if (inferior_cwd != NULL)
+ {
+ if (chdir (expanded_inferior_cwd.c_str ()) < 0)
+ trace_start_error_with_name (expanded_inferior_cwd.c_str ());
+ }
+
if (debug_fork)
sleep (debug_fork);

diff --git a/gdb/testsuite/gdb.base/set-cwd.c b/gdb/testsuite/gdb.base/set-cwd.c
new file mode 100644
index 0000000000..2a501aa675
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.c
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static char dir[4096];
+
+int
+main (int argc, char *argv[])
+{
+ const char *home = getenv ("HOME");
+
+ getcwd (dir, 4096);
+
+ return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
new file mode 100644
index 0000000000..f2700ec44d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -0,0 +1,140 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
+ untested "not implemented on gdbserver"
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ global decimal gdb_prompt hex
+
+ with_test_prefix "test tilde expansion" {
+ gdb_test_no_output "set cwd ~/" "set cwd to ~/ dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test_multiple "print home" "print home var" {
+ -re "\\\$$decimal = $hex \"\(.+\)\"\r\n$gdb_prompt $" {
+ set home $expect_out(1,string)
+ }
+ -re "$gdb_prompt $" {
+ untested "could to retrieve home var"
+ return
+ }
+ default {
+ untested "could to retrieve home var"
+ return
+ }
+ }
+
+ if { [string length $home] > 0 } {
+ gdb_test_multiple "print dir" "print dir var" {
+ -re "\\\$$decimal = \"\(.+\)\"\(, .*repeats.*\)?\r\n$gdb_prompt $" {
+ set curdir $expect_out(1,string)
+ }
+ -re "$gdb_prompt $" {
+ fail "failed to retrieve dir var"
+ return -1
+ }
+ default {
+ fail "failed to retrieve dir var"
+ return -1
+ }
+ }
+
+ gdb_assert [string equal $curdir $home] \
+ "successfully chdir'd into home"
+ } else {
+ untested "could not determine value of HOME"
+ return
+ }
+ }
+}
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain cwd before run"
+ return -1
+ }
+ default {
+ fail "failed to obtain cwd before run"
+ return -1
+ }
+ }
+
+ set tmpdir [standard_output_file ""]
+
+ gdb_test_no_output "set cwd $tmpdir" "set cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain cwd after run"
+ return -1
+ }
+ default {
+ fail "failed to obtain cwd after run"
+ return -1
+ }
+ }
+
+ gdb_assert [string equal $gdb_cwd_before_run $gdb_cwd_after_run] \
+ "GDB cwd is unchanged after running inferior"
+ }
+}
+
+test_cd_into_dir
+clean_restart $binfile
+test_tilde_expansion
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 3e1894410d..c762222654 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2432,6 +2432,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
cygwin_buf_t *toexec;
cygwin_buf_t *cygallargs;
cygwin_buf_t *args;
+ cygwin_buf_t *infcwd;
char **old_env = NULL;
PWCHAR w32_env;
size_t len;
@@ -2461,6 +2462,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
BOOL ret;
DWORD flags = 0;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ const char *inferior_cwd = get_inferior_cwd ();

if (!exec_file)
error (_("No executable specified, use `target exec'."));
@@ -2488,8 +2490,15 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
error (_("Error starting executable: %d"), errno);
cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
mbstowcs (cygallargs, allargs, len);
+
+ len = mbstowcs (NULL, inferior_cwd, 0) + 1;
+ if (len == (size_t) -1)
+ error (_("Invalid cwd for inferior: %d"), errno);
+ infcwd = (wchar_t *) alloca (len * sizeof (wchar_t));
+ mbstowcs (infcwd, inferior_cwd, len);
#else /* !__USEWIDE */
cygallargs = allargs;
+ infcwd = (cygwin_buf_t *) inferior_cwd;
#endif
}
else
@@ -2574,7 +2583,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32_env, /* environment */
- NULL, /* current directory */
+ infcwd, /* current directory */
&si,
&pi);
if (w32_env)
@@ -2697,7 +2706,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32env, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si,
&pi);
if (tty != INVALID_HANDLE_VALUE)
--
2.13.3
Eli Zaretskii
2017-09-22 08:02:57 UTC
Permalink
Date: Thu, 21 Sep 2017 18:59:25 -0400
This is the actual implementation of the "set/show cwd" commands on
- If the user sets the inferior's cwd by using "set cwd", then this
directory is saved into current_inferior ()->cwd and is used when
the inferior is started (see below).
- If the user doesn't set the inferior's cwd by using "set cwd", but
rather use the "cd" command as before, then this directory is
inherited by the inferior because GDB will have chdir'd into it.
On Unix-like hosts, the way the directory is changed before the
inferior execution is by expanding the user set directory before the
fork, and then "chdir" after the call to fork/vfork on
"fork_inferior", but before the actual execution. On Windows, the
inferior cwd set by the user is passed directly to the CreateProcess
call, which takes care of the actual chdir for us.
Thanks, I have some comments.
diff --git a/gdb/NEWS b/gdb/NEWS
index 549f511b29..c131713293 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -64,6 +64,9 @@ QStartupWithShell
* New commands
+set|show cwd
+ Set and show the current working directory for the inferior.
+
set|show compile-gcc
Set and show compilation command used for compiling and injecting code
with the 'compile' commands.
This part is OK.
I think we should document here what does "~" mean on MS-Windows,
especially since, when HOME is not in the environment, Gnulib's glob
module doesn't behave according to MS platform recommendations (which
say not to create files directly below %HOMEDRIVE%%HOMEPATH%).

More generally, I think we should say here that the argument is
glob-expanded, because this is user-visible behavior (right?). Also,
how will TAB-completion react to input of this command? will it expand
the input typed so far?
+Show the inferior's working directory. If no directory has been
Does this show the original value typed by the user, or the expanded
value? E.g., if the user types "set cwd ~/foo", what will "show cwd"
display? If it shows the unexpanded form, does that mean the actual
cwd will change if, say, HOME changes?

Should we store the cwd after tilde-expansion?
@@ -2461,6 +2462,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
BOOL ret;
DWORD flags = 0;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ const char *inferior_cwd = get_inferior_cwd ();
if (!exec_file)
error (_("No executable specified, use `target exec'."));
@@ -2488,8 +2490,15 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
error (_("Error starting executable: %d"), errno);
cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
mbstowcs (cygallargs, allargs, len);
+
+ len = mbstowcs (NULL, inferior_cwd, 0) + 1;
+ if (len == (size_t) -1)
+ error (_("Invalid cwd for inferior: %d"), errno);
+ infcwd = (wchar_t *) alloca (len * sizeof (wchar_t));
+ mbstowcs (infcwd, inferior_cwd, len);
#else /* !__USEWIDE */
cygallargs = allargs;
+ infcwd = (cygwin_buf_t *) inferior_cwd;
#endif
}
else
@@ -2574,7 +2583,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32_env, /* environment */
- NULL, /* current directory */
+ infcwd, /* current directory */
&si,
&pi);
if (w32_env)
@@ -2697,7 +2706,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32env, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si,
&pi);
if (tty != INVALID_HANDLE_VALUE)
This seems to pass the unexpanded cwd directly to CreateProcess. I
don't think this will work on Windows, as this directory is not
interpreted by any shell, so "~" will cause errors. I think we should
pass this via gdb_tilde_expand, like we do in the Unix case, and I
also think we should mirror all the slashes in the result, just in
case.
Pedro Alves
2017-09-22 12:31:21 UTC
Permalink
Post by Eli Zaretskii
I think we should document here what does "~" mean on MS-Windows,
especially since, when HOME is not in the environment, Gnulib's glob
module doesn't behave according to MS platform recommendations (which
say not to create files directly below %HOMEDRIVE%%HOMEPATH%).
More generally, I think we should say here that the argument is
glob-expanded, because this is user-visible behavior (right?). Also,
how will TAB-completion react to input of this command? will it expand
the input typed so far?
Actually, should the command default to ~ at all? Shouldn't we
make "set cwd" clear the setting to the default state, i.e.,
empty? Otherwise, how do you get back to the default state?
Post by Eli Zaretskii
Post by Sergio Durigan Junior
+Show the inferior's working directory. If no directory has been
Does this show the original value typed by the user, or the expanded
value? E.g., if the user types "set cwd ~/foo", what will "show cwd"
display? If it shows the unexpanded form, does that mean the actual
cwd will change if, say, HOME changes?
Should we store the cwd after tilde-expansion?
I don't think so, because this is an inferior setting. I.e.,
e.g., when remote debugging, only the target (remote side) can
do the expansion, and the user may set this before connecting
to a target (remote, native, etc.), even.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-22 18:15:11 UTC
Permalink
Post by Pedro Alves
Post by Eli Zaretskii
I think we should document here what does "~" mean on MS-Windows,
especially since, when HOME is not in the environment, Gnulib's glob
module doesn't behave according to MS platform recommendations (which
say not to create files directly below %HOMEDRIVE%%HOMEPATH%).
More generally, I think we should say here that the argument is
glob-expanded, because this is user-visible behavior (right?). Also,
how will TAB-completion react to input of this command? will it expand
the input typed so far?
Actually, should the command default to ~ at all? Shouldn't we
make "set cwd" clear the setting to the default state, i.e.,
empty? Otherwise, how do you get back to the default state?
That's a good point. "set cwd" currently mimics what "cd" does, and
that's the reason for this "default is to use ~" decision.

I can certainly make "set cwd" without arguments to clear out whatever
has been set by the user. I think that's a more sensible decision
indeed.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-22 18:00:51 UTC
Permalink
Post by Eli Zaretskii
I think we should document here what does "~" mean on MS-Windows,
especially since, when HOME is not in the environment, Gnulib's glob
module doesn't behave according to MS platform recommendations (which
say not to create files directly below %HOMEDRIVE%%HOMEPATH%).
Sure, but just to be clear, this text was strongly based on another part
of the docs, which also mentions '~' without explaining further.

As I am totally out of the loop when it comes to Windows environments,
I'd appreciate a suggestion for the new text.
Post by Eli Zaretskii
More generally, I think we should say here that the argument is
glob-expanded, because this is user-visible behavior (right?). Also,
how will TAB-completion react to input of this command? will it expand
the input typed so far?
TAB-completion will not change anything; we don't have such a facility
on GDB AFAIK. But it will complete the input.
Post by Eli Zaretskii
Post by Sergio Durigan Junior
+Show the inferior's working directory. If no directory has been
Does this show the original value typed by the user, or the expanded
value? E.g., if the user types "set cwd ~/foo", what will "show cwd"
display? If it shows the unexpanded form, does that mean the actual
cwd will change if, say, HOME changes?
Pedro and I had a conversation about this specific topic yesterday, and
the decision was that the host should not do any path expansion on this
case. Therefore, whatever the user sets with "set cwd" is not expanded
until the inferior starts, which means that it is the target who
performs the expansion.
Post by Eli Zaretskii
Should we store the cwd after tilde-expansion?
I don't think so. Or at least I cannot see a reason to do that.
Post by Eli Zaretskii
Post by Sergio Durigan Junior
@@ -2461,6 +2462,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
BOOL ret;
DWORD flags = 0;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ const char *inferior_cwd = get_inferior_cwd ();
if (!exec_file)
error (_("No executable specified, use `target exec'."));
@@ -2488,8 +2490,15 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
error (_("Error starting executable: %d"), errno);
cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
mbstowcs (cygallargs, allargs, len);
+
+ len = mbstowcs (NULL, inferior_cwd, 0) + 1;
+ if (len == (size_t) -1)
+ error (_("Invalid cwd for inferior: %d"), errno);
+ infcwd = (wchar_t *) alloca (len * sizeof (wchar_t));
+ mbstowcs (infcwd, inferior_cwd, len);
#else /* !__USEWIDE */
cygallargs = allargs;
+ infcwd = (cygwin_buf_t *) inferior_cwd;
#endif
}
else
@@ -2574,7 +2583,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32_env, /* environment */
- NULL, /* current directory */
+ infcwd, /* current directory */
&si,
&pi);
if (w32_env)
@@ -2697,7 +2706,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32env, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si,
&pi);
if (tty != INVALID_HANDLE_VALUE)
This seems to pass the unexpanded cwd directly to CreateProcess. I
don't think this will work on Windows, as this directory is not
interpreted by any shell, so "~" will cause errors. I think we should
pass this via gdb_tilde_expand, like we do in the Unix case, and I
also think we should mirror all the slashes in the result, just in
case.
Hm, you're right. I will call "gdb_tilde_expand" here. I'm not sure
what you mean by "mirror all the slashes in the result". Do you mean
"escape the slashes"?

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Eli Zaretskii
2017-09-22 18:56:10 UTC
Permalink
Date: Fri, 22 Sep 2017 14:00:51 -0400
Post by Eli Zaretskii
I think we should document here what does "~" mean on MS-Windows,
especially since, when HOME is not in the environment, Gnulib's glob
module doesn't behave according to MS platform recommendations (which
say not to create files directly below %HOMEDRIVE%%HOMEPATH%).
Sure, but just to be clear, this text was strongly based on another part
of the docs, which also mentions '~' without explaining further.
As I am totally out of the loop when it comes to Windows environments,
I'd appreciate a suggestion for the new text.
If you write the Unix part, I can propose how to amend it to cover
Windows. OK?
Post by Eli Zaretskii
Does this show the original value typed by the user, or the expanded
value? E.g., if the user types "set cwd ~/foo", what will "show cwd"
display? If it shows the unexpanded form, does that mean the actual
cwd will change if, say, HOME changes?
Pedro and I had a conversation about this specific topic yesterday, and
the decision was that the host should not do any path expansion on this
case. Therefore, whatever the user sets with "set cwd" is not expanded
until the inferior starts, which means that it is the target who
performs the expansion.
There's no contradiction between these two sides of this issue. For
native debugging, host == target, so the host can expand. For the
non-native debugging, you can ask the target to do the expansion and
store the result. Either way IMO is better than expanding at run
time, because the latter makes the expansion dependent on factors
which could be out of the user control, and also requires every use
of the value to call gdb_tilde_expand, thus wasting cycles.
Post by Eli Zaretskii
This seems to pass the unexpanded cwd directly to CreateProcess. I
don't think this will work on Windows, as this directory is not
interpreted by any shell, so "~" will cause errors. I think we should
pass this via gdb_tilde_expand, like we do in the Unix case, and I
also think we should mirror all the slashes in the result, just in
case.
Hm, you're right. I will call "gdb_tilde_expand" here. I'm not sure
what you mean by "mirror all the slashes in the result". Do you mean
"escape the slashes"?
No, I mean convert forward slashes to backslashes.

Thanks.
Pedro Alves
2017-09-22 19:24:40 UTC
Permalink
Post by Eli Zaretskii
There's no contradiction between these two sides of this issue. For
native debugging, host == target, so the host can expand. For the
non-native debugging, you can ask the target to do the expansion and
store the result.
You can't, not as the actual value of the setting, because the
setting can be tweaked before GDB is even connected to a target.

I.e., you can do:

(gdb) set cwd ~ # I haven't even connected to a target yet.
# Where should this be expanded?
# On host may be incorrect.
# '~' -> /home/pedro on this machine
(gdb) target extended-remote foo:9999
(gdb) start
error: /home/pedro does not exist
# '~' is /mount/home/pedro on 'foo'
(gdb) kill
(gdb) target extended-remote bar:9999
(gdb) start
error: /home/pedro does not exist
# '~' is /nfs/home/palves on 'bar'


It may be useful to display the expanded path as extra info,
like in:

(gdb) set cwd ~foo/bar
(gdb) show cwd
The current directory is ~foo/bar (/home/foo/bar)
^^^^^^^^^^^^^

though that'd require a new remote protocol packet.
Post by Eli Zaretskii
Either way IMO is better than expanding at run
time, because the latter makes the expansion dependent on factors
which could be out of the user control,
I don't see what the problem is here.
Post by Eli Zaretskii
and also requires every use
of the value to call gdb_tilde_expand, thus wasting cycles.
I don't think that significant, compared to all the other
work / syscalls / remote protocol roundtrips that we have
to do to start a process.

Thanks,
Pedro Alves
Eli Zaretskii
2017-09-22 19:41:01 UTC
Permalink
Date: Fri, 22 Sep 2017 20:24:40 +0100
(gdb) set cwd ~ # I haven't even connected to a target yet.
# Where should this be expanded?
# On host may be incorrect.
# '~' -> /home/pedro on this machine
You can expand it when you connect. The value has no use until then
anyway.
Post by Eli Zaretskii
Either way IMO is better than expanding at run
time, because the latter makes the expansion dependent on factors
which could be out of the user control,
I don't see what the problem is here.
Post by Eli Zaretskii
and also requires every use
of the value to call gdb_tilde_expand, thus wasting cycles.
I don't think that significant, compared to all the other
work / syscalls / remote protocol roundtrips that we have
to do to start a process.
It may be insignificant in terms of CPU usage, but it's a nuisance
that people will keep forgetting to do, as demonstrated in this case.

Anyway, I will shut up now. I just feel that keeping this unexpanded
is wrong in the long run, that's all.
Sergio Durigan Junior
2017-09-22 20:26:56 UTC
Permalink
Post by Eli Zaretskii
Date: Fri, 22 Sep 2017 20:24:40 +0100
(gdb) set cwd ~ # I haven't even connected to a target yet.
# Where should this be expanded?
# On host may be incorrect.
# '~' -> /home/pedro on this machine
You can expand it when you connect. The value has no use until then
anyway.
So you're proposing that we discard the previous path expansion done
before connecting, right? I'm just trying to understand your proposal
here, not to bikeshed or anything.
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-22 20:37:49 UTC
Permalink
Post by Sergio Durigan Junior
Post by Eli Zaretskii
Date: Fri, 22 Sep 2017 20:24:40 +0100
(gdb) set cwd ~ # I haven't even connected to a target yet.
# Where should this be expanded?
# On host may be incorrect.
# '~' -> /home/pedro on this machine
You can expand it when you connect. The value has no use until then
anyway.
So you're proposing that we discard the previous path expansion done
before connecting, right? I'm just trying to understand your proposal
here, not to bikeshed or anything.
That would mean keep both non-expanded, and expanded paths around,
which is what I was suggesting with:

(gdb) set cwd ~foo/bar
(gdb) show cwd
The current directory is ~foo/bar (/home/foo/bar)
^^^^^^^^^^^^^

The (^^^) part was meant to indicate "currently expands to this".

Which means we'd add a new remote packet to request "expand
this path and give me back the result".

(I think we could do that as a follow up extension.)

But that's not what I understood Eli suggesting. I understood
it as gdb expanding whatever's the value set on connection.
But I don't see how that could work, because before gdb connects
to a remote target explicitly, it's as if gdb was connected to
the native target (that's how "run" works without typing
"target native" explicitly, though you can type that), so
by the time you connect to the remote target, it's already
too late, gdb has already expanded on the host, and there's
nothing left to expand.

Thanks,
Pedro Alves
Eli Zaretskii
2017-09-23 05:55:45 UTC
Permalink
Date: Fri, 22 Sep 2017 21:37:49 +0100
That would mean keep both non-expanded, and expanded paths around,
(gdb) set cwd ~foo/bar
(gdb) show cwd
The current directory is ~foo/bar (/home/foo/bar)
^^^^^^^^^^^^^
Keeping both is also OK, although I don't see how it would solve the
But that's not what I understood Eli suggesting. I understood
it as gdb expanding whatever's the value set on connection.
But I don't see how that could work, because before gdb connects
to a remote target explicitly, it's as if gdb was connected to
the native target (that's how "run" works without typing
"target native" explicitly, though you can type that), so
by the time you connect to the remote target, it's already
too late, gdb has already expanded on the host, and there's
nothing left to expand.
I don't understand this description, which is not surprising, since my
knowledge of the machinery involved in this is very superficial.
Pedro Alves
2017-09-27 14:01:58 UTC
Permalink
Post by Eli Zaretskii
Date: Fri, 22 Sep 2017 21:37:49 +0100
That would mean keep both non-expanded, and expanded paths around,
(gdb) set cwd ~foo/bar
(gdb) show cwd
The current directory is ~foo/bar (/home/foo/bar)
^^^^^^^^^^^^^
Keeping both is also OK, although I don't see how it would solve the
But that's not what I understood Eli suggesting. I understood
it as gdb expanding whatever's the value set on connection.
But I don't see how that could work, because before gdb connects
to a remote target explicitly, it's as if gdb was connected to
the native target (that's how "run" works without typing
"target native" explicitly, though you can type that), so
by the time you connect to the remote target, it's already
too late, gdb has already expanded on the host, and there's
nothing left to expand.
I don't understand this description, which is not surprising, since my
knowledge of the machinery involved in this is very superficial.
Let's say that GDB keeps track of the desired cwd for the inferior
as a single string, like Sergio's patch is doing. Say the user does:

$ gdb
(gdb) file program
(gdb) set cwd ~

At this point, GDB it not "connected" to any target yet. However,
if the user types "run", GDB automatically uses the native
target to run the inferior. So typing "run" after the above is
equivalent to:

$ gdb
(gdb) file program
(gdb) set cwd ~
(gdb) target native
(gdb) run

OK, now the question is, when to expand that '~'. If it is
expanded immediately at "set cwd" time, then we end up expanding
it incorrectly in case the user actually wanted to debug remotely:

$ gdb
(gdb) file program
(gdb) set cwd ~
(gdb) show cwd
/home/pedro # local path, doesn't exists on the 'foo' machine.
(gdb) target extended-remote foo:12345
(gdb) show cwd
/home/pedro # does not exist on 'foo'

If is it instead expanded only when GDB connects to a target, then
we get this:

$ gdb
(gdb) file program
(gdb) set cwd ~
(gdb) show cwd
~ # not expanded yet!
(gdb) start # gdb expands ~ -> /home/pedro, then starts the inferior
(gdb) show cwd
/home/pedro # now it's expanded. users scratches head.
(gdb) kill
(gdb) target extended-remote foo:12345 # switch same inferior
# to different target
(gdb) show cwd
/home/pedro # whoops, lost original '~' path, and this path
# doesn't make sense for the 'foo' machine.


If GDB does not expand the set cwd path ever except internally
when starting the inferior, then the problems shown just above
never happen.
Post by Eli Zaretskii
Keeping both is also OK, although I don't see how it would solve the
The problems I mentioned are solved by not expanding in the
first place. Saving both original-path-as-specified-by-user and
expanded-path (or expanding on demand when displaying the path to the
user and saving it nowhere) would then be a way to let the user
know what the path expands to on the current target, without losing the
originally set path. Like:

$ gdb
(gdb) file program
(gdb) set cwd ~
(gdb) show cwd
cwd is: ~
expands to /home/pedro on current target
(gdb) start
(gdb) show cwd
cwd is: ~
expands to /home/pedro on current target
(gdb) kill
(gdb) target extended-remote foo:12345
(gdb) show cwd
cwd is: ~
expands to /mnt/home/palves on current target
(gdb) disconnect
(gdb) target extended-remote bar:12345
(gdb) show cwd
cwd is: ~
expands to /nfs/homes/pedro on current target

I'm not sure it's worth the trouble to show the
expansions like this. But if we make GDB _not_ expand
the "set cwd" setting's value itself, as I was proposing,
then we can always come back and improve GDB's output like
above, to inform the user what the setting expands to,
as extra info.

Hope that is clearer.

Thanks,
Pedro Alves
Eli Zaretskii
2017-09-23 05:51:56 UTC
Permalink
Date: Fri, 22 Sep 2017 16:26:56 -0400
Post by Eli Zaretskii
Post by Pedro Alves
(gdb) set cwd ~ # I haven't even connected to a target yet.
# Where should this be expanded?
# On host may be incorrect.
# '~' -> /home/pedro on this machine
You can expand it when you connect. The value has no use until then
anyway.
So you're proposing that we discard the previous path expansion done
before connecting, right?
Yes, discard and replace with the actual expansion which the target
returns.
Sergio Durigan Junior
2017-09-22 20:24:26 UTC
Permalink
Post by Eli Zaretskii
Date: Fri, 22 Sep 2017 14:00:51 -0400
Post by Eli Zaretskii
I think we should document here what does "~" mean on MS-Windows,
especially since, when HOME is not in the environment, Gnulib's glob
module doesn't behave according to MS platform recommendations (which
say not to create files directly below %HOMEDRIVE%%HOMEPATH%).
Sure, but just to be clear, this text was strongly based on another part
of the docs, which also mentions '~' without explaining further.
As I am totally out of the loop when it comes to Windows environments,
I'd appreciate a suggestion for the new text.
If you write the Unix part, I can propose how to amend it to cover
Windows. OK?
Deal. Thanks.
Post by Eli Zaretskii
Post by Eli Zaretskii
This seems to pass the unexpanded cwd directly to CreateProcess. I
don't think this will work on Windows, as this directory is not
interpreted by any shell, so "~" will cause errors. I think we should
pass this via gdb_tilde_expand, like we do in the Unix case, and I
also think we should mirror all the slashes in the result, just in
case.
Hm, you're right. I will call "gdb_tilde_expand" here. I'm not sure
what you mean by "mirror all the slashes in the result". Do you mean
"escape the slashes"?
No, I mean convert forward slashes to backslashes.
Sorry, I wasn't familiar with the term. Anyway, I think I can implement
that. In fact, I think gdbserver/win32-low.c:create_process already
does that, right?

wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
mbstowcs (wprogram, program, strlen (program) + 1);

for (p = wprogram; *p; ++p)
if (L'/' == *p)
*p = L'\\';

Anyway, I'll do the same for the inferior's cwd.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Eli Zaretskii
2017-09-23 05:50:45 UTC
Permalink
Date: Fri, 22 Sep 2017 16:24:26 -0400
Post by Eli Zaretskii
No, I mean convert forward slashes to backslashes.
Sorry, I wasn't familiar with the term.
Nothing to be sorry about.
Anyway, I think I can implement
that. In fact, I think gdbserver/win32-low.c:create_process already
does that, right?
wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
mbstowcs (wprogram, program, strlen (program) + 1);
for (p = wprogram; *p; ++p)
if (L'/' == *p)
*p = L'\\';
Yes, that's it. But this is for wchar_t strings, not for char
strings, of course.

Thanks.
Sergio Durigan Junior
2017-09-22 20:55:35 UTC
Permalink
Post by Eli Zaretskii
Date: Fri, 22 Sep 2017 14:00:51 -0400
Post by Eli Zaretskii
I think we should document here what does "~" mean on MS-Windows,
especially since, when HOME is not in the environment, Gnulib's glob
module doesn't behave according to MS platform recommendations (which
say not to create files directly below %HOMEDRIVE%%HOMEPATH%).
Sure, but just to be clear, this text was strongly based on another part
of the docs, which also mentions '~' without explaining further.
As I am totally out of the loop when it comes to Windows environments,
I'd appreciate a suggestion for the new text.
If you write the Unix part, I can propose how to amend it to cover
Windows. OK?
What do you think:

@table @code
@kindex set cwd
@cindex change inferior's working directory
@item set cwd @r{[}@var{directory}@r{]}
Set the inferior's working directory to @var{directory}, which will be
@code{glob}-expanded in order to resolve tildes (@file{~}). If no
argument has been specified, the command clears the setting and resets
it to an empty state. This setting has no effect on @value{GDBN}'s
working directory, and it only takes effect the next time you start
the inferior.

?
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Eli Zaretskii
2017-09-23 06:05:11 UTC
Permalink
Date: Fri, 22 Sep 2017 16:55:35 -0400
@table @code
@kindex set cwd
@cindex change inferior's working directory
@item set cwd @r{[}@var{directory}@r{]}
@code{glob}-expanded in order to resolve tildes (@file{~}). If no
argument has been specified, the command clears the setting and resets
working directory, and it only takes effect the next time you start
the inferior.
OK. I'd suggest to append this text.

The @file{~} in @var{directory} is a short for the @dfn{home
directory}, usually pointed to by the @env{HOME} environment
variable. On MS-Windows, if @env{HOME} is not defined, @value{GDBN}
uses the concatenation of @env{HOMEDRIVE} and @env{HOMEPATH} as
fallback.

(This ignores the "~username" case -- is that important enough to
mention?)

Btw, what should the user do if the file name includes a literal '~'?
Escape it with a backslash?
Sergio Durigan Junior
2017-09-23 17:01:24 UTC
Permalink
Post by Eli Zaretskii
Date: Fri, 22 Sep 2017 16:55:35 -0400
@table @code
@kindex set cwd
@cindex change inferior's working directory
@item set cwd @r{[}@var{directory}@r{]}
@code{glob}-expanded in order to resolve tildes (@file{~}). If no
argument has been specified, the command clears the setting and resets
working directory, and it only takes effect the next time you start
the inferior.
OK. I'd suggest to append this text.
fallback.
Thanks, added.
Post by Eli Zaretskii
(This ignores the "~username" case -- is that important enough to
mention?)
I don't think so. I mean, the "~username" tilde expansion is part of
the default behaviour, so I think it's OK to leave it implicit.
Post by Eli Zaretskii
Btw, what should the user do if the file name includes a literal '~'?
Escape it with a backslash?
Yes.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Sergio Durigan Junior
2017-09-21 22:59:26 UTC
Permalink
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.

The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.

Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) and the
documentation.

No regressions found.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
(show_cwd_command): Expand text to include remote debugging.
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_set_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_set_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass the inferior's cwd to
CreateProcess.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.base/set-cwd.exp: Make it available on gdbserver.

gdb/doc/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.texinfo (Starting your Program) <The working directory.>:
Mention remote debugging.
(Working Directory) <Your Program's Working Directory>:
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 12 ++++++++++++
gdb/common/common-inferior.h | 3 +++
gdb/doc/gdb.texinfo | 39 +++++++++++++++++++++++++++++++++++---
gdb/gdbserver/inferiors.c | 9 +++++++++
gdb/gdbserver/server.c | 18 +++++++++++++++++-
gdb/gdbserver/win32-low.c | 15 ++++++++++++---
gdb/infcmd.c | 7 ++++---
gdb/remote.c | 37 ++++++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 11 +++++++++--
9 files changed, 139 insertions(+), 12 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index c131713293..4ac340eeb5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -23,6 +23,14 @@

* New features in the GDB remote stub, GDBserver

+ ** GDBserver is now able to set the inferior's current working
+ directory.
+
+ The user can set the desired working directory to be used by the
+ remote inferior on GDB, using the new "set cwd" command, which
+ will instruct GDB to tell GDBserver about this directory change
+ the next time an inferior is run.
+
** New "--selftest" command line option runs some GDBserver self
tests. These self tests are disabled in releases.

@@ -56,6 +64,10 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.

+QSetWorkingDir
+ Tell GDBserver that the inferior to be started should use a specific
+ working directory.
+
* The "maintenance print c-tdesc" command now takes an optional
argument which is the file name of XML target description.

diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 515a8c0f4e..26acddc84a 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,7 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();

+/* Set the inferior current working directory. */
+extern void set_inferior_cwd (const char *cwd);
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 899afb92b6..7434de2a68 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
You can set your program's working directory with the command
@code{set cwd}. If you do not set any working directory with this
-command, your program will inherit @value{GDBN}'s working directory.
-@xref{Working Directory, ,Your Program's Working Directory}.
+command, your program will inherit @value{GDBN}'s working directory if
+native debugging, or @code{gdbserver}'s working directory if remote
+debugging. @xref{Working Directory, ,Your Program's Working
+Directory}.

@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
@@ -2439,7 +2441,9 @@ Each time you start your program with @code{run}, the inferior will be
initialized with the current working directory specified by the
@code{set cwd} command. If no directory has been specified by this
command, then the inferior will inherit @value{GDBN}'s current working
-directory as its working directory.
+directory as its working directory if native debugging, or it will
+inherit @code{gdbserver}'s current working directory if remote
+debugging.

You can also change @value{GDBN}'s current working directory by using
the @code{cd} command.
@@ -20993,6 +20997,10 @@ are:
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}

+@item @code{set-working-dir}
+@tab @code{QSetWorkingDir}
+@tab @code{set cwd}
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@@ -36781,6 +36789,28 @@ Reply:
@table @samp
@item OK
The request succeeded.
+
+@item QSetWorkingDir:@var{hex-value}
+@anchor{QSetWorkingDir packet}
+@cindex set working directory, remote request
+@cindex @samp{QSetWorkingDir} packet
+This packet is used to inform @command{gdbserver} of the intended
+current working directory for programs that are going to be executed.
+
+The packet is composed by @var{hex-value}, an hex encoded
+representation of the directory to be entered by @command{gdbserver}.
+
+This packet is only transmitted when the user issues a @code{set cwd}
+command in @value{GDBN} (@pxref{Working Directory, ,Your Program's
+Working Directory}).
+
+This packet is only available in extended mode (@pxref{extended
+mode}).
+
+Reply:
+@table @samp
+@item OK
+The request succeeded.
@end table

This packet is not probed by default; the remote stub must request it,
@@ -36811,6 +36841,9 @@ Reply:
@table @samp
@item OK
The request succeeded.
+
+@item E @var{nn}
+An error occurred. The error number @var{nn} is given as hex digits.
@end table

This packet is not probed by default; the remote stub must request it,
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e78ad4faf1..326d01f4d9 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,12 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f3eee31052..14f8a732a7 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
return;
}

+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Changed current directory to %s]\n"),
+ path.c_str ());
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2355,7 +2370,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);

if (target_supports_catch_syscall ())
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index cc84d15c2f..62b222d2fa 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,10 +562,11 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;

#ifdef _WIN32_WCE
- wchar_t *p, *wprogram, *wargs;
+ wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
size_t argslen;

wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
@@ -579,6 +580,14 @@ create_process (const char *program, char *args,
wargs = alloca ((argslen + 1) * sizeof (wchar_t));
mbstowcs (wargs, args, argslen + 1);

+ if (inferior_cwd != NULL)
+ {
+ size_t cwdlen = strlen (inferior_cwd);
+
+ wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+ mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+ }
+
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
@@ -586,7 +595,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +608,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 4c5bbfdbf2..f483a33a44 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -250,9 +250,9 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}

-/* Set the inferior current working directory. */
+/* See common/common-inferior.h. */

-static void
+void
set_inferior_cwd (const char *cwd)
{
if (*cwd == '\0')
@@ -292,7 +292,8 @@ show_cwd_command (struct ui_file *file, int from_tty,
fprintf_filtered (gdb_stdout,
_("\
You have not set the inferior's current working directory.\n\
-The inferior will inherit GDB's cwd.\n"));
+The inferior will inherit GDB's cwd if native debugging, or gdbserver's\n\
+cwd if remote debugging.\n"));
else
fprintf_filtered (gdb_stdout,
_("Current working directory that will be used "
diff --git a/gdb/remote.c b/gdb/remote.c
index 33b0c2a09d..18d3aaea3f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1434,6 +1434,7 @@ enum {
PACKET_QPassSignals,
PACKET_QCatchSyscalls,
PACKET_QProgramSignals,
+ PACKET_QSetWorkingDir,
PACKET_QStartupWithShell,
PACKET_QEnvironmentHexEncoded,
PACKET_QEnvironmentReset,
@@ -4665,6 +4666,8 @@ static const struct protocol_feature remote_protocol_features[] = {
PACKET_QCatchSyscalls },
{ "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QProgramSignals },
+ { "QSetWorkingDir", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QSetWorkingDir },
{ "QStartupWithShell", PACKET_DISABLE, remote_supported_packet,
PACKET_QStartupWithShell },
{ "QEnvironmentHexEncoded", PACKET_DISABLE, remote_supported_packet,
@@ -9644,6 +9647,35 @@ extended_remote_environment_support (struct remote_state *rs)
send_environment_packet (rs, "unset", "QEnvironmentUnset", el.c_str ());
}

+/* Helper function to set the current working directory for the
+ inferior in the remote. */
+
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QSetWorkingDir])
+ != PACKET_OK)
+ error (_("\
+Remote replied unexpectedly while changing working directory: %s"),
+ rs->buf);
+ }
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9686,6 +9718,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),

extended_remote_environment_support (rs);

+ extended_remote_set_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14185,6 +14219,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);

+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);

diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index f2700ec44d..32458e384e 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,11 +15,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

-if { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
- untested "not implemented on gdbserver"
+if { [use_gdb_stub] } {
+ untested "not valid on native-gdbserver"
return
}

+if { [target_info gdb_protocol] == "remote" } {
+ load_lib gdbserver-support.exp
+ if { [skip_gdbserver_tests] } {
+ return
+ }
+}
+
standard_testfile

if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
--
2.13.3
Eli Zaretskii
2017-09-22 08:12:18 UTC
Permalink
Date: Thu, 21 Sep 2017 18:59:26 -0400
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.
This once again raises the issue of whether to send expanded or
unexpanded directory down the wire, and if unexpanded, then what is
the meaning of the default "~" in the inferior.
diff --git a/gdb/NEWS b/gdb/NEWS
index c131713293..4ac340eeb5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -23,6 +23,14 @@
* New features in the GDB remote stub, GDBserver
+ ** GDBserver is now able to set the inferior's current working
+ directory.
+
+ The user can set the desired working directory to be used by the
+ remote inferior on GDB, using the new "set cwd" command, which
+ will instruct GDB to tell GDBserver about this directory change
+ the next time an inferior is run.
+
** New "--selftest" command line option runs some GDBserver self
tests. These self tests are disabled in releases.
@@ -56,6 +64,10 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.
+QSetWorkingDir
+ Tell GDBserver that the inferior to be started should use a specific
+ working directory.
+
* The "maintenance print c-tdesc" command now takes an optional
argument which is the file name of XML target description.
This part is OK.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 899afb92b6..7434de2a68 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
OK for this part.
+ if (inferior_cwd != NULL)
+ {
+ size_t cwdlen = strlen (inferior_cwd);
+
+ wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+ mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+ }
no error checking of the mbstowcs conversion?
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
@@ -586,7 +595,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +608,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
Once again, this feeds CreateProcess with an unexpanded directory,
which AFAIU will not work if the directory includes "~".
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
Shouldn't this do some encoding conversion, from the GDB charset to
the target charset, before encoding in hex?

Thanks.
Sergio Durigan Junior
2017-09-22 18:45:59 UTC
Permalink
Post by Eli Zaretskii
Date: Thu, 21 Sep 2017 18:59:26 -0400
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.
This once again raises the issue of whether to send expanded or
unexpanded directory down the wire, and if unexpanded, then what is
the meaning of the default "~" in the inferior.
FWIW, I decided (based on another message by Pedro) to modify the
behaviour of "set cwd" without arguments. Before it was setting the
inferior's cwd as "~", but now it clears out whatever cwd that has been
specified by the user.

But of course, the user can still do "set cwd ~". We do not expand
paths on the host, as I explained in another message, so gdbserver will
see "~" coming down the wire. Then, when the inferior is to be started,
gdbserver will perform the path expansion based on what
"gdb_tilde_expand" (i.e., "glob") does.
Post by Eli Zaretskii
+ if (inferior_cwd != NULL)
+ {
+ size_t cwdlen = strlen (inferior_cwd);
+
+ wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+ mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+ }
no error checking of the mbstowcs conversion?
Sorry, I am not a Windows programmer. Other places in the code also
don't check for errors. I'd be happy to improve this code, but I refuse
to touch a Windows machine so I'm doing this all this without any
testing. But please, feel absolutely free to point out how this code
should look like.
Post by Eli Zaretskii
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
@@ -586,7 +595,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +608,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
Once again, this feeds CreateProcess with an unexpanded directory,
which AFAIU will not work if the directory includes "~".
You're right; I've changed that now.
Post by Eli Zaretskii
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
Shouldn't this do some encoding conversion, from the GDB charset to
the target charset, before encoding in hex?
I don't know. There's nothing related to charset on gdb/gdbserver/, but
then again I don't know if we've ever encountered a case that demanded
conversions. I can investigate this a bit more.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Eli Zaretskii
2017-09-22 19:08:55 UTC
Permalink
Date: Fri, 22 Sep 2017 14:45:59 -0400
Post by Eli Zaretskii
Post by Sergio Durigan Junior
+ if (inferior_cwd != NULL)
+ {
+ size_t cwdlen = strlen (inferior_cwd);
+
+ wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+ mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+ }
no error checking of the mbstowcs conversion?
Sorry, I am not a Windows programmer. Other places in the code also
don't check for errors.
Not checking for errors in these conversions can be worse on Windows
than on other platforms, because the Windows' wchar_t supports only
the BMP, so the chances of getting a conversion error are higher than
on Unix.
I'd be happy to improve this code, but I refuse to touch a Windows
machine so I'm doing this all this without any testing. But please,
feel absolutely free to point out how this code should look like.
mbstowcs returns NULL if it fails, so I suggest to throw an error in
that case. I see no reason for anything fancier.
Post by Eli Zaretskii
Post by Sergio Durigan Junior
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
Shouldn't this do some encoding conversion, from the GDB charset to
the target charset, before encoding in hex?
I don't know. There's nothing related to charset on gdb/gdbserver/, but
then again I don't know if we've ever encountered a case that demanded
conversions. I can investigate this a bit more.
GDB does know about target-charset and host-charset. I'd expect file
names that are sent to the target be in the target charset, but since
what get_inferior_cwd returns is in host charset (it was typed by the
user), I think a conversion might be in order.
Sergio Durigan Junior
2017-09-22 20:47:26 UTC
Permalink
Post by Eli Zaretskii
Date: Fri, 22 Sep 2017 14:45:59 -0400
Post by Eli Zaretskii
Post by Sergio Durigan Junior
+ if (inferior_cwd != NULL)
+ {
+ size_t cwdlen = strlen (inferior_cwd);
+
+ wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+ mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+ }
no error checking of the mbstowcs conversion?
Sorry, I am not a Windows programmer. Other places in the code also
don't check for errors.
Not checking for errors in these conversions can be worse on Windows
than on other platforms, because the Windows' wchar_t supports only
the BMP, so the chances of getting a conversion error are higher than
on Unix.
I'd be happy to improve this code, but I refuse to touch a Windows
machine so I'm doing this all this without any testing. But please,
feel absolutely free to point out how this code should look like.
mbstowcs returns NULL if it fails, so I suggest to throw an error in
that case. I see no reason for anything fancier.
OK, that I can do :-).
Post by Eli Zaretskii
Post by Eli Zaretskii
Post by Sergio Durigan Junior
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
Shouldn't this do some encoding conversion, from the GDB charset to
the target charset, before encoding in hex?
I don't know. There's nothing related to charset on gdb/gdbserver/, but
then again I don't know if we've ever encountered a case that demanded
conversions. I can investigate this a bit more.
GDB does know about target-charset and host-charset. I'd expect file
names that are sent to the target be in the target charset, but since
what get_inferior_cwd returns is in host charset (it was typed by the
user), I think a conversion might be in order.
I don't know. We never seem to do that in other cases. For example,
when we are starting the inferior remotely:

static int
extended_remote_run (const std::string &args)
{
...
if (strlen (remote_exec_file) * 2 + len >= get_remote_packet_size ())
error (_("Remote file name too long for run packet"));
len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len,
strlen (remote_exec_file));


The "remote_exec_file" variable is also something that the user inputs
through the "set remote exec-file" command. It doesn't seem like we
need to worry about charset conversion here.

Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Eli Zaretskii
2017-09-23 06:00:13 UTC
Permalink
Date: Fri, 22 Sep 2017 16:47:26 -0400
Post by Eli Zaretskii
GDB does know about target-charset and host-charset. I'd expect file
names that are sent to the target be in the target charset, but since
what get_inferior_cwd returns is in host charset (it was typed by the
user), I think a conversion might be in order.
I don't know. We never seem to do that in other cases. For example,
static int
extended_remote_run (const std::string &args)
{
...
if (strlen (remote_exec_file) * 2 + len >= get_remote_packet_size ())
error (_("Remote file name too long for run packet"));
len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len,
strlen (remote_exec_file));
The "remote_exec_file" variable is also something that the user inputs
through the "set remote exec-file" command. It doesn't seem like we
need to worry about charset conversion here.
If remote_exec_file came from the target, that's okay, as it would be
already in the target charset. But if it is typed by the user, then I
guess we indeed have such problems, when the 2 charsets are different.

Anyway, I don't want to block the changeset or hijack the discussions.
Feel free to go ahead with pushing if we generally ignore this issue
elsewhere.

Thanks.
Pedro Alves
2017-09-27 14:42:04 UTC
Permalink
Post by Sergio Durigan Junior
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Unix implementation detail.
Post by Sergio Durigan Junior
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.
Unix implementation detail. That's not how it works for Windows.
Post by Sergio Durigan Junior
Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) and the
documentation.
No regressions found.
* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
(show_cwd_command): Expand text to include remote debugging.
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_set_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_set_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.
* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass the inferior's cwd to
CreateProcess.
* gdb.base/set-cwd.exp: Make it available on gdbserver.
Mention remote debugging.
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 12 ++++++++++++
gdb/common/common-inferior.h | 3 +++
gdb/doc/gdb.texinfo | 39 +++++++++++++++++++++++++++++++++++---
gdb/gdbserver/inferiors.c | 9 +++++++++
gdb/gdbserver/server.c | 18 +++++++++++++++++-
gdb/gdbserver/win32-low.c | 15 ++++++++++++---
gdb/infcmd.c | 7 ++++---
gdb/remote.c | 37 ++++++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 11 +++++++++--
9 files changed, 139 insertions(+), 12 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index c131713293..4ac340eeb5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -23,6 +23,14 @@
* New features in the GDB remote stub, GDBserver
+ ** GDBserver is now able to set the inferior's current working
+ directory.
+
+ The user can set the desired working directory to be used by the
+ remote inferior on GDB, using the new "set cwd" command, which
+ will instruct GDB to tell GDBserver about this directory change
+ the next time an inferior is run.
+
** New "--selftest" command line option runs some GDBserver self
tests. These self tests are disabled in releases.
@@ -56,6 +64,10 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.
+QSetWorkingDir
+ Tell GDBserver that the inferior to be started should use a specific
+ working directory.
+
* The "maintenance print c-tdesc" command now takes an optional
argument which is the file name of XML target description.
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 515a8c0f4e..26acddc84a 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,7 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();
+/* Set the inferior current working directory. */
+extern void set_inferior_cwd (const char *cwd);
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 899afb92b6..7434de2a68 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
You can set your program's working directory with the command
@code{set cwd}. If you do not set any working directory with this
+Directory}.
Elsewhere in the manual we say "the remote server" instead of @code{gdbserver},
because not all remote debugging uses gdbserver.
Post by Sergio Durigan Junior
@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
@@ -2439,7 +2441,9 @@ Each time you start your program with @code{run}, the inferior will be
initialized with the current working directory specified by the
@code{set cwd} command. If no directory has been specified by this
-directory as its working directory.
+directory as its working directory if native debugging, or it will
+debugging.
Ditto.
Post by Sergio Durigan Junior
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@table @samp
@item OK
The request succeeded.
+
I think it'd be clearer to say @var{directory}, and
then say below that @var{directory} is an hex-encoded
string, like you're already doing. That's what we do
elsewhere in the manual.
Ditto re. "gdbserver".
Post by Sergio Durigan Junior
+current working directory for programs that are going to be executed.
+
+
+Working Directory}).
"This packet is only transmitted when set cwd" suggests to me that
the packet is sent immediately when the user types "set cwd".

This packet is only transmitted if the user explicitly
specifies a directory with the @kdb{set cwd} command.

note:
s/when/if/.
Post by Sergio Durigan Junior
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e78ad4faf1..326d01f4d9 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,12 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f3eee31052..14f8a732a7 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
return;
}
+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Changed current directory to %s]\n"),
+ path.c_str ());
Please tweak the debug string to be clear that this is the
inferior's cwd, not gdbserver's.
Post by Sergio Durigan Junior
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2355,7 +2370,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);
if (target_supports_catch_syscall ())
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index cc84d15c2f..62b222d2fa 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,10 +562,11 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;
#ifdef _WIN32_WCE
- wchar_t *p, *wprogram, *wargs;
+ wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
size_t argslen;
wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
@@ -579,6 +580,14 @@ create_process (const char *program, char *args,
wargs = alloca ((argslen + 1) * sizeof (wchar_t));
mbstowcs (wargs, args, argslen + 1);
+ if (inferior_cwd != NULL)
+ {
+ size_t cwdlen = strlen (inferior_cwd);
+
+ wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+ mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+ }
+
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
@@ -586,7 +595,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +608,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 4c5bbfdbf2..f483a33a44 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -250,9 +250,9 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}
-/* Set the inferior current working directory. */
+/* See common/common-inferior.h. */
-static void
+void
set_inferior_cwd (const char *cwd)
{
if (*cwd == '\0')
@@ -292,7 +292,8 @@ show_cwd_command (struct ui_file *file, int from_tty,
fprintf_filtered (gdb_stdout,
_("\
You have not set the inferior's current working directory.\n\
-The inferior will inherit GDB's cwd.\n"));
+The inferior will inherit GDB's cwd if native debugging, or gdbserver's\n\
+cwd if remote debugging.\n"));
gdbserver -> remote server.
Post by Sergio Durigan Junior
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
What happens if you do:

set cwd foo
run
kill
set cwd # clear
run

Do we clear the cwd on the remote end or we do we fail the
NULL check above?
Post by Sergio Durigan Junior
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
This always sets to non-NULL. So is it really possible
to get back to the original clear state? Doesn't look like it?
Do we have a test for that?
Post by Sergio Durigan Junior
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QSetWorkingDir])
+ != PACKET_OK)
+ error (_("\
+Remote replied unexpectedly while changing working directory: %s"),
+ rs->buf);
Again "changing". Maybe say "setting the inferior's working directory"
instead.
Post by Sergio Durigan Junior
+ }
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9686,6 +9718,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
extended_remote_environment_support (rs);
+ extended_remote_set_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14185,6 +14219,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index f2700ec44d..32458e384e 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,11 +15,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-if { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
- untested "not implemented on gdbserver"
+if { [use_gdb_stub] } {
+ untested "not valid on native-gdbserver"
There are many other boards that set use_gdb_stub, not just
native-gdbserver. Other testcases say:

untested "skipping tests due to use_gdb_stub"
Post by Sergio Durigan Junior
return
}
+if { [target_info gdb_protocol] == "remote" } {
+ load_lib gdbserver-support.exp
+ if { [skip_gdbserver_tests] } {
+ return
+ }
+}
+
Please remember to drop this part.
Post by Sergio Durigan Junior
standard_testfile
if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-27 21:48:18 UTC
Permalink
Post by Pedro Alves
Post by Sergio Durigan Junior
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that gdbserver is supposed to cd into before executing the inferior.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unix implementation detail.
Rewrote as:

[...]
The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that the remote inferior will use.

For UNIX-like targets this feature is already implemented on
nat/fork-inferior.c, and all gdbserver has to do is to basically
implement "set_inferior_cwd" and call it whenever such packet arrives.
For other targets, like Windows, it is possible to use the existing
"get_inferior_cwd" function and do the necessary steps to make sure
that the inferior will use the specified working directory.
[...]
Post by Pedro Alves
Post by Sergio Durigan Junior
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.
Unix implementation detail. That's not how it works for Windows.
See above.
Post by Pedro Alves
Post by Sergio Durigan Junior
Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) and the
documentation.
No regressions found.
* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
(show_cwd_command): Expand text to include remote debugging.
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_set_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_set_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.
* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass the inferior's cwd to
CreateProcess.
* gdb.base/set-cwd.exp: Make it available on gdbserver.
Mention remote debugging.
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 12 ++++++++++++
gdb/common/common-inferior.h | 3 +++
gdb/doc/gdb.texinfo | 39 +++++++++++++++++++++++++++++++++++---
gdb/gdbserver/inferiors.c | 9 +++++++++
gdb/gdbserver/server.c | 18 +++++++++++++++++-
gdb/gdbserver/win32-low.c | 15 ++++++++++++---
gdb/infcmd.c | 7 ++++---
gdb/remote.c | 37 ++++++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 11 +++++++++--
9 files changed, 139 insertions(+), 12 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index c131713293..4ac340eeb5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -23,6 +23,14 @@
* New features in the GDB remote stub, GDBserver
+ ** GDBserver is now able to set the inferior's current working
+ directory.
+
+ The user can set the desired working directory to be used by the
+ remote inferior on GDB, using the new "set cwd" command, which
+ will instruct GDB to tell GDBserver about this directory change
+ the next time an inferior is run.
+
** New "--selftest" command line option runs some GDBserver self
tests. These self tests are disabled in releases.
@@ -56,6 +64,10 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.
+QSetWorkingDir
+ Tell GDBserver that the inferior to be started should use a specific
+ working directory.
+
* The "maintenance print c-tdesc" command now takes an optional
argument which is the file name of XML target description.
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 515a8c0f4e..26acddc84a 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,7 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();
+/* Set the inferior current working directory. */
+extern void set_inferior_cwd (const char *cwd);
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 899afb92b6..7434de2a68 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
You can set your program's working directory with the command
@code{set cwd}. If you do not set any working directory with this
+Directory}.
because not all remote debugging uses gdbserver.
Updated.
Post by Pedro Alves
Post by Sergio Durigan Junior
@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
@@ -2439,7 +2441,9 @@ Each time you start your program with @code{run}, the inferior will be
initialized with the current working directory specified by the
@code{set cwd} command. If no directory has been specified by this
-directory as its working directory.
+directory as its working directory if native debugging, or it will
+debugging.
Ditto.
Updated.
Post by Pedro Alves
Post by Sergio Durigan Junior
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@table @samp
@item OK
The request succeeded.
+
string, like you're already doing. That's what we do
elsewhere in the manual.
Sure. Updated
Post by Pedro Alves
Ditto re. "gdbserver".
Updated.
Post by Pedro Alves
Post by Sergio Durigan Junior
+current working directory for programs that are going to be executed.
+
+
+Working Directory}).
"This packet is only transmitted when set cwd" suggests to me that
the packet is sent immediately when the user types "set cwd".
This packet is only transmitted if the user explicitly
Rewrote it.
Post by Pedro Alves
s/when/if/.
It's @kbd (from "keyboard"). But I know, our muscle memory wants us to
type "db" :-P.

Even though I slightly disagree here (commands are not keybindings), I
Post by Pedro Alves
Post by Sergio Durigan Junior
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e78ad4faf1..326d01f4d9 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,12 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f3eee31052..14f8a732a7 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
return;
}
+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Changed current directory to %s]\n"),
+ path.c_str ());
Please tweak the debug string to be clear that this is the
inferior's cwd, not gdbserver's.
OK, changed to:

debug_printf (_("[Set the inferior's current directory to %s]\n"),
path.c_str ());
Post by Pedro Alves
Post by Sergio Durigan Junior
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2355,7 +2370,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);
if (target_supports_catch_syscall ())
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index cc84d15c2f..62b222d2fa 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,10 +562,11 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;
#ifdef _WIN32_WCE
- wchar_t *p, *wprogram, *wargs;
+ wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
size_t argslen;
wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
@@ -579,6 +580,14 @@ create_process (const char *program, char *args,
wargs = alloca ((argslen + 1) * sizeof (wchar_t));
mbstowcs (wargs, args, argslen + 1);
+ if (inferior_cwd != NULL)
+ {
+ size_t cwdlen = strlen (inferior_cwd);
+
+ wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+ mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+ }
+
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
@@ -586,7 +595,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +608,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 4c5bbfdbf2..f483a33a44 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -250,9 +250,9 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}
-/* Set the inferior current working directory. */
+/* See common/common-inferior.h. */
-static void
+void
set_inferior_cwd (const char *cwd)
{
if (*cwd == '\0')
@@ -292,7 +292,8 @@ show_cwd_command (struct ui_file *file, int from_tty,
fprintf_filtered (gdb_stdout,
_("\
You have not set the inferior's current working directory.\n\
-The inferior will inherit GDB's cwd.\n"));
+The inferior will inherit GDB's cwd if native debugging, or gdbserver's\n\
+cwd if remote debugging.\n"));
gdbserver -> remote server.
Updated.
Post by Pedro Alves
Post by Sergio Durigan Junior
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
set cwd foo
run
kill
set cwd # clear
run
Do we clear the cwd on the remote end or we do we fail the
NULL check above?
In this specific version of the patch, which does not have the
implementation to clear out the inferior's cwd, the empty "set cwd"
would actually make the "~" as the current directory for the inferior.
But in the next version (which I'll send), when "inferior_cwd == NULL" I
will send an empty QSetWorkingDir packet (which means I'll extend the
QSetWorkingDir packet to accept empty arguments), and that will clear
things up in the server side.
Post by Pedro Alves
Post by Sergio Durigan Junior
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ current_inferior_cwd = xstrdup (cwd);
+}
This always sets to non-NULL. So is it really possible
to get back to the original clear state? Doesn't look like it?
Do we have a test for that?
Not in this specific version, no. This was something decided *after* I
had sent this version. In my local tree I have code implementing the
"clear up" behaviour, and I'll add a test for that as well.
Post by Pedro Alves
Post by Sergio Durigan Junior
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QSetWorkingDir])
+ != PACKET_OK)
+ error (_("\
+Remote replied unexpectedly while changing working directory: %s"),
+ rs->buf);
Again "changing". Maybe say "setting the inferior's working directory"
instead.
OK.
Post by Pedro Alves
Post by Sergio Durigan Junior
+ }
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9686,6 +9718,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
extended_remote_environment_support (rs);
+ extended_remote_set_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14185,6 +14219,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index f2700ec44d..32458e384e 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,11 +15,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-if { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
- untested "not implemented on gdbserver"
+if { [use_gdb_stub] } {
+ untested "not valid on native-gdbserver"
There are many other boards that set use_gdb_stub, not just
untested "skipping tests due to use_gdb_stub"
Hm, OK.

Does this look correct now, though?
Post by Pedro Alves
Post by Sergio Durigan Junior
return
}
+if { [target_info gdb_protocol] == "remote" } {
+ load_lib gdbserver-support.exp
+ if { [skip_gdbserver_tests] } {
+ return
+ }
+}
+
Please remember to drop this part.
Already did. Thanks.
Post by Pedro Alves
Post by Sergio Durigan Junior
standard_testfile
if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
Thanks,
Pedro Alves
Thanks,
--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
Pedro Alves
2017-09-29 14:03:21 UTC
Permalink
Post by Sergio Durigan Junior
Post by Pedro Alves
s/when/if/.
type "db" :-P.
;-)
Post by Sergio Durigan Junior
Even though I slightly disagree here (commands are not keybindings), I
See discussion starting here:

https://sourceware.org/ml/gdb-patches/2017-06/msg00592.html
Post by Sergio Durigan Junior
Not in this specific version, no. This was something decided *after* I
had sent this version. In my local tree I have code implementing the
"clear up" behaviour, and I'll add a test for that as well.
OK, thanks. Sorry I got confused.
Post by Sergio Durigan Junior
Post by Pedro Alves
There are many other boards that set use_gdb_stub, not just
untested "skipping tests due to use_gdb_stub"
Hm, OK.
Does this look correct now, though?
I don't know; I'll take a look at v4. We may
still need is_remote checks depending on whether the
tests have assumptions about build==host or host==target.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-28 04:10:43 UTC
Permalink
v1: https://sourceware.org/ml/gdb-patches/2017-09/msg00321.html
v2: https://sourceware.org/ml/gdb-patches/2017-09/msg00458.html
v3: https://sourceware.org/ml/gdb-patches/2017-09/msg00658.html

Changes from v3:

* Patch #1 (former patch #3):

- Do not s/tilde_expand/gdb_tilde_expand/ on
gdb/cli/cli-cmds.c:cd_command (leave as a possible cleanup for
later patches).

- Use only GLOB_TILDE_CHECK (and not "GLOB_TILDE | GLOB_TILDE_CHECK
| GLOB_ONLYDIR") when calling "glob", making "gdb_tilde_expand" to
behave as a general-purpose "tilde-expander" (i.e., don't deal only
with dirs).

* Patch #2 (former patch #4):

- Rewrite several parts of the documentation (NEWS, gdb.texinfo,
commit log, etc.) in order to remove target-dependent sentences
explaining how GDB deals with the inferior's cwd.

- Expand documentation to explain what "~" means on Windows.

- Improve Windows-related code to perform wide-char conversion when
needed, and mirror slashes of paths provided by the user. Call
"gdb_tilde_expand" before passing the path to CreateProcess.

- Make "set cwd" (without arguments) actually clean up the
previously set inferior's cwd (i.e., reset it to an empty value),
instead of defaulting to "~" as "cd" does. Adjust testsuite and
code accordingly.

* Patch #3 (former patch #5):

- Rewrite several parts of the documentation (NEWS, gdb.texinfo,
commit log, etc.) in order to remove target-dependent sentences
explaining how GDB deals with the inferior's cwd.

- s/gdbserver/remote server/ in the manual.

- s/@code/@kbd/ for writing commands in the manual.

- Improve debug string on gdb/gdbserver/server.c:handle_general_set
when dealing with "QSetWorkingDir".

- Implement the "set cwd"-without-arguments cleanup on gdbserver, by
making "QSetWorkingDir" accept an empty argument. This way, we'll
always send the packet to the remote stub, even when the user
hasn't set any cwd for the inferior.

- Improved debug string on gdb/remote.c's code to handle
"QSetWorkingDir".

- Improved message when calling "untested" because "[use_gdb_stub]"
is true.



This patch series is a followup of the discussion that happened at:

https://sourceware.org/ml/gdb-patches/2017-09/msg00160.html

It implements a new GDB command, "set cwd", which is used to set the
current working directory of the inferior that will be started. This
command works for both native and remote debugging scenarios.

The idea here is that "set cwd" will become the de facto way of
setting the inferior's cwd. Currently, the user can use "cd" for
that, but there are side effects: with "cd", GDB also switches to
another directory, and that can impact the loading of scripts and
other files. With "set cwd", we separate the logic into a new
command.

To maintain backward compatibility, if the user issues a "cd" command
but doesn't use "set cwd", then the inferior's cwd will still be
changed according to what the user specified. However, "set cwd" has
precedence over "cd", so it can always be used to override it.
Sergio Durigan Junior
2017-09-28 04:10:44 UTC
Permalink
Currently, whenever we want to handle paths provided by the user and
perform tilde expansion on GDB, we rely on "tilde_expand", which comes
from readline. This was enough for our use cases so far, but the
situation will change when we start dealing with paths on gdbserver as
well, which is what the next patches implement.

Unfortunately it is not possible to use "tilde_expand" in this case
because gdbserver doesn't use readline. For that reason I decided to
implement a new "gdb_tilde_expand" function, which is basically a
wrapper for "glob" and its GNU extension, GLOB_TILDE_CHECK. With the
import of the "glob" module from gnulib, this is a no-brainer.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add gdb_tilde_expand.c.
(HFILES_NO_SRCDIR): Add gdb_tilde_expand.h.
(COMMON_OBS): Add gdb_tilde_expand.o.
* common/gdb_tilde_expand.c: New file.
* common/gdb_tilde_expand.h: Likewise.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* Makefile.in (SFILES): Add $(srcdir)/common/gdb_tilde_expand.c.
(OBS): Add gdb_tilde_expand.o.
---
gdb/Makefile.in | 3 ++
gdb/common/gdb_tilde_expand.c | 82 +++++++++++++++++++++++++++++++++++++++++++
gdb/common/gdb_tilde_expand.h | 27 ++++++++++++++
gdb/gdbserver/Makefile.in | 2 ++
4 files changed, 114 insertions(+)
create mode 100644 gdb/common/gdb_tilde_expand.c
create mode 100644 gdb/common/gdb_tilde_expand.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9004b350e4..d60b5d984b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1246,6 +1246,7 @@ SFILES = \
common/filestuff.c \
common/format.c \
common/job-control.c \
+ common/gdb_tilde_expand.c \
common/gdb_vecs.c \
common/new-op.c \
common/print-utils.c \
@@ -1530,6 +1531,7 @@ HFILES_NO_SRCDIR = \
common/fileio.h \
common/format.h \
common/gdb_assert.h \
+ common/gdb_tilde_expand.h \
common/gdb_locale.h \
common/gdb_setjmp.h \
common/gdb_signals.h \
@@ -1735,6 +1737,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
frame-unwind.o \
gcore.o \
gdb_bfd.o \
+ gdb_tilde_expand.o \
gdb-dlfcn.o \
gdb_obstack.o \
gdb_regex.o \
diff --git a/gdb/common/gdb_tilde_expand.c b/gdb/common/gdb_tilde_expand.c
new file mode 100644
index 0000000000..8dd94239f9
--- /dev/null
+++ b/gdb/common/gdb_tilde_expand.c
@@ -0,0 +1,82 @@
+/* Perform tilde expansion on paths for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "common-defs.h"
+#include "gdb_tilde_expand.h"
+#include <glob.h>
+
+/* RAII-style class wrapping "glob". */
+
+class gdb_glob
+{
+public:
+ /* Construct a "gdb_glob" object by calling "glob" with the provided
+ parameters. This function can throw if "glob" fails. */
+ gdb_glob (const char *pattern, int flags,
+ int (*errfunc) (const char *epath, int eerrno))
+ {
+ int ret = glob (pattern, flags, errfunc, &m_glob);
+
+ if (ret != 0)
+ {
+ if (ret == GLOB_NOMATCH)
+ error (_("Could not find a match for '%s'."), pattern);
+ else
+ error (_("glob could not process pattern '%s'."),
+ pattern);
+ }
+ }
+
+ /* Destroy the object and free M_GLOB. */
+ ~gdb_glob ()
+ {
+ globfree (&m_glob);
+ }
+
+ /* Return the GL_PATHC component of M_GLOB. */
+ int pathc () const
+ {
+ return m_glob.gl_pathc;
+ }
+
+ /* Return the GL_PATHV component of M_GLOB. */
+ char **pathv () const
+ {
+ return m_glob.gl_pathv;
+ }
+
+private:
+ /* The actual glob object we're dealing with. */
+ glob_t m_glob;
+};
+
+/* See common/gdb_tilde_expand.h. */
+
+std::string
+gdb_tilde_expand (const char *dir)
+{
+ gdb_glob glob (dir, GLOB_TILDE_CHECK, NULL);
+
+ gdb_assert (glob.pathc () > 0);
+ /* "glob" may return more than one match to the path provided by the
+ user, but we are only interested in the first match. */
+ std::string expanded_dir = glob.pathv ()[0];
+
+ return expanded_dir;
+}
diff --git a/gdb/common/gdb_tilde_expand.h b/gdb/common/gdb_tilde_expand.h
new file mode 100644
index 0000000000..a5d923d66b
--- /dev/null
+++ b/gdb/common/gdb_tilde_expand.h
@@ -0,0 +1,27 @@
+/* Perform tilde expansion on paths for GDB and gdbserver.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef HAVE_GDB_TILDE_EXPAND_H
+#define HAVE_GDB_TILDE_EXPAND_H
+
+/* Perform path expansion (i.e., tilde expansion) on DIR, and return
+ the full path. */
+extern std::string gdb_tilde_expand (const char *dir);
+
+#endif /* ! HAVE_GDB_TILDE_EXPAND_H */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1bbe515629..6c931ba952 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -205,6 +205,7 @@ SFILES = \
$(srcdir)/common/fileio.c \
$(srcdir)/common/filestuff.c \
$(srcdir)/common/job-control.c \
+ $(srcdir)/common/gdb_tilde_expand.c \
$(srcdir)/common/gdb_vecs.c \
$(srcdir)/common/new-op.c \
$(srcdir)/common/print-utils.c \
@@ -247,6 +248,7 @@ OBS = \
fileio.o \
filestuff.o \
format.o \
+ gdb_tilde_expand.o \
gdb_vecs.o \
hostio.o \
inferiors.o \
--
2.13.3
Pedro Alves
2017-09-29 14:08:09 UTC
Permalink
Post by Sergio Durigan Junior
--- /dev/null
+++ b/gdb/common/gdb_tilde_expand.h
+
+#ifndef HAVE_GDB_TILDE_EXPAND_H
+#define HAVE_GDB_TILDE_EXPAND_H
HAVE above should be COMMON_GDB_TILDE_EXPAND_H surely.

OK with that change.

Thanks,
Pedro Alves
Sergio Durigan Junior
2017-09-28 04:10:46 UTC
Permalink
This is the "natural" extension necessary for the "set cwd" command
(and the whole "set the inferior's cwd" logic) to work on gdbserver.

The idea here is to have a new remote packet, QSetWorkingDir (name
adopted from LLDB's extension to the RSP, as can be seen at
<https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
which sends an hex-encoded string representing the working directory
that the remote inferior will use. There is a slight difference from
the packet proposed by LLDB: GDB's version will accept empty
arguments, meaning that the user wants to clear the previously set
working directory for the inferior (i.e., "set cwd" without arguments
on GDB).

For UNIX-like targets this feature is already implemented on
nat/fork-inferior.c, and all gdbserver has to do is to basically
implement "set_inferior_cwd" and call it whenever such packet arrives.
For other targets, like Windows, it is possible to use the existing
"get_inferior_cwd" function and do the necessary steps to make sure
that the inferior will use the specified working directory.

Aside from that, the patch consists basically of updates to the
testcase (making it available on remote targets) and the
documentation.

No regressions found.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* NEWS (Changes since GDB 8.0): Add entry about new
'set-cwd-on-gdbserver' feature.
(New remote packets): Add entry for QSetWorkingDir.
* common/common-inferior.h (set_inferior_cwd): New prototype.
* infcmd.c (set_inferior_cwd): Remove "static".
(show_cwd_command): Expand text to include remote debugging.
* remote.c: Add PACKET_QSetWorkingDir.
(remote_protocol_features) <QSetWorkingDir>: New entry for
PACKET_QSetWorkingDir.
(extended_remote_set_inferior_cwd): New function.
(extended_remote_create_inferior): Call
"extended_remote_set_inferior_cwd".
(_initialize_remote): Call "add_packet_config_cmd" for
QSetWorkingDir.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* inferiors.c (set_inferior_cwd): New function.
* server.c (handle_general_set): Handle QSetWorkingDir packet.
(handle_query): Inform that QSetWorkingDir is supported.
* win32-low.c (create_process): Pass the inferior's cwd to
CreateProcess.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.base/set-cwd.exp: Make it available on
native-extended-gdbserver.

gdb/doc/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.texinfo (Starting your Program) <The working directory.>:
Mention remote debugging.
(Working Directory) <Your Program's Working Directory>:
Likewise.
(Connecting) <Remote Packet>: Add "set-working-dir"
and "QSetWorkingDir" to the table.
(Remote Protocol) <QSetWorkingDir>: New item, explaining the
packet.
---
gdb/NEWS | 12 +++++++++++
gdb/common/common-inferior.h | 4 ++++
gdb/doc/gdb.texinfo | 43 +++++++++++++++++++++++++++++++++++---
gdb/gdbserver/inferiors.c | 12 +++++++++++
gdb/gdbserver/server.c | 30 +++++++++++++++++++++++++-
gdb/gdbserver/win32-low.c | 22 ++++++++++++++++---
gdb/infcmd.c | 8 +++----
gdb/remote.c | 43 ++++++++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/set-cwd.exp | 4 ++--
9 files changed, 165 insertions(+), 13 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index fcf454833f..d68b3464e7 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -26,6 +26,14 @@

* New features in the GDB remote stub, GDBserver

+ ** GDBserver is now able to set the inferior's current working
+ directory.
+
+ The user can set the desired working directory to be used by the
+ remote inferior on GDB, using the new "set cwd" command, which
+ will instruct GDB to tell GDBserver about this directory change
+ the next time an inferior is run.
+
** New "--selftest" command line option runs some GDBserver self
tests. These self tests are disabled in releases.

@@ -59,6 +67,10 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.

+QSetWorkingDir
+ Tell GDBserver that the inferior to be started should use a specific
+ working directory.
+
* The "maintenance print c-tdesc" command now takes an optional
argument which is the file name of XML target description.

diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 515a8c0f4e..3dcfda3e7b 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,8 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();

+/* Set the inferior current working directory. If CWD is NULL, unset
+ the directory. */
+extern void set_inferior_cwd (const char *cwd);
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0d059603cf..2d041f9819 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
You can set your program's working directory with the command
@kbd{set cwd}. If you do not set any working directory with this
-command, your program will inherit @value{GDBN}'s working directory.
-@xref{Working Directory, ,Your Program's Working Directory}.
+command, your program will inherit @value{GDBN}'s working directory if
+native debugging, or the remote server's working directory if remote
+debugging. @xref{Working Directory, ,Your Program's Working
+Directory}.

@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
@@ -2439,7 +2441,9 @@ Each time you start your program with @code{run}, the inferior will be
initialized with the current working directory specified by the
@kbd{set cwd} command. If no directory has been specified by this
command, then the inferior will inherit @value{GDBN}'s current working
-directory as its working directory.
+directory as its working directory if native debugging, or it will
+inherit the remote server's current working directory if remote
+debugging.

You can also change @value{GDBN}'s current working directory by using
the @code{cd} command.
@@ -20999,6 +21003,10 @@ are:
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}

+@item @code{set-working-dir}
+@tab @code{QSetWorkingDir}
+@tab @code{set cwd}
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@@ -36856,6 +36864,35 @@ by supplying an appropriate @samp{qSupported} response
actually support passing environment variables to the starting
inferior.

+@item QSetWorkingDir:@r{[}@var{directory}@r{]}
+@anchor{QSetWorkingDir packet}
+@cindex set working directory, remote request
+@cindex @samp{QSetWorkingDir} packet
+This packet is used to inform the remote server of the intended
+current working directory for programs that are going to be executed.
+
+The packet is composed by @var{directory}, an hex encoded
+representation of the directory that the remote inferior will use as
+its current working directory. If @var{directory} is an empty string,
+the remote server should reset the inferior's current working
+directory to its original, empty value.
+
+This packet is always transmitted when the inferior is run. If the
+user has not explcitly specified a directory with the @kbd{set cwd}
+command, then an empty packet will be sent to the remote server, which
+will have no effect. Otherwise, the specified inferior's working
+directory will be transmitted (@pxref{Working Directory, ,Your
+Program's Working Directory}).
+
+This packet is only available in extended mode (@pxref{extended
+mode}).
+
+Reply:
+@table @samp
+@item OK
+The request succeeded.
+@end table
+
@item qfThreadInfo
@itemx qsThreadInfo
@cindex list active threads, remote request
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 57d9956ebb..154c167f4c 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,15 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ if (cwd != NULL)
+ current_inferior_cwd = xstrdup (cwd);
+ else
+ current_inferior_cwd = NULL;
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f3eee31052..8e3d30fb53 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,33 @@ handle_general_set (char *own_buf)
return;
}

+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+
+ if (*p != '\0')
+ {
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Set the inferior's current directory to %s]\n"),
+ path.c_str ());
+ }
+ else
+ {
+ set_inferior_cwd (NULL);
+
+ if (remote_debug)
+ debug_printf (_("\
+[Unset the inferior's current directory; will use gdbserver's cwd]\n"));
+ }
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2355,7 +2382,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);

if (target_supports_catch_syscall ())
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index cc84d15c2f..c11926f7c6 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -32,6 +32,7 @@
#include <tlhelp32.h>
#include <psapi.h>
#include <process.h>
+#include "gdb_tilde_expand.h"

#ifndef USE_WIN32API
#include <sys/cygwin.h>
@@ -562,10 +563,12 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
+ std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);
BOOL ret;

#ifdef _WIN32_WCE
- wchar_t *p, *wprogram, *wargs;
+ wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
size_t argslen;

wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
@@ -579,6 +582,19 @@ create_process (const char *program, char *args,
wargs = alloca ((argslen + 1) * sizeof (wchar_t));
mbstowcs (wargs, args, argslen + 1);

+ if (inferior_cwd != NULL)
+ {
+ std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
+ '/', '\\');
+ wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t));
+ if (mbstowcs (wcwd, expanded_infcwd.c_str (),
+ expanded_infcwd.size () + 1) == NULL)
+ {
+ error (_("\
+Could not convert the expanded inferior cwd to wide-char."));
+ }
+ }
+
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
@@ -586,7 +602,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +615,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ expanded_infcwd.c_str (), /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index dbdf273ca5..187c71f344 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -242,10 +242,9 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}

-/* Set the inferior current working directory. If CWD is NULL, unset
- the directory. */
+/* See common/common-inferior.h. */

-static void
+void
set_inferior_cwd (const char *cwd)
{
struct inferior *inf = current_inferior ();
@@ -289,7 +288,8 @@ show_cwd_command (struct ui_file *file, int from_tty,
fprintf_filtered (gdb_stdout,
_("\
You have not set the inferior's current working directory.\n\
-The inferior will inherit GDB's cwd.\n"));
+The inferior will inherit GDB's cwd if native debugging, or the remote\n\
+server's cwd if remote debugging.\n"));
else
fprintf_filtered (gdb_stdout,
_("Current working directory that will be used "
diff --git a/gdb/remote.c b/gdb/remote.c
index d4f06a84da..267646f2ef 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1430,6 +1430,7 @@ enum {
PACKET_QPassSignals,
PACKET_QCatchSyscalls,
PACKET_QProgramSignals,
+ PACKET_QSetWorkingDir,
PACKET_QStartupWithShell,
PACKET_QEnvironmentHexEncoded,
PACKET_QEnvironmentReset,
@@ -4661,6 +4662,8 @@ static const struct protocol_feature remote_protocol_features[] = {
PACKET_QCatchSyscalls },
{ "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QProgramSignals },
+ { "QSetWorkingDir", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QSetWorkingDir },
{ "QStartupWithShell", PACKET_DISABLE, remote_supported_packet,
PACKET_QStartupWithShell },
{ "QEnvironmentHexEncoded", PACKET_DISABLE, remote_supported_packet,
@@ -9640,6 +9643,41 @@ extended_remote_environment_support (struct remote_state *rs)
send_environment_packet (rs, "unset", "QEnvironmentUnset", el.c_str ());
}

+/* Helper function to set the current working directory for the
+ inferior in the remote. */
+
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ }
+ else
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:");
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QSetWorkingDir])
+ != PACKET_OK)
+ error (_("\
+Remote replied unexpectedly while setting the inferior's working\n\
+directory: %s"),
+ rs->buf);
+
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9682,6 +9720,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),

extended_remote_environment_support (rs);

+ extended_remote_set_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14181,6 +14221,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);

+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);

diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index 3d666ba18d..60eb404c06 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,8 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

-if { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
- untested "not implemented on gdbserver"
+if { [use_gdb_stub] } {
+ untested "skipping tests due to use_gdb_stub"
return
}
--
2.13.3
Pedro Alves
2017-09-29 15:21:14 UTC
Permalink
Post by Sergio Durigan Junior
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -26,6 +26,14 @@
* New features in the GDB remote stub, GDBserver
+ ** GDBserver is now able to set the inferior's current working
+ directory.
That's confusing IMO, because it sounds like you're saying
you can change the inferior's current working directory at
any time, even on inferiors that are already running...

I'd go for:

** GDBserver is now able to start inferior processes with a
specified initial working directory.
Post by Sergio Durigan Junior
+
+ The user can set the desired working directory to be used by the
+ remote inferior on GDB, using the new "set cwd" command, which
+ will instruct GDB to tell GDBserver about this directory change
+ the next time an inferior is run.
And instead of the above, say:

The user can set the desired working directory to be used from GDB
using the new "set cwd" command.

Note "on" -> "from". I think that conveys it better.

The "which will instruct" part is distracting and unnecessary
implementation detail, IMO.
Post by Sergio Durigan Junior
+This packet is used to inform the remote server of the intended
+current working directory for programs that are going to be executed.
+
+representation of the directory that the remote inferior will use as
+the remote server should reset the inferior's current working
+directory to its original, empty value.
+
+This packet is always transmitted when the inferior is run. If the
typo: explicitly
Post by Sergio Durigan Junior
+command, then an empty packet will be sent to the remote server, which
Not an empty packet, and empty directory. Really-empty packets are
special in the remote protocol.
Post by Sergio Durigan Junior
+will have no effect.
WDYM will have no effect, when just above you've explained that empty
means reset ? I think you should just remove this paragraph starting
with "This packet is always transmitted". That's implementation
detail. GDB could for example not resend the packet if the value
didn't change between runs, no?
Post by Sergio Durigan Junior
Otherwise, the specified inferior's working
+Program's Working Directory}).
This too should be tweaked accordingly.
Post by Sergio Durigan Junior
+
+mode}).
+
Thanks,
Pedro Alves

Sergio Durigan Junior
2017-09-28 04:10:45 UTC
Permalink
This is the actual implementation of the "set/show cwd" commands on
GDB. The way they work is:

- If the user sets the inferior's cwd by using "set cwd", then this
directory is saved into current_inferior ()->cwd and is used when
the inferior is started (see below).

- If the user doesn't set the inferior's cwd by using "set cwd", but
rather use the "cd" command as before, then this directory is
inherited by the inferior because GDB will have chdir'd into it.

On Unix-like hosts, the way the directory is changed before the
inferior execution is by expanding the user set directory before the
fork, and then "chdir" after the call to fork/vfork on
"fork_inferior", but before the actual execution. On Windows, the
inferior cwd set by the user is passed directly to the CreateProcess
call, which takes care of the actual chdir for us.

This way, we'll make sure that GDB's cwd is not affected by the user
set cwd.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* NEWS (New commands): Mention "set/show cwd".
* cli/cli-cmds.c (_initialize_cli_cmds): Mention "set cwd" on
"cd" command's help text.
* common/common-inferior.h (get_inferior_cwd): New prototype.
* infcmd.c (inferior_cwd_scratch): New global variable.
(set_inferior_cwd): New function.
(get_inferior_cwd): Likewise.
(set_cwd_command): Likewise.
(show_cwd_command): Likewise.
(_initialize_infcmd): Add "set/show cwd" commands.
* inferior.h (class inferior) <cwd>: New field.
* nat/fork-inferior.c: Include "gdb_tilde_expand.h".
(fork_inferior): Change inferior's cwd before its execution.
* windows-nat.c (windows_create_inferior): Pass inferior's cwd
to CreateProcess.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* inferiors.c (current_inferior_cwd): New global variable.
(get_inferior_cwd): New function.
* inferiors.h (struct process_info) <cwd>: New field.

gdb/doc/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.texinfo (Starting your Program) <The working directory.>:
Mention new "set cwd" command.
(Working Directory) <Your Program's Working Directory>:
Rephrase to explain that "set cwd" exists and is the default
way to change the inferior's cwd.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <***@redhat.com>

* gdb.base/set-cwd.c: New file.
* gdb.base/set-cwd.exp: Likewise.
---
gdb/NEWS | 3 +
gdb/cli/cli-cmds.c | 8 +-
gdb/common/common-inferior.h | 4 +
gdb/doc/gdb.texinfo | 41 ++++++--
gdb/gdbserver/inferiors.c | 11 ++
gdb/infcmd.c | 77 ++++++++++++++
gdb/inferior.h | 4 +
gdb/nat/fork-inferior.c | 18 ++++
gdb/testsuite/gdb.base/set-cwd.c | 32 ++++++
gdb/testsuite/gdb.base/set-cwd.exp | 206 +++++++++++++++++++++++++++++++++++++
gdb/windows-nat.c | 16 ++-
11 files changed, 407 insertions(+), 13 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/set-cwd.c
create mode 100644 gdb/testsuite/gdb.base/set-cwd.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 81c21b82cc..fcf454833f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -67,6 +67,9 @@ QStartupWithShell

* New commands

+set|show cwd
+ Set and show the current working directory for the inferior.
+
set|show compile-gcc
Set and show compilation command used for compiling and injecting code
with the 'compile' commands.
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index dde67ee2b3..dad5ffa42e 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1727,9 +1727,11 @@ The commands below can be used to select other frames by number or address."),
Print working directory. This is used for your program as well."));

c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
+The debugger's current working directory specifies where scripts and other\n\
+files that can be loaded by GDB are located.\n\
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
set_cmd_completer (c, filename_completer);

add_com ("echo", class_support, echo_command, _("\
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
index 87c13009ed..515a8c0f4e 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -30,4 +30,8 @@ extern const char *get_exec_wrapper ();
otherwise return 0 in that case. */
extern char *get_exec_file (int err);

+/* Return the inferior's current working directory. If nothing has
+ been set, then return NULL. */
+extern const char *get_inferior_cwd ();
+
#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9905ff6513..0d059603cf 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2057,8 +2057,9 @@ environment} to change parts of the environment that affect
your program. @xref{Environment, ,Your Program's Environment}.

@item The @emph{working directory.}
-Your program inherits its working directory from @value{GDBN}. You can set
-the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}.
+You can set your program's working directory with the command
+@kbd{set cwd}. If you do not set any working directory with this
+command, your program will inherit @value{GDBN}'s working directory.
@xref{Working Directory, ,Your Program's Working Directory}.

@item The @emph{standard input and output.}
@@ -2434,19 +2435,43 @@ variables to files that are only run when you sign on, such as
@section Your Program's Working Directory

@cindex working directory (of your program)
-Each time you start your program with @code{run}, it inherits its
-working directory from the current working directory of @value{GDBN}.
-The @value{GDBN} working directory is initially whatever it inherited
-from its parent process (typically the shell), but you can specify a new
-working directory in @value{GDBN} with the @code{cd} command.
+Each time you start your program with @code{run}, the inferior will be
+initialized with the current working directory specified by the
+@kbd{set cwd} command. If no directory has been specified by this
+command, then the inferior will inherit @value{GDBN}'s current working
+directory as its working directory.
+
+You can also change @value{GDBN}'s current working directory by using
+the @code{cd} command.

The @value{GDBN} working directory also serves as a default for the commands
that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to
Specify Files}.

@table @code
+@kindex set cwd
+@cindex change inferior's working directory
+@item set cwd @r{[}@var{directory}@r{]}
+Set the inferior's working directory to @var{directory}, which will be
+@code{glob}-expanded in order to resolve tildes (@file{~}). If no
+argument has been specified, the command clears the setting and resets
+it to an empty state. This setting has no effect on @value{GDBN}'s
+working directory, and it only takes effect the next time you start
+the inferior. The @file{~} in @var{directory} is a short for the
+@dfn{home directory}, usually pointed to by the @env{HOME} environment
+variable. On MS-Windows, if @env{HOME} is not defined, @value{GDBN}
+uses the concatenation of @env{HOMEDRIVE} and @env{HOMEPATH} as
+fallback.
+
+@kindex show cwd
+@cindex show inferior's working directory
+@item show cwd
+Show the inferior's working directory. If no directory has been
+specified by @kbd{set cwd}, then the default inferior's working
+directory is the same as @value{GDBN}'s working directory.
+
@kindex cd
-@cindex change working directory
+@cindex change @value{GDBN}'s working directory
@item cd @r{[}@var{directory}@r{]}
Set the @value{GDBN} working directory to @var{directory}. If not
given, @var{directory} uses @file{'~'}.
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 3a45959000..57d9956ebb 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,9 @@ struct thread_info *current_thread;

#define get_thread(inf) ((struct thread_info *)(inf))

+/* The current working directory used to start the inferior. */
+static const char *current_inferior_cwd = NULL;
+
void
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
@@ -445,3 +448,11 @@ switch_to_thread (ptid_t ptid)
gdb_assert (ptid != minus_one_ptid);
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index da16f5ed6d..dbdf273ca5 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -103,6 +103,10 @@ static void run_command (char *, int);

static char *inferior_args_scratch;

+/* Scratch area where the new cwd will be stored by 'set cwd'. */
+
+static char *inferior_cwd_scratch;
+
/* Scratch area where 'set inferior-tty' will store user-provided value.
We'll immediate copy it into per-inferior storage. */

@@ -238,6 +242,60 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}

+/* Set the inferior current working directory. If CWD is NULL, unset
+ the directory. */
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+
+ if (cwd == NULL)
+ inf->cwd.reset ();
+ else
+ inf->cwd.reset (xstrdup (cwd));
+}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior ()->cwd.get ();
+}
+
+/* Handle the 'set cwd' command. */
+
+static void
+set_cwd_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ if (*inferior_cwd_scratch == '\0')
+ set_inferior_cwd (NULL);
+ else
+ set_inferior_cwd (inferior_cwd_scratch);
+}
+
+/* Handle the 'show cwd' command. */
+
+static void
+show_cwd_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd == NULL)
+ fprintf_filtered (gdb_stdout,
+ _("\
+You have not set the inferior's current working directory.\n\
+The inferior will inherit GDB's cwd.\n"));
+ else
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+

/* Compute command-line string given argument vector. This does the
same shell processing as fork_inferior. */
@@ -3253,6 +3311,25 @@ Follow this command with any number of args, to be passed to the program."),
gdb_assert (c != NULL);
set_cmd_completer (c, filename_completer);

+ cmd_name = "cwd";
+ add_setshow_string_noescape_cmd (cmd_name, class_run,
+ &inferior_cwd_scratch, _("\
+Set the current working directory to be used when the inferior is started.\n\
+Changing this setting does not have any effect on inferiors that are\n\
+already running."),
+ _("\
+Show the current working directory that is used when the inferior is started."),
+ _("\
+Use this command to change the current working directory that will be used\n\
+when the inferior is started. This setting does not affect GDB's current\n\
+working directory."),
+ set_cwd_command,
+ show_cwd_command,
+ &setlist, &showlist);
+ c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+ gdb_assert (c != NULL);
+ set_cmd_completer (c, filename_completer);
+
c = add_cmd ("environment", no_class, environment_info, _("\
The environment to give the program, or one variable's value.\n\
With an argument VAR, prints the value of environment variable VAR to\n\
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 7f2d53e5b3..498d74706a 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -355,6 +355,10 @@ public:
should never be freed. */
char **argv = NULL;

+ /* The current working directory that will be used when starting
+ this inferior. */
+ gdb::unique_xmalloc_ptr<char> cwd;
+
/* The name of terminal device to use for I/O. */
char *terminal = NULL;

diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index 6ff119768c..0ce442f162 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -25,6 +25,7 @@
#include "common-inferior.h"
#include "common-gdbthread.h"
#include "signals-state-save-restore.h"
+#include "gdb_tilde_expand.h"
#include <vector>

extern char **environ;
@@ -298,6 +299,8 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
char **save_our_env;
int i;
int save_errno;
+ const char *inferior_cwd;
+ std::string expanded_inferior_cwd;

/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
@@ -339,6 +342,13 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
the parent and child flushing the same data after the fork. */
gdb_flush_out_err ();

+ /* Check if the user wants to set a different working directory for
+ the inferior. */
+ inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ expanded_inferior_cwd = gdb_tilde_expand (inferior_cwd);
+
/* If there's any initialization of the target layers that must
happen to prepare to handle the child we're about fork, do it
now... */
@@ -374,6 +384,14 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();

+ /* Change to the requested working directory if the user
+ requested it. */
+ if (inferior_cwd != NULL)
+ {
+ if (chdir (expanded_inferior_cwd.c_str ()) < 0)
+ trace_start_error_with_name (expanded_inferior_cwd.c_str ());
+ }
+
if (debug_fork)
sleep (debug_fork);

diff --git a/gdb/testsuite/gdb.base/set-cwd.c b/gdb/testsuite/gdb.base/set-cwd.c
new file mode 100644
index 0000000000..2a501aa675
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.c
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static char dir[4096];
+
+int
+main (int argc, char *argv[])
+{
+ const char *home = getenv ("HOME");
+
+ getcwd (dir, 4096);
+
+ return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
new file mode 100644
index 0000000000..3d666ba18d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -0,0 +1,206 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
+ untested "not implemented on gdbserver"
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ global decimal gdb_prompt hex
+
+ with_test_prefix "test tilde expansion" {
+ gdb_test_no_output "set cwd ~/" "set inferior cwd to ~/ dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test_multiple "print home" "print home var" {
+ -re "\\\$$decimal = $hex \"\(.+\)\"\r\n$gdb_prompt $" {
+ set home $expect_out(1,string)
+ }
+ -re "$gdb_prompt $" {
+ untested "could to retrieve home var"
+ return
+ }
+ default {
+ untested "could to retrieve home var"
+ return
+ }
+ }
+
+ if { [string length $home] > 0 } {
+ gdb_test_multiple "print dir" "print dir var" {
+ -re "\\\$$decimal = \"\(.+\)\"\(, .*repeats.*\)?\r\n$gdb_prompt $" {
+ set curdir $expect_out(1,string)
+ }
+ -re "$gdb_prompt $" {
+ fail "failed to retrieve dir var"
+ return -1
+ }
+ default {
+ fail "failed to retrieve dir var"
+ return -1
+ }
+ }
+
+ gdb_assert [string equal $curdir $home] \
+ "successfully chdir'd into home"
+ } else {
+ untested "could not determine value of HOME"
+ return
+ }
+ }
+}
+
+# The temporary directory that we will use to start the inferior.
+set tmpdir [standard_output_file ""]
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt tmpdir
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ default {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ }
+
+ # This test only makes sense if $tmpdir != $gdb_cwd_before_run
+ if { ![gdb_assert ![string equal $tmpdir $gdb_cwd_before_run] \
+ "make sure that tmpdir and GDB's cwd are different"] } {
+ return -1
+ }
+
+ gdb_test_no_output "set cwd $tmpdir" "set inferior cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain GDB cwd after run"
+ return -1
+ }
+ default {
+ fail "failed to obtain GDB cwd after run"
+ return -1
+ }
+ }
+
+ gdb_assert [string equal $gdb_cwd_before_run $gdb_cwd_after_run] \
+ "GDB cwd is unchanged after running inferior"
+ }
+}
+
+# Test that executing "set cwd" without arguments will reset the
+# inferior's cwd setting to its previous state.
+
+proc test_cwd_reset { } {
+ global decimal gdb_prompt tmpdir
+
+ with_test_prefix "test inferior cwd reset" {
+ gdb_test_multiple "pwd" "GDB cwd" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ default {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ }
+
+ # This test only makes sense if $tmpdir != $gdb_cwd
+ # This test only makes sense if $tmpdir != $gdb_cwd
+ if { ![gdb_assert ![string equal $tmpdir $gdb_cwd] \
+ "make sure that tmpdir and GDB's cwd are different"] } {
+ return -1
+ }
+
+ gdb_test_no_output "set cwd $tmpdir" "set inferior cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ # Reset the inferior's cwd.
+ gdb_test_no_output "set cwd" "resetting inferior cwd"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$gdb_cwd\", .*" \
+ "inferior cwd got reset correctly"
+ }
+}
+
+test_cd_into_dir
+clean_restart $binfile
+test_tilde_expansion
+clean_restart $binfile
+test_cwd_reset
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 3e1894410d..5144e9f7a6 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -66,6 +66,7 @@
#include "x86-nat.h"
#include "complaints.h"
#include "inf-child.h"
+#include "gdb_tilde_expand.h"

#define AdjustTokenPrivileges dyn_AdjustTokenPrivileges
#define DebugActiveProcessStop dyn_DebugActiveProcessStop
@@ -2432,6 +2433,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
cygwin_buf_t *toexec;
cygwin_buf_t *cygallargs;
cygwin_buf_t *args;
+ cygwin_buf_t *infcwd;
char **old_env = NULL;
PWCHAR w32_env;
size_t len;
@@ -2461,6 +2463,8 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
BOOL ret;
DWORD flags = 0;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ const char *inferior_cwd = get_inferior_cwd ();
+ std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);

if (!exec_file)
error (_("No executable specified, use `target exec'."));
@@ -2514,6 +2518,10 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
flags |= DEBUG_PROCESS;
}

+ if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, expanded_infcwd.c_str (),
+ infcwd, expanded_infcwd.size ()) < 0)
+ error (_("Error converting inferior cwd: %d"), errno);
+
#ifdef __USEWIDE
args = (cygwin_buf_t *) alloca ((wcslen (toexec) + wcslen (cygallargs) + 2)
* sizeof (wchar_t));
@@ -2574,7 +2582,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32_env, /* environment */
- NULL, /* current directory */
+ infcwd, /* current directory */
&si,
&pi);
if (w32_env)
@@ -2689,6 +2697,10 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
/* Final nil string to terminate new env. */
*temp = 0;

+ /* Mirror slashes on inferior's cwd. */
+ std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
+ '/', '\\');
+
windows_init_thread_list ();
ret = CreateProcessA (0,
args, /* command line */
@@ -2697,7 +2709,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
TRUE, /* inherit handles */
flags, /* start flags */
w32env, /* environment */
- NULL, /* current directory */
+ expanded_infcwd.c_str (), /* current directory */
&si,
&pi);
if (tty != INVALID_HANDLE_VALUE)
--
2.13.3
Pedro Alves
2017-09-29 15:19:59 UTC
Permalink
Post by Sergio Durigan Junior
This is the actual implementation of the "set/show cwd" commands on
(This is not a huge deal, but note that this is
assuming the reader first read the cover letter, but the
cover letter doesn't make it to git and won't be available
to whoever looks ends up looking at the commit while doing
some archaeology.)
Post by Sergio Durigan Junior
- If the user sets the inferior's cwd by using "set cwd", then this
directory is saved into current_inferior ()->cwd and is used when
the inferior is started (see below).
- If the user doesn't set the inferior's cwd by using "set cwd", but
rather use the "cd" command as before, then this directory is
inherited by the inferior because GDB will have chdir'd into it.
On Unix-like hosts, the way the directory is changed before the
inferior execution is by expanding the user set directory before the
fork, and then "chdir" after the call to fork/vfork on
"fork_inferior", but before the actual execution. On Windows, the
inferior cwd set by the user is passed directly to the CreateProcess
call, which takes care of the actual chdir for us.
This way, we'll make sure that GDB's cwd is not affected by the user
set cwd.
@@ -339,6 +342,13 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
the parent and child flushing the same data after the fork. */
gdb_flush_out_err ();
+ /* Check if the user wants to set a different working directory for
+ the inferior. */
+ inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ expanded_inferior_cwd = gdb_tilde_expand (inferior_cwd);
Please add something like:

/* Expand before forking because between fork and exec, the child
process may only execute async-signal-safe operations. */

I think it'd look clearer to do:

inferior_cwd = get_inferior_cwd ();

if (inferior_cwd != NULL)
{
expanded_inferior_cwd = gdb_tilde_expand (inferior_cwd);
inferior_cwd = expanded_inferior_cwd.c_str ();
}

here and ...
Post by Sergio Durigan Junior
+
/* If there's any initialization of the target layers that must
happen to prepare to handle the child we're about fork, do it
now... */
@@ -374,6 +384,14 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();
+ /* Change to the requested working directory if the user
+ requested it. */
+ if (inferior_cwd != NULL)
+ {
+ if (chdir (expanded_inferior_cwd.c_str ()) < 0)
+ trace_start_error_with_name (expanded_inferior_cwd.c_str ());
+ }
... then here do:

if (inferior_cwd != NULL)
{
if (chdir (inferior_cwd) < 0)
trace_start_error_with_name (inferior_cwd);
}

Or even:

if (inferior_cwd != NULL && chdir (inferior_cwd) < 0)
trace_start_error_with_name (inferior_cwd);
Post by Sergio Durigan Junior
+++ b/gdb/testsuite/gdb.base/set-cwd.c
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
This include doesn't look necessary.
Post by Sergio Durigan Junior
+#include <stdlib.h>
+#include <unistd.h>
+
+static char dir[4096];
+
+int
+main (int argc, char *argv[])
+{
+ const char *home = getenv ("HOME");
+
+ getcwd (dir, 4096);
+
+ return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
new file mode 100644
index 0000000000..3d666ba18d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -0,0 +1,206 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
+ untested "not implemented on gdbserver"
The untested message still refers to gdbserver. OK, I see that
you're changing it in the next patch.
Post by Sergio Durigan Junior
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ global decimal gdb_prompt hex
+
+ with_test_prefix "test tilde expansion" {
Note you can use proc_with_prefix to avoid having to
write procs with nested scopes.
Post by Sergio Durigan Junior
+ gdb_test_no_output "set cwd ~/" "set inferior cwd to ~/ dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test_multiple "print home" "print home var" {
+ -re "\\\$$decimal = $hex \"\(.+\)\"\r\n$gdb_prompt $" {
+ set home $expect_out(1,string)
+ }
+ -re "$gdb_prompt $" {
+ untested "could to retrieve home var"
+ return
"could not" I assume.
Post by Sergio Durigan Junior
+ }
+ default {
+ untested "could to retrieve home var"
+ return
+ }
+ }
I'd rather this was written like this:

set home ""
set test "print home var"
gdb_test_multiple "print home" $test {
-re "\\\$$decimal = $hex \"\(.+\)\"\r\n$gdb_prompt $" {
set home $expect_out(1,string)
pass $test
}
}

if {$home == ""} {
untested "could not retrieve home var"
return
}

Because this way, you automatically get the usual:
FAIL: print home var (timeout)
or:
FAIL: print home var (eof)

which your version suppresses, followed by:
UNTESTED: could to retrieve home var

And in spirit of always having matching pass/fails, note
there's a pass call above.

Actually, you can probably just use get_valueof for this:

set home [get_valueof "" "home" "" "retrieve home var"]
if {$home == ""} {
untested "could not retrieve home var"
return
}
Post by Sergio Durigan Junior
+
+ if { [string length $home] > 0 } {
This check can then go away.
Post by Sergio Durigan Junior
+ gdb_test_multiple "print dir" "print dir var" {
+ -re "\\\$$decimal = \"\(.+\)\"\(, .*repeats.*\)?\r\n$gdb_prompt $" {
+ set curdir $expect_out(1,string)
+ }
+ -re "$gdb_prompt $" {
+ fail "failed to retrieve dir var"
+ return -1
+ }
+ default {
+ fail "failed to retrieve dir var"
+ return -1
+ }
+ }
And here you'd apply the same pattern.
Post by Sergio Durigan Junior
+
+ gdb_assert [string equal $curdir $home] \
+ "successfully chdir'd into home"
+ } else {
+ untested "could not determine value of HOME"
+ return
+ }
+ }
+}
+
+# The temporary directory that we will use to start the inferior.
+set tmpdir [standard_output_file ""]
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt tmpdir
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ default {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ }
Ditto. (This appears multiple times throughout.)
Post by Sergio Durigan Junior
+
+ # This test only makes sense if $tmpdir != $gdb_cwd_before_run
+ if { ![gdb_assert ![string equal $tmpdir $gdb_cwd_before_run] \
+ "make sure that tmpdir and GDB's cwd are different"] } {
+ return -1
+ }
+
+ gdb_test_no_output "set cwd $tmpdir" "set inferior cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain GDB cwd after run"
+ return -1
+ }
+ default {
+ fail "failed to obtain GDB cwd after run"
+ return -1
+ }
+ }
+
+ gdb_assert [string equal $gdb_cwd_before_run $gdb_cwd_after_run] \
+ "GDB cwd is unchanged after running inferior"
+ }
+}
+
+# Test that executing "set cwd" without arguments will reset the
+# inferior's cwd setting to its previous state.
+
+proc test_cwd_reset { } {
+ global decimal gdb_prompt tmpdir
+
+ with_test_prefix "test inferior cwd reset" {
+ gdb_test_multiple "pwd" "GDB cwd" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd $expect_out(1,string)
+ }
+ -re ".*$gdb_prompt $" {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ default {
+ fail "failed to obtain GDB cwd before run"
+ return -1
+ }
+ }
+
+ # This test only makes sense if $tmpdir != $gdb_cwd
+ # This test only makes sense if $tmpdir != $gdb_cwd
Duplicate comment. And missing period.
Post by Sergio Durigan Junior
+ if { ![gdb_assert ![string equal $tmpdir $gdb_cwd] \
+ "make sure that tmpdir and GDB's cwd are different"] } {
+ return -1
+ }
+
+ gdb_test_no_output "set cwd $tmpdir" "set inferior cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ # Reset the inferior's cwd.
+ gdb_test_no_output "set cwd" "resetting inferior cwd"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
Wrap each runto_main invocation in its own with_test_prefix,
so that if any fails we get unique test names in gdb.sum.
Post by Sergio Durigan Junior
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$gdb_cwd\", .*" \
+ "inferior cwd got reset correctly"
+ }
+}
+
+test_cd_into_dir
+clean_restart $binfile
+test_tilde_expansion
+clean_restart $binfile
+test_cwd_reset
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 3e1894410d..5144e9f7a6 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -66,6 +66,7 @@
#include "x86-nat.h"
#include "complaints.h"
#include "inf-child.h"
+#include "gdb_tilde_expand.h"
#define AdjustTokenPrivileges dyn_AdjustTokenPrivileges
#define DebugActiveProcessStop dyn_DebugActiveProcessStop
@@ -2432,6 +2433,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
cygwin_buf_t *toexec;
cygwin_buf_t *cygallargs;
cygwin_buf_t *args;
+ cygwin_buf_t *infcwd;
char **old_env = NULL;
PWCHAR w32_env;
size_t len;
@@ -2461,6 +2463,8 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
BOOL ret;
DWORD flags = 0;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ const char *inferior_cwd = get_inferior_cwd ();
+ std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);
Does gdb_tilde_expand work with NULL input ?
Post by Sergio Durigan Junior
if (!exec_file)
error (_("No executable specified, use `target exec'."));
@@ -2514,6 +2518,10 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
flags |= DEBUG_PROCESS;
}
+ if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, expanded_infcwd.c_str (),
+ infcwd, expanded_infcwd.size ()) < 0)
+ error (_("Error converting inferior cwd: %d"), errno);
I don't see how this can work. 'infcwd' was never initialized to
point at some buffer? It's garbage. I think you're supposed to
call this twice, once to determine the needed size, and then
another to fill in a buffer of that size.

Thanks,
Pedro Alves
Loading...