From: Pedro Alves <pedro@palves.net>
To: gdb-patches@sourceware.org
Subject: [PATCH] Windows: Normalize backward slashes to forward slashes
Date: Mon, 29 Jun 2026 22:24:30 +0100 [thread overview]
Message-ID: <20260629212430.340516-1-pedro@palves.net> (raw)
Currently, on Windows, GDB presents a mix of backward and forward
slashes to users, like e.g.:
...
attach 15044
Attaching to program: C:\msys2\home\alves\gdb\build-testsuite-cqe-vs\outputs\gdb.base\attach\attach.exe, process 15044
...
[Switching to thread 1 (Thread 15044.0x1294)]
main () at C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:19
19 while (! should_exit)
(gdb) FAIL: gdb.base/attach.exp: do_attach_failure_tests: first attach
...
Note how above, the "attach" command uses backslashes, and the source
path uses forward slashes.
Most annoyingly, depending on compiler, you can end up with mixed
slash styles in the same path:
Temporary breakpoint 1 at 0x1400010ec: file C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp, line 33.
^
A while ago, in commit a63213cd37 ("MSYS2+MinGW testing: Unix <->
Windows path conversion"), I had made the testsuite normalize
backslashes to forward slashes, among other things. I had said in the
commit log there:
"It's arguable whether GDB itself should do this sanitization. I
suspect it should. I personally dislike seeing backward slashes in
e.g., "info shared" output, or worse, mixed backward and forward
slashes. Still, I propose starting with a testsuite adjustment that
moves us forward, and handle that separately. I won't be surprised if
we need the new routine for some cases even if we adjust GDB."
After running into some other tests that would need backslash
adjustment, and also because this is something user-visible, not just
a testsuite issue, I decided to bite the bullet and make GDB itself do
the slashes normalization.
This patch fixes all the cases of backward slashes that I could find:
- source files and compilation directory
- executable name, and shared library names
- cd/pwd commands
It does this by normalizing slashes at some strategic places. The
conversion is only attempted if needed -- i.e., if debugging on
Windows, or cross-debugging Windows programs from a non-Windows host.
For executable/shared library names, this is doing the conversion
completely on the host side in common code, without touching the
target backend files in either GDB or GDBserver, by design, so that
this is all completely a client side decision, and works the same
against any Windows GDBserver version, against remote servers other
than ours (e.g., Wine's), so we can change it later if we want, etc.
I did not add an option to make this configurable at runtime on
purpose. I don't see the point, it'd just add more complication and
testing surface. Always normalizing keeps it simple.
For the source paths, I considered doing the normalization earlier in
the DWARF reader, but decided against it, because that would force
extra copying of strings -- the DWARF reader works mostly by passing
around const char pointers. Also, the places I picked in principle
will automatically handle PDB if/when we get to it.
The buildsym.c change takes care of compilation directory paths.
The allocate_symtab change takes care of source paths. That one
required a (temporary) copy, but I think that that's acceptable there.
The gdb_realpath change is needed because just before the touched code
there's a GetFullPathName call, which itself normalizes to backward
slashes.
The exec.c and solib.c changes take care of executable and shared
libraries.
The change to testsuite/lib/gdb.exp, to adjust to forward-slash style
for DOS full names, are necessary otherwise MI tests break. E.g.:
*stopped,reason="breakpoint-hit",disp="del",bkptno="1",frame={addr="0x00007ff780461508",
func="main",args=[],file="C:/rocgdb/src/gdb/testsuite/gdb.mi/basics.c",
fullname="C:/rocgdb/src/gdb/testsuite/gdb.mi/basics.c",line="64",arch="i386:x86-64"},
thread-id="1",stopped-threads="all"
FAIL: gdb.mi/gdb2549.exp: mi runto main (unknown output after running)
gdb.base/set-cwd.exp was the only test I found (so far at least) that
required adjustment, but note that without this patch that testcase
fails and throws TCL errors, like:
...
FAIL: gdb.base/set-cwd.exp: test_cwd_reset: inferior cwd is correctly set
ERROR: couldn't compile regular expression pattern: invalid escape \ sequence
...
It passes cleanly with the patch.
Below's the before / after comparison of different commands / output.
Before:
Reading symbols from ./outputs/gdb.rocm/simple/simple...
(gdb)
start
Temporary breakpoint 1 at 0x1400010ec: file C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp, line 33.
Starting program: C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple
Thread 1 hit Temporary breakpoint 1, main () at C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp:33
33 hipError_t error = hipMalloc (&result_ptr, sizeof (int));
Thread 1 hit Temporary breakpoint 1, main () at C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp:33
33 hipError_t error = hipMalloc (&result_ptr, sizeof (int));
(gdb)
(gdb) info inferiors
Num Description Connection Executable
* 1 process 15620 1 (native) C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x00007ffd22f91000 0x00007ffd231a69a8 Yes (*) C:\Windows\SYSTEM32\ntdll.dll
0x00007ffd21af1000 0x00007ffd21bb2520 Yes (*) C:\Windows\System32\kernel32.dll
0x00007ffd20091000 0x00007ffd20432548 Yes (*) C:\Windows\System32\KernelBase.dll
0x00007ffcc89c1000 0x00007ffcc9b145bc Yes (*) C:\Windows\SYSTEM32\amdhip64_7.dll
0x00007ffd22911000 0x00007ffd22d829b0 Yes (*) C:\Windows\System32\setupapi.dll
0x00007ffd216c1000 0x00007ffd217653f0 Yes (*) C:\Windows\System32\msvcrt.dll
0x00007ffd22431000 0x00007ffd224de5c8 Yes (*) C:\Windows\System32\advapi32.dll
0x00007ffd21a41000 0x00007ffd21ae52b8 Yes (*) C:\Windows\System32\sechost.dll
0x00007ffd20651000 0x00007ffd20676af0 Yes (*) C:\Windows\System32\bcrypt.dll
0x00007ffd21f31000 0x00007ffd22045860 Yes (*) C:\Windows\System32\rpcrt4.dll
0x00007ffd22d91000 0x00007ffd22f40e50 Yes (*) C:\Windows\System32\user32.dll
0x00007ffd20781000 0x00007ffd207a43d8 Yes (*) C:\Windows\System32\win32u.dll
0x00007ffd228d1000 0x00007ffd228f73d8 Yes (*) C:\Windows\System32\gdi32.dll
0x00007ffd207b1000 0x00007ffd208d09c8 Yes (*) C:\Windows\System32\gdi32full.dll
0x00007ffd20b91000 0x00007ffd20c28410 Yes (*) C:\Windows\System32\msvcp_win.dll
0x00007ffd20471000 0x00007ffd2057f410 Yes (*) C:\Windows\System32\ucrtbase.dll
0x00007ffd21541000 0x00007ffd215afbc8 Yes (*) C:\Windows\System32\ws2_32.dll
0x00007ffd223f1000 0x00007ffd2241fc40 Yes (*) C:\Windows\System32\imm32.dll
(gdb) info source
Current source file is C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp
Compilation directory is C:\msys2\home\alves\gdb\build-testsuite
Located in C:\rocgdb\src\gdb\testsuite\gdb.rocm\simple.cpp
(gdb) info sources
C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple:
C:\rocgdb\src\gdb\testsuite\gdb.rocm\simple.cpp, C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\corecrt_stdio_config.h,
C:\Program Files\AMD\ROCm\7.1\include\hip\hip_runtime_api.h, C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\stdint.h,
C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\stdio.h, C:\Program Files\AMD\ROCm\7.1\lib\clang\21\include\__stddef_nullptr_t.h,
C:\Program Files\AMD\ROCm\7.1\lib\clang\21\include\__stddef_size_t.h, C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\cstdlib,
C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\stdlib.h, C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\corecrt_search.h,
C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\corecrt_malloc.h,
...
(gdb) detach
Detaching from program: C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple, process 20800
[Inferior 1 (process 20800) detached]
(gdb) cd /tmp
Working directory C:\tmp.
(gdb) pwd
Working directory C:\tmp.
After:
Reading symbols from ./outputs/gdb.rocm/simple/simple...
(gdb) start
Temporary breakpoint 1 at 0x1400010ec: file C:/rocgdb/src/gdb/testsuite/gdb.rocm/simple.cpp, line 33.
Starting program: C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple
Thread 1 hit Temporary breakpoint 1, main () at C:/rocgdb/src/gdb/testsuite/gdb.rocm/simple.cpp:33
33 hipError_t error = hipMalloc (&result_ptr, sizeof (int));
(gdb) info sources
C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple:
C:/rocgdb/src/gdb/testsuite/gdb.rocm/simple.cpp, C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/corecrt_stdio_config.h,
C:/Program Files/AMD/ROCm/7.1/include/hip/hip_runtime_api.h, C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/include/stdint.h,
C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/stdio.h, C:/Program Files/AMD/ROCm/7.1/lib/clang/21/include/__stddef_nullptr_t.h,
C:/Program Files/AMD/ROCm/7.1/lib/clang/21/include/__stddef_size_t.h, C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/include/cstdlib,
C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/stdlib.h, C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/corecrt_search.h,
C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/corecrt_malloc.h,
...
(gdb) info inferiors
Num Description Connection Executable
* 1 process 19920 1 (native) C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple
(gdb) info shared
From To Syms Read Shared Object Library
0x00007ffd22f91000 0x00007ffd231a69a8 Yes (*) C:/Windows/SYSTEM32/ntdll.dll
0x00007ffd21af1000 0x00007ffd21bb2520 Yes (*) C:/Windows/System32/kernel32.dll
0x00007ffd20091000 0x00007ffd20432548 Yes (*) C:/Windows/System32/KernelBase.dll
0x00007ffcc89c1000 0x00007ffcc9b145bc Yes (*) C:/Windows/SYSTEM32/amdhip64_7.dll
0x00007ffd22911000 0x00007ffd22d829b0 Yes (*) C:/Windows/System32/setupapi.dll
0x00007ffd216c1000 0x00007ffd217653f0 Yes (*) C:/Windows/System32/msvcrt.dll
0x00007ffd22431000 0x00007ffd224de5c8 Yes (*) C:/Windows/System32/advapi32.dll
0x00007ffd21a41000 0x00007ffd21ae52b8 Yes (*) C:/Windows/System32/sechost.dll
0x00007ffd20651000 0x00007ffd20676af0 Yes (*) C:/Windows/System32/bcrypt.dll
0x00007ffd21f31000 0x00007ffd22045860 Yes (*) C:/Windows/System32/rpcrt4.dll
0x00007ffd22d91000 0x00007ffd22f40e50 Yes (*) C:/Windows/System32/user32.dll
0x00007ffd20781000 0x00007ffd207a43d8 Yes (*) C:/Windows/System32/win32u.dll
0x00007ffd228d1000 0x00007ffd228f73d8 Yes (*) C:/Windows/System32/gdi32.dll
0x00007ffd207b1000 0x00007ffd208d09c8 Yes (*) C:/Windows/System32/gdi32full.dll
0x00007ffd20b91000 0x00007ffd20c28410 Yes (*) C:/Windows/System32/msvcp_win.dll
0x00007ffd20471000 0x00007ffd2057f410 Yes (*) C:/Windows/System32/ucrtbase.dll
0x00007ffd21541000 0x00007ffd215afbc8 Yes (*) C:/Windows/System32/ws2_32.dll
0x00007ffd223f1000 0x00007ffd2241fc40 Yes (*) C:/Windows/System32/imm32.dll
(*): Shared library is missing debugging information.
(gdb) detach
Detaching from program: C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple, process 7816
[Inferior 1 (process 7816) detached]
(gdb) cd /tmp
Working directory C:/tmp.
(gdb) pwd
Working directory C:/tmp.
Change-Id: I6366c41d200938259330e60bc1e98b576f787518
---
gdb/NEWS | 15 +++++++++++
gdb/buildsym.c | 5 ++++
gdb/cli/cli-cmds.c | 5 ++--
gdb/exec.c | 5 ++++
gdb/filesystem.c | 42 +++++++++++++++++++++++++++++
gdb/filesystem.h | 43 ++++++++++++++++++++++++++++++
gdb/go32-nat.c | 5 ++--
gdb/main.c | 3 ++-
gdb/mi/mi-cmd-env.c | 3 ++-
gdb/solib.c | 17 ++++++++++++
gdb/solib.h | 7 +----
gdb/symfile.c | 4 +++
gdb/testsuite/gdb.base/set-cwd.exp | 32 +++++++++++++++++-----
gdb/testsuite/lib/gdb.exp | 27 +++++++------------
gdbsupport/pathstuff.cc | 16 +++++++++--
gdbsupport/pathstuff.h | 5 ++++
16 files changed, 196 insertions(+), 38 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index d5214a98a57..aec31c95e7a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -83,6 +83,21 @@
* Support for native Thread Local Storage (TLS) variables on Windows.
+* GDB now normalizes backslashes to forward slashes on Windows.
+
+ E.g., depending on compiler and build system used by your project,
+ previously GDB could show a mix of slash styles, like for example:
+
+ C:/proj/src\simple.cpp
+
+ GDB will now consistently show forward slashes:
+
+ C:/proj/src/simple.cpp
+
+ This affects everywhere GDB shows a filename/dirname: source
+ filenames, executable filename, shared libraries, the cd/pwd
+ commands, etc.
+
* GDB now supports libipt v2.2 events originating from Event Tracing (set
record btrace pt event-tracing on) on a FRED-enabled system and from
Trigger Tracing.
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 94bc5a24edb..b543cd10eb5 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -18,6 +18,8 @@
#include "buildsym.h"
#include "gdbsupport/gdb_obstack.h"
+#include "gdbsupport/pathstuff.h"
+#include "filesystem.h"
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
@@ -53,6 +55,9 @@ buildsym_compunit::buildsym_compunit (struct objfile *objfile_,
m_language (language_),
m_last_source_start_addr (last_addr)
{
+ if (should_normalize_slashes ())
+ normalize_slashes (&m_comp_dir[0]);
+
/* Build the subfile for NAME (the main source file) so that we can record
a pointer to it for later.
IMPORTANT: Do not allocate a struct symtab for NAME here.
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index f5c85dfc352..5348d156d06 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -30,6 +30,7 @@
#include "value.h"
#include "language.h"
#include "filenames.h"
+#include "filesystem.h"
#include "objfiles.h"
#include "source.h"
#include "disasm.h"
@@ -494,7 +495,7 @@ pwd_command (const char *args, int from_tty)
styled_string (command_style.style (), "pwd"),
args);
- gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ gdb::unique_xmalloc_ptr<char> cwd (gdb_getcwd (NULL, 0));
if (cwd == NULL)
error (_("Error finding name of working directory: %s"),
@@ -534,7 +535,7 @@ cd_command (const 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. */
- gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ gdb::unique_xmalloc_ptr<char> cwd (gdb_getcwd (NULL, 0));
dir = cwd.get ();
#endif
diff --git a/gdb/exec.c b/gdb/exec.c
index 36ec45c14bc..f4c82519449 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -37,6 +37,7 @@
#include "gcore.h"
#include "source.h"
#include "build-id.h"
+#include "filesystem.h"
#include <fcntl.h>
#include "gdbcore.h"
@@ -230,6 +231,8 @@ validate_exec_file (int from_tty)
if (pid_exec_file == nullptr)
return;
+ scoped_normalized_path path_storage (&pid_exec_file);
+
/* In case current_exec_file was changed, reopen_exec_file ensures an up
to date build_id (will do nothing if the file timestamp did not
change). If exec file changed, reopen_exec_file has allocated another
@@ -334,6 +337,8 @@ exec_file_locate_attach (int pid, int defer_bp_reset, int from_tty)
return;
}
+ scoped_normalized_path path_storage (&exec_file_target);
+
gdb::unique_xmalloc_ptr<char> exec_file_host
= exec_file_find (exec_file_target);
if (exec_file_host == nullptr)
diff --git a/gdb/filesystem.c b/gdb/filesystem.c
index 1046e827ae9..82bd664c4b3 100644
--- a/gdb/filesystem.c
+++ b/gdb/filesystem.c
@@ -18,10 +18,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "filesystem.h"
+#include "filenames.h"
#include "gdbarch.h"
#include "cli/cli-cmds.h"
#include "inferior.h"
+/* Same as HAVE_DOS_BASED_FILE_SYSTEM, but usable as an rvalue. */
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+# define DOS_BASED_FILE_SYSTEM 1
+#else
+# define DOS_BASED_FILE_SYSTEM 0
+#endif
+
const char file_system_kind_auto[] = "auto";
const char file_system_kind_unix[] = "unix";
const char file_system_kind_dos_based[] = "dos-based";
@@ -57,6 +65,40 @@ target_lbasename (const char *kind, const char *name)
return unix_lbasename (name);
}
+/* See filesystem.h. */
+
+bool
+should_normalize_slashes ()
+{
+ if (DOS_BASED_FILE_SYSTEM)
+ return true;
+ else
+ {
+ const char *fskind = effective_target_file_system_kind ();
+ return fskind == file_system_kind_dos_based;
+ }
+}
+
+/* See filesystem.h. */
+
+char *
+gdb_getcwd (char *buf, size_t size)
+{
+ char *cwd = getcwd (buf, size);
+
+ /* Note this is returning a host path, so we only check
+ DOS_BASED_FILE_SYSTEM without considering the target filesystem
+ kind. */
+ if (cwd != nullptr && DOS_BASED_FILE_SYSTEM)
+ {
+ /* If CWD is non-NULL, then it's always a NULL-terminated
+ string. */
+ normalize_slashes (cwd);
+ }
+
+ return cwd;
+}
+
static void
show_target_file_system_kind_command (struct ui_file *file,
int from_tty,
diff --git a/gdb/filesystem.h b/gdb/filesystem.h
index 49f8e791ec4..d48d2508c70 100644
--- a/gdb/filesystem.h
+++ b/gdb/filesystem.h
@@ -19,6 +19,8 @@
#ifndef GDB_FILESYSTEM_H
#define GDB_FILESYSTEM_H
+#include "gdbsupport/pathstuff.h"
+
extern const char file_system_kind_auto[];
extern const char file_system_kind_unix[];
extern const char file_system_kind_dos_based[];
@@ -55,4 +57,45 @@ extern const char *target_lbasename (const char *kind, const char *name);
result from this function. */
extern const char *effective_target_file_system_kind (void);
+/* Return true if GDB should normalize backslashes to forward slashes.
+ This is true if GDB is running on a system with a DOS-based
+ filesystem (e.g., Windows), or, if cross debugging and the target
+ itself has a DOS-based filesystem (e.g., remote debugging Windows
+ GDBserver from Linux). */
+extern bool should_normalize_slashes ();
+
+/* Normalizes backslashes to forward slashes in a path string if
+ necessary, extending the lifetime of the normalized copy for the
+ duration of the object's scope.
+
+ The constructor takes a pointer-to-pointer and updates *PATH to
+ point at the normalized string when normalization is needed, so
+ callers need only:
+
+ scoped_normalized_path path_storage (&path);
+
+ and then use PATH directly without a separate reassignment. */
+struct scoped_normalized_path
+{
+ explicit scoped_normalized_path (const char **path)
+ {
+ gdb_assert (path != nullptr);
+
+ if (should_normalize_slashes ())
+ {
+ m_normalized = *path;
+ normalize_slashes (&m_normalized[0]);
+ *path = m_normalized.c_str ();
+ }
+ }
+
+private:
+ /* The normalized version of PATH if normalization was necessary,
+ empty otherwise. */
+ std::string m_normalized;
+};
+
+/* Like getcwd but normalizes slashes if needed. */
+extern char *gdb_getcwd (char *buf, size_t size);
+
#endif /* GDB_FILESYSTEM_H */
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index b3ea5c1fd5c..fdfa6cd4209 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -101,6 +101,7 @@
#include "top.h"
#include "cli/cli-utils.h"
#include "inf-child.h"
+#include "filesystem.h"
#include <unistd.h>
#include <sys/utsname.h>
@@ -478,7 +479,7 @@ go32_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
set with the gdb-command "cd ..." */
if (!*child_cwd)
/* Initialize child's cwd with the current one. */
- getcwd (child_cwd, sizeof (child_cwd));
+ gdb_getcwd (child_cwd, sizeof (child_cwd));
chdir (child_cwd);
@@ -501,7 +502,7 @@ go32_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
a_tss.tss_eflags |= 0x0100;
}
- getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
+ gdb_getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
if (current_directory != NULL)
chdir (current_directory);
diff --git a/gdb/main.c b/gdb/main.c
index 7272862a3f8..4a11b6c5f88 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -61,6 +61,7 @@
#include "bt-utils.h"
#include "terminal.h"
#include "logging-file.h"
+#include "filesystem.h"
/* The selected interpreter. */
std::string interpreter_p;
@@ -717,7 +718,7 @@ captured_main_1 (struct captured_main_args *context)
= xstrprintf ("%s: ", gdb_program_name);
warning_pre_print = tmp_warn_preprint.get ();
- current_directory = getcwd (NULL, 0);
+ current_directory = gdb_getcwd (NULL, 0);
if (current_directory == NULL)
perror_warning_with_name (_("error finding working directory"));
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
index 8fb952f8ee1..c2188d1f540 100644
--- a/gdb/mi/mi-cmd-env.c
+++ b/gdb/mi/mi-cmd-env.c
@@ -29,6 +29,7 @@
#include "top.h"
#include <sys/stat.h>
#include "source.h"
+#include "filesystem.h"
static const char path_var_name[] = "PATH";
static char *orig_path = NULL;
@@ -62,7 +63,7 @@ mi_cmd_env_pwd (const char *command, const char *const *argv, int argc)
if (argc > 0)
error (_("-environment-pwd: No arguments allowed"));
- gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+ gdb::unique_xmalloc_ptr<char> cwd (gdb_getcwd (NULL, 0));
if (cwd == NULL)
error (_("-environment-pwd: error finding name of working directory: %s"),
safe_strerror (errno));
diff --git a/gdb/solib.c b/gdb/solib.c
index d92d0dd9a3d..869b769d043 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -44,6 +44,7 @@
#include "gdb_bfd.h"
#include "gdbsupport/filestuff.h"
#include "gdbsupport/scoped_fd.h"
+#include "gdbsupport/pathstuff.h"
#include "source.h"
#include "cli/cli-style.h"
@@ -570,6 +571,22 @@ solib_map_sections (solib &so)
/* See solib.h. */
+solib::solib (lm_info_up lm_info, std::string original_name_,
+ std::string name_, const solib_ops &ops)
+ : lm_info (std::move (lm_info)),
+ original_name (std::move (original_name_)),
+ name (std::move (name_)),
+ m_ops (&ops)
+{
+ if (should_normalize_slashes ())
+ {
+ normalize_slashes (&name[0]);
+ normalize_slashes (&original_name[0]);
+ }
+}
+
+/* See solib.h. */
+
void
solib::clear ()
{
diff --git a/gdb/solib.h b/gdb/solib.h
index 9e6c3f7346e..662d467b0cc 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -62,12 +62,7 @@ struct solib : intrusive_list_node<solib>
OPS is the solib_ops implementation providing this solib. */
explicit solib (lm_info_up lm_info, std::string original_name,
- std::string name, const solib_ops &ops)
- : lm_info (std::move (lm_info)),
- original_name (std::move (original_name)),
- name (std::move (name)),
- m_ops (&ops)
- {}
+ std::string name, const solib_ops &ops);
/* Return the solib_ops implementation providing this solib. */
const solib_ops &ops () const
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 296795bda80..0357f124794 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -53,6 +53,7 @@
#include "cli/cli-style.h"
#include "gdbsupport/forward-scope-exit.h"
#include "gdbsupport/buildargv.h"
+#include "filesystem.h"
#include <sys/types.h>
#include <fcntl.h>
@@ -2809,6 +2810,9 @@ allocate_symtab (struct compunit_symtab *cust, const char *filename,
const char *filename_for_id)
{
struct objfile *objfile = cust->objfile ();
+
+ scoped_normalized_path path_storage (&filename);
+
struct symtab *symtab
= obstack_new<struct symtab> (&objfile->objfile_obstack,
*cust,
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index 279004596a1..aae557ece27 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -72,6 +72,29 @@ proc_with_prefix test_tilde_expansion { } {
# The temporary directory that we will use to start the inferior.
set tmpdir [standard_output_file ""]
+# Check that the 'dir' variable in the inferior is set to
+# EXPECTED_DIR. Use MESSAGE as test message.
+
+proc test_dir {expected_dir message} {
+ set dir "UNSET"
+ gdb_test_multiple "print dir" "$message: extract dir" {
+ -re -wrap " = \"(.*)\", .*" {
+ set dir $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+
+ if {[istarget "*-*-mingw*"]} {
+ # getcwd on native Windows uses backslashes. Convert to
+ # forward slashes. We look for pairs of backslashes as DIR
+ # comes from a C string printed by GDB, which escapes
+ # backslashes.
+ set dir [string map {\\\\ /} $dir]
+ }
+
+ gdb_assert [string equal $expected_dir $dir] $message
+}
+
# Test that when we "set cwd" the inferior will be started under the
# correct working directory and GDB will not be affected by this.
@@ -107,8 +130,7 @@ proc_with_prefix test_cd_into_dir { } {
gdb_breakpoint [gdb_get_line_number "break-here"]
gdb_continue_to_breakpoint "break-here" ".* break-here .*"
- gdb_test "print dir" "${::valnum_re} = \"$tmpdir\", .*" \
- "inferior cwd is correctly set"
+ test_dir $tmpdir "inferior cwd is correctly set"
set gdb_cwd_after_run ""
set test "pwd after run"
@@ -164,8 +186,7 @@ proc_with_prefix test_cwd_reset { } {
gdb_breakpoint [gdb_get_line_number "break-here"]
gdb_continue_to_breakpoint "break-here" ".* break-here .*"
- gdb_test "print dir" "${::valnum_re} = \"$tmpdir\", .*" \
- "inferior cwd is correctly set"
+ test_dir $tmpdir "inferior cwd is correctly set"
# Reset the inferior's cwd.
gdb_test_no_output "set cwd" "resetting inferior cwd"
@@ -178,8 +199,7 @@ proc_with_prefix test_cwd_reset { } {
gdb_breakpoint [gdb_get_line_number "break-here"]
gdb_continue_to_breakpoint "break-here" ".* break-here .*"
- gdb_test "print dir" "${::valnum_re} = \"$gdb_cwd\", .*" \
- "inferior cwd got reset correctly"
+ test_dir $gdb_cwd "inferior cwd got reset correctly"
}
}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index d8619ded236..a19e8ba6729 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -342,15 +342,15 @@ set pagination_prompt [string_to_regexp $pagination_prompt_str]
# absolute path ie. "/foo/".
set fullname_syntax_POSIX {/[^\n]*/}
# The variable fullname_syntax_UNC is a regexp which matches a Windows
-# UNC path ie. "\\D\foo\".
-set fullname_syntax_UNC {\\\\[^\\]+\\[^\n]+\\}
+# UNC path ie. "//D/foo/".
+set fullname_syntax_UNC {//[^/]+/[^\n]+/}
# The variable fullname_syntax_DOS_CASE is a regexp which matches a
# particular DOS case that GDB most likely will output
-# ie. "\foo\", but don't match "\\.*\".
-set fullname_syntax_DOS_CASE {\\[^\\][^\n]*\\}
+# ie. "/foo/", but don't match "//.*/".
+set fullname_syntax_DOS_CASE {/[^/][^\n]*/}
# The variable fullname_syntax_DOS is a regexp which matches a DOS path
-# ie. "a:\foo\" && "a:foo\".
-set fullname_syntax_DOS {[a-zA-Z]:[^\n]*\\}
+# ie. "a:/foo/" && "a:foo/".
+set fullname_syntax_DOS {[a-zA-Z]:[^\n]*/}
# The variable fullname_syntax is a regexp which matches what GDB considers
# an absolute path. It is currently debatable if the Windows style paths
# "d:foo" and "\abc" should be considered valid as an absolute path.
@@ -2321,22 +2321,13 @@ gdb_caching_proc get_mount_point_map {} {
return [list $sorted_win $sorted_unix]
}
-# Normalize backward slashes to forward slashes.
-
-proc normalize_slashes {filename} {
- return [string map {\\ /} $filename]
-}
-
# Sanitize a host file name, without making it absolute or resolving
-# symlinks. On native Windows, this normalizes slashes to forward
-# slashes, and makes sure that if the file name starts with a drive
-# letter, it is upper case. On other systems, it just returns the
-# file name unmodified.
+# symlinks. On native Windows, this makes sure that if the file name
+# starts with a drive letter, it is upper case. On other systems, it
+# just returns the file name unmodified.
proc host_file_sanitize {filename} {
if {[ishost *-*-mingw*]} {
- set filename [normalize_slashes $filename]
-
# If the file name starts with a drive letter, uppercase it.
if {[regexp {^([a-zA-Z]):(/.*)?} $filename -> drive rest]} {
set filename "[string toupper $drive]:$rest"
diff --git a/gdbsupport/pathstuff.cc b/gdbsupport/pathstuff.cc
index e3faaaed9ee..d301c6fe5c2 100644
--- a/gdbsupport/pathstuff.cc
+++ b/gdbsupport/pathstuff.cc
@@ -32,6 +32,17 @@ char *current_directory;
/* See gdbsupport/pathstuff.h. */
+char *
+normalize_slashes (char *path)
+{
+ for (char *p = path; *p != '\0'; ++p)
+ if (*p == '\\')
+ *p = '/';
+ return path;
+}
+
+/* See gdbsupport/pathstuff.h. */
+
gdb::unique_xmalloc_ptr<char>
gdb_realpath (const char *filename)
{
@@ -56,7 +67,8 @@ gdb_realpath (const char *filename)
Since the simplification would be useful even if the path is not
valid (one can always set a breakpoint on a file, even if the file
does not exist locally), we rely instead on GetFullPathName to
- perform the canonicalization. */
+ perform the canonicalization. And then, we normalize backslashes
+ to forward slashes. */
#if defined (_WIN32)
{
@@ -68,7 +80,7 @@ gdb_realpath (const char *filename)
we might not be able to display the original casing in a given
path. */
if (len > 0 && len < MAX_PATH)
- return make_unique_xstrdup (buf);
+ return make_unique_xstrdup (normalize_slashes (buf));
}
#else
{
diff --git a/gdbsupport/pathstuff.h b/gdbsupport/pathstuff.h
index e84c3eacfae..819a4bda527 100644
--- a/gdbsupport/pathstuff.h
+++ b/gdbsupport/pathstuff.h
@@ -33,6 +33,11 @@
/* String containing the current directory (what getwd would return). */
extern char *current_directory;
+/* Normalize backslashes to forward slashes in the null-terminated
+ PATH string. Returns PATH. */
+
+extern char *normalize_slashes (char *path);
+
/* Return the real path of FILENAME, expanding all the symbolic links.
Contrary to "gdb_abspath", this function does not use
base-commit: 18ca02157d9cc245f035452e397a07a3787034d0
--
2.54.0
next reply other threads:[~2026-06-29 21:25 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 21:24 Pedro Alves [this message]
2026-06-30 11:26 ` Eli Zaretskii
2026-06-30 14:47 ` Pedro Alves
2026-06-30 15:11 ` Eli Zaretskii
2026-07-01 11:28 ` [PATCH v2] " Pedro Alves
2026-07-01 12:07 ` Eli Zaretskii
2026-07-01 19:28 ` Pedro Alves
2026-07-02 5:28 ` Eli Zaretskii
2026-07-06 12:07 ` Andrew Burgess
2026-07-06 22:35 ` Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260629212430.340516-1-pedro@palves.net \
--to=pedro@palves.net \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox