* [PATCH] Windows: Normalize backward slashes to forward slashes
@ 2026-06-29 21:24 Pedro Alves
2026-06-30 11:26 ` Eli Zaretskii
0 siblings, 1 reply; 10+ messages in thread
From: Pedro Alves @ 2026-06-29 21:24 UTC (permalink / raw)
To: gdb-patches
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
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Windows: Normalize backward slashes to forward slashes
2026-06-29 21:24 [PATCH] Windows: Normalize backward slashes to forward slashes Pedro Alves
@ 2026-06-30 11:26 ` Eli Zaretskii
2026-06-30 14:47 ` Pedro Alves
0 siblings, 1 reply; 10+ messages in thread
From: Eli Zaretskii @ 2026-06-30 11:26 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> From: Pedro Alves <pedro@palves.net>
> Date: Mon, 29 Jun 2026 22:24:30 +0100
>
> Starting program: C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple
Are forward slashes only shown to the user, or does the code pas the
file name with forward slashes to CreateProcess? (I'm not familiar
with thecode enough to determine which one myself, sorry.) If we pass
forward slashes to CreateProcess, it could cause problems, IME; it is
much safer to use backslashes there.
Thanks.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Windows: Normalize backward slashes to forward slashes
2026-06-30 11:26 ` Eli Zaretskii
@ 2026-06-30 14:47 ` Pedro Alves
2026-06-30 15:11 ` Eli Zaretskii
0 siblings, 1 reply; 10+ messages in thread
From: Pedro Alves @ 2026-06-30 14:47 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On 2026-06-30 12:26, Eli Zaretskii wrote:
>> From: Pedro Alves <pedro@palves.net>
>> Date: Mon, 29 Jun 2026 22:24:30 +0100
>>
>> Starting program: C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple
>
> Are forward slashes only shown to the user, or does the code pas the
> file name with forward slashes to CreateProcess? (I'm not familiar
> with thecode enough to determine which one myself, sorry.) If we pass
> forward slashes to CreateProcess, it could cause problems, IME; it is
> much safer to use backslashes there.
We now pass forward slashes down to CreateProcess. It just works on my Windows 11 machine, though. I forgot to
mention, but I (painfully) ran the whole testsuite before and after this patch (that's how I discovered the need
to tweak the gdb.base/set-cwd.exp testcase).
Searching online, I found this:
https://stackoverflow.com/questions/5652834/c-createprocess-wont-work-with-app-and-args-with-forward-slash-worked
... where someone said:
"CreateProcess does work with forward-slashes on Windows 7. I'm guessing this is a version-specific feature (or bug)."
And here:
https://www.reddit.com/r/programmingmemes/comments/1k8ctk2/comment/mp8lvsr/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
Someone said:
"At least since Windows 2000, probably since always."
I asked an LLM, and got this:
"That normalization is original to NT -- Windows NT 3.1 (1993). The kernel's RtlDosPathNameToNtPathName has always treated / as an alternate separator. CreateProcess
itself never "added" the feature -- it just calls through to the kernel, which handles it transparently."
So I wonder whether what you're recalling is something from the Windows 9x days, which we no longer support (we support WinXP and up). Do you happen to recall?
If it's really a problem on supported Windows versions, it should be a matter of converting back to forward slashes before we
call CreateProcess. We already do that in gdb/windows-nat.c:windows_nat_target::create_inferior, for "set cwd":
/* Mirror slashes on inferior's cwd. */
std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
'/', '\\');
we'd just need to do the same for exec_file.
Pedro Alves
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Windows: Normalize backward slashes to forward slashes
2026-06-30 14:47 ` Pedro Alves
@ 2026-06-30 15:11 ` Eli Zaretskii
2026-07-01 11:28 ` [PATCH v2] " Pedro Alves
0 siblings, 1 reply; 10+ messages in thread
From: Eli Zaretskii @ 2026-06-30 15:11 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> Date: Tue, 30 Jun 2026 15:47:54 +0100
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <pedro@palves.net>
>
> On 2026-06-30 12:26, Eli Zaretskii wrote:
> >> From: Pedro Alves <pedro@palves.net>
> >> Date: Mon, 29 Jun 2026 22:24:30 +0100
> >>
> >> Starting program: C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple
> >
> > Are forward slashes only shown to the user, or does the code pas the
> > file name with forward slashes to CreateProcess? (I'm not familiar
> > with thecode enough to determine which one myself, sorry.) If we pass
> > forward slashes to CreateProcess, it could cause problems, IME; it is
> > much safer to use backslashes there.
>
> We now pass forward slashes down to CreateProcess. It just works on my Windows 11 machine, though. I forgot to
> mention, but I (painfully) ran the whole testsuite before and after this patch (that's how I discovered the need
> to tweak the gdb.base/set-cwd.exp testcase).
>
> Searching online, I found this:
>
> https://stackoverflow.com/questions/5652834/c-createprocess-wont-work-with-app-and-args-with-forward-slash-worked
>
> ... where someone said:
>
> "CreateProcess does work with forward-slashes on Windows 7. I'm guessing this is a version-specific feature (or bug)."
>
> And here:
>
> https://www.reddit.com/r/programmingmemes/comments/1k8ctk2/comment/mp8lvsr/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
>
> Someone said:
>
> "At least since Windows 2000, probably since always."
>
> I asked an LLM, and got this:
>
> "That normalization is original to NT -- Windows NT 3.1 (1993). The kernel's RtlDosPathNameToNtPathName has always treated / as an alternate separator. CreateProcess
> itself never "added" the feature -- it just calls through to the kernel, which handles it transparently."
>
> So I wonder whether what you're recalling is something from the Windows 9x days, which we no longer support (we support WinXP and up). Do you happen to recall?
No, I don't. But I stopped using Windows 9X a very long time ago, and
my main development machine ran XP until two years ago. So if I had
to guess, I'd guess it was on XP.
The articles you cite are correct in that the low-level Windows APIs
which accept file names treat the forward slash as a directory
separator. But CreateProcess has some application-level logic of
itself: it accepts a complete command line as a single string, not as
argv[]-style array, and decides by itself which part of that command
line is the executable and which the rest of the command line. It is
this part that I'm afraid of: it could treat the two slash variants
differently. That happens before the command line gets to the
low-level APIs which accept file names.
> If it's really a problem on supported Windows versions, it should be a matter of converting back to forward slashes before we
> call CreateProcess. We already do that in gdb/windows-nat.c:windows_nat_target::create_inferior, for "set cwd":
>
> /* Mirror slashes on inferior's cwd. */
> std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
> '/', '\\');
>
> we'd just need to do the same for exec_file.
Yes, I think it's safer to convert to all backslashes in the argument
we pass to CreateProcess. And it will not show outside of that place,
so the (very positive and welcome) effects of your changes will not be
affected.
Thanks.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2] Windows: Normalize backward slashes to forward slashes
2026-06-30 15:11 ` Eli Zaretskii
@ 2026-07-01 11:28 ` Pedro Alves
2026-07-01 12:07 ` Eli Zaretskii
2026-07-06 12:07 ` Andrew Burgess
0 siblings, 2 replies; 10+ messages in thread
From: Pedro Alves @ 2026-07-01 11:28 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
Hi,
On 2026-06-30 16:11, Eli Zaretskii wrote:
>> Date: Tue, 30 Jun 2026 15:47:54 +0100
>> From: Pedro Alves <pedro@palves.net>
>> So I wonder whether what you're recalling is something from the Windows 9x days, which we no longer support (we support WinXP and up). Do you happen to recall?
>
> No, I don't. But I stopped using Windows 9X a very long time ago, and
> my main development machine ran XP until two years ago. So if I had
> to guess, I'd guess it was on XP.
>
> The articles you cite are correct in that the low-level Windows APIs
> which accept file names treat the forward slash as a directory
> separator. But CreateProcess has some application-level logic of
> itself: it accepts a complete command line as a single string, not as
> argv[]-style array, and decides by itself which part of that command
> line is the executable and which the rest of the command line. It is
> this part that I'm afraid of: it could treat the two slash variants
> differently. That happens before the command line gets to the
> low-level APIs which accept file names.
Ah, OK. I dug into this a bit more. GDB does call CreateProcess with a
NULL lpApplicationName, which makes CreateProcess parse the command line
itself to find the executable to launch. But, that parse splits on
whitespace, while honoring double-quotes -- and we already quote the
executable:
xsnprintf (args, args_len, ""%s" %s", toexec, allargs_copy);
So I believe the executable filename is unambiguous regardless of slash
direction, and the file APIs CreateProcess then uses accept forward
slashes fine.
GDBserver OTOH, passes the image to run via lpApplicationName, which
completely bypasses such parsing, so it should be good there too.
Still, I think the conversion is worth doing. What the slash direction does
for sure affect is the argv[0] the inferior sees. The command line we hand
CreateProcess is also what the child's CRT splits into argv, so without converting,
the inferior sees forward slashes in its own program name. Giving the inferior
native separators in argv[0] seems like enough reason to convert -- i.e., not
framing it about what CreateProcess parses, but what the inferior itself sees
and parses.
I've made gdb and gdbserver do that, and added a comment about this. In gdb/windows-nat.c:
/* Convert the executable path to backslash separators, so the
inferior observes native backslashes in its own program name. */
std::string toexec_native = exec_file;
std::replace (toexec_native.begin (), toexec_native.end (), '/', '\\');
toexec = toexec_native.c_str ();
and in gdbserver/win32-low.cc:
/* Convert the executable path to backslash separators, so the
inferior observes native backslashes in its own program name. */
std::string program_native = program;
std::replace (program_native.begin (), program_native.end (), '/', '\\');
program = program_native.c_str ();
(Note: these are both on !Cygwin paths, as the Cygwin paths already do the path
conversion via cygwin_conv_path. And BTW, Cygwin GDB already presented forward
slashes to users already everywhere, including in "info shared", etc.)
Having this reason written down also avoids having to try to come up with some
speculative comment about some old Windows behavior we're not exactly sure what it was.
>
>> If it's really a problem on supported Windows versions, it should be a matter of converting back to forward slashes before we
>> call CreateProcess. We already do that in gdb/windows-nat.c:windows_nat_target::create_inferior, for "set cwd":
>>
>> /* Mirror slashes on inferior's cwd. */
>> std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
>> '/', '\\');
>>
>> we'd just need to do the same for exec_file.
>
> Yes, I think it's safer to convert to all backslashes in the argument
> we pass to CreateProcess. And it will not show outside of that place,
> so the (very positive and welcome) effects of your changes will not be
> affected.
>
Here's the updated patch. Other than the tweaks mentioned above, and an updated
commit log, nothing else changed.
Let me know what you think.
From dc15b7c75728bbef1d6a844997a0f654d1431220 Mon Sep 17 00:00:00 2001
From: Pedro Alves <pedro@palves.net>
Date: Fri, 12 Dec 2025 12:12:30 +0000
Subject: [PATCH] Windows: Normalize backslashes to forward slashes
Currently, on native Windows, GDB presents a mix of backslashes and
forward slashes to users, like e.g.:
...
attach 15044
Attaching to program: C:\msys2\home\alves\gdb\build-testsuite\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 backslashes 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 backslash ->
forward slash 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 tweak the gdb and gdbserver backends for the other way around
(forward slash => backslash), to make sure that they pass backslashes
to CreateProcess, so that inferiors see native backslashes in their
own argv[0]. For GDBserver, it would already have been possible to
launch an executable with forward slashes before (e.g., when debugging
from a Linux or Cygwin client), so this makes Windows gdbserver
behavior more consistent, independently of client, too.
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
backslashes.
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 +++++++------------
gdb/windows-nat.c | 6 ++++-
gdbserver/win32-low.cc | 6 +++++
gdbsupport/pathstuff.cc | 16 +++++++++--
gdbsupport/pathstuff.h | 5 ++++
18 files changed, 207 insertions(+), 39 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index d5214a98a57..75927c36f19 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\main.c
+
+ GDB will now consistently show forward slashes:
+
+ C:/proj/src/main.c
+
+ 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/gdb/windows-nat.c b/gdb/windows-nat.c
index d2940afadff..def8fa606f4 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -3062,7 +3062,11 @@ windows_nat_target::create_inferior (const char *exec_file,
si.dwFlags |= STARTF_USESTDHANDLES;
}
- toexec = exec_file;
+ /* Convert the executable path to backslash separators, so the
+ inferior observes native backslashes in its own program name. */
+ std::string toexec_native = exec_file;
+ std::replace (toexec_native.begin (), toexec_native.end (), '/', '\\');
+ toexec = toexec_native.c_str ();
/* Build the command line, a space-separated list of tokens where
the first token is the name of the module to be executed.
To avoid ambiguities introduced by spaces in the module name,
diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc
index 7db0a6739f4..7629beca213 100644
--- a/gdbserver/win32-low.cc
+++ b/gdbserver/win32-low.cc
@@ -539,6 +539,12 @@ win32_process_target::create_inferior (const char *program,
}
cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX);
program = real_path;
+#else
+ /* Convert the executable path to backslash separators, so the
+ inferior observes native backslashes in its own program name. */
+ std::string program_native = program;
+ std::replace (program_native.begin (), program_native.end (), '/', '\\');
+ program = program_native.c_str ();
#endif
OUTMSG2 (("Command line is \"%s %s\"\n", program, args));
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
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] Windows: Normalize backward slashes to forward slashes
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-06 12:07 ` Andrew Burgess
1 sibling, 1 reply; 10+ messages in thread
From: Eli Zaretskii @ 2026-07-01 12:07 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> Date: Wed, 1 Jul 2026 12:28:41 +0100
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <pedro@palves.net>
>
> Still, I think the conversion is worth doing. What the slash direction does
> for sure affect is the argv[0] the inferior sees. The command line we hand
> CreateProcess is also what the child's CRT splits into argv, so without converting,
> the inferior sees forward slashes in its own program name. Giving the inferior
> native separators in argv[0] seems like enough reason to convert -- i.e., not
> framing it about what CreateProcess parses, but what the inferior itself sees
> and parses.
I agree.
> I've made gdb and gdbserver do that, and added a comment about this. In gdb/windows-nat.c:
>
> /* Convert the executable path to backslash separators, so the
> inferior observes native backslashes in its own program name. */
> std::string toexec_native = exec_file;
> std::replace (toexec_native.begin (), toexec_native.end (), '/', '\\');
> toexec = toexec_native.c_str ();
>
> and in gdbserver/win32-low.cc:
>
> /* Convert the executable path to backslash separators, so the
> inferior observes native backslashes in its own program name. */
> std::string program_native = program;
> std::replace (program_native.begin (), program_native.end (), '/', '\\');
> program = program_native.c_str ();
>
>
> (Note: these are both on !Cygwin paths, as the Cygwin paths already do the path
> conversion via cygwin_conv_path. And BTW, Cygwin GDB already presented forward
> slashes to users already everywhere, including in "info shared", etc.)
>
>
> Having this reason written down also avoids having to try to come up with some
> speculative comment about some old Windows behavior we're not exactly sure what it was.
>
>
> >
> >> If it's really a problem on supported Windows versions, it should be a matter of converting back to forward slashes before we
> >> call CreateProcess. We already do that in gdb/windows-nat.c:windows_nat_target::create_inferior, for "set cwd":
> >>
> >> /* Mirror slashes on inferior's cwd. */
> >> std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
> >> '/', '\\');
> >>
> >> we'd just need to do the same for exec_file.
> >
> > Yes, I think it's safer to convert to all backslashes in the argument
> > we pass to CreateProcess. And it will not show outside of that place,
> > so the (very positive and welcome) effects of your changes will not be
> > affected.
> >
>
> Here's the updated patch. Other than the tweaks mentioned above, and an updated
> commit log, nothing else changed.
>
> Let me know what you think.
LGTM, thanks. I have a couple of minor comments below.
> --- 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\main.c
> +
> + GDB will now consistently show forward slashes:
> +
> + C:/proj/src/main.c
> +
> + This affects everywhere GDB shows a filename/dirname: source
> + filenames, executable filename, shared libraries, the cd/pwd
> + commands, etc.
Should this mention GDB/MI output? Someone might not guess that it's
covered by "etc.", given that the other examples are from quite
different use cases.
> +char *
> +normalize_slashes (char *path)
> +{
> + for (char *p = path; *p != '\0'; ++p)
> + if (*p == '\\')
> + *p = '/';
> + return path;
> +}
Ehm... GNU Coding Standards frown on using "path" for anything but
PATH-style directory lists. So maybe we should use "filename" or
somesuch, here and elsewhere.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] Windows: Normalize backward slashes to forward slashes
2026-07-01 12:07 ` Eli Zaretskii
@ 2026-07-01 19:28 ` Pedro Alves
2026-07-02 5:28 ` Eli Zaretskii
0 siblings, 1 reply; 10+ messages in thread
From: Pedro Alves @ 2026-07-01 19:28 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On 2026-07-01 13:07, Eli Zaretskii wrote:
>> Date: Wed, 1 Jul 2026 12:28:41 +0100
>> Cc: gdb-patches@sourceware.org
>> From: Pedro Alves <pedro@palves.net>
>>
>> Still, I think the conversion is worth doing. What the slash direction does
>> for sure affect is the argv[0] the inferior sees. The command line we hand
>> CreateProcess is also what the child's CRT splits into argv, so without converting,
>> the inferior sees forward slashes in its own program name. Giving the inferior
>> native separators in argv[0] seems like enough reason to convert -- i.e., not
>> framing it about what CreateProcess parses, but what the inferior itself sees
>> and parses.
>
> I agree.
>
>> I've made gdb and gdbserver do that, and added a comment about this. In gdb/windows-nat.c:
>>
>> /* Convert the executable path to backslash separators, so the
>> inferior observes native backslashes in its own program name. */
>> std::string toexec_native = exec_file;
>> std::replace (toexec_native.begin (), toexec_native.end (), '/', '\\');
>> toexec = toexec_native.c_str ();
>>
>> and in gdbserver/win32-low.cc:
>>
>> /* Convert the executable path to backslash separators, so the
>> inferior observes native backslashes in its own program name. */
>> std::string program_native = program;
>> std::replace (program_native.begin (), program_native.end (), '/', '\\');
>> program = program_native.c_str ();
>>
>>
>> (Note: these are both on !Cygwin paths, as the Cygwin paths already do the path
>> conversion via cygwin_conv_path. And BTW, Cygwin GDB already presented forward
>> slashes to users already everywhere, including in "info shared", etc.)
>>
>>
>> Having this reason written down also avoids having to try to come up with some
>> speculative comment about some old Windows behavior we're not exactly sure what it was.
>>
>>
>>>
>>>> If it's really a problem on supported Windows versions, it should be a matter of converting back to forward slashes before we
>>>> call CreateProcess. We already do that in gdb/windows-nat.c:windows_nat_target::create_inferior, for "set cwd":
>>>>
>>>> /* Mirror slashes on inferior's cwd. */
>>>> std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
>>>> '/', '\\');
>>>>
>>>> we'd just need to do the same for exec_file.
>>>
>>> Yes, I think it's safer to convert to all backslashes in the argument
>>> we pass to CreateProcess. And it will not show outside of that place,
>>> so the (very positive and welcome) effects of your changes will not be
>>> affected.
>>>
>>
>> Here's the updated patch. Other than the tweaks mentioned above, and an updated
>> commit log, nothing else changed.
>>
>> Let me know what you think.
>
> LGTM, thanks. I have a couple of minor comments below.
>
>> --- 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\main.c
>> +
>> + GDB will now consistently show forward slashes:
>> +
>> + C:/proj/src/main.c
>> +
>> + This affects everywhere GDB shows a filename/dirname: source
>> + filenames, executable filename, shared libraries, the cd/pwd
>> + commands, etc.
>
> Should this mention GDB/MI output? Someone might not guess that it's
> covered by "etc.", given that the other examples are from quite
> different use cases.
How about this?
This impacts all interpreters, including the CLI, the TUI, the
GDB/MI interface, and the Debug Adapter Protocol, and affects
everywhere GDB shows a filename/dirname: source filenames,
executable filename, shared libraries, the cd/pwd commands, etc.
>
>> +char *
>> +normalize_slashes (char *path)
>> +{
>> + for (char *p = path; *p != '\0'; ++p)
>> + if (*p == '\\')
>> + *p = '/';
>> + return path;
>> +}
>
> Ehm... GNU Coding Standards frown on using "path" for anything but
> PATH-style directory lists. So maybe we should use "filename" or
> somesuch, here and elsewhere.
Yeah, I had made an effort to avoid it in the NEWS entry for that reason.
For the code itself, I think that's a losing battle, the file itself
is called pathstuff.c, described at the top as:
/* Path manipulation routines for GDB and gdbserver.
It's full of functions using "path" as I was using, and then used throughout GDB,
like:
$ grep path ../gdbsupport/pathstuff.h | grep extern
extern char *normalize_slashes (char *path);
extern gdb::unique_xmalloc_ptr<char> gdb_realpath (const char *filename);
extern std::string gdb_realpath_keepfile (const char *filename);
extern std::string gdb_abspath (const char *path,
extern const char *child_path (const char *parent, const char *child);
extern std::string path_join (gdb::array_view<const char *> paths);
extern bool contains_dir_separator (const char *path);
Then you have standard functions/symbols like realpath, GetFullPathName, PATH_MAX, etc
(used by that file).
So "path" is pretty well established, including in POSIX and Windows APIs, and I don't
think GDB developers end up confused.
Honestly, I think using the GNU terminology confuses more people than helps.
Recently in the DWARF committee I pointed out the GNU terminology to people, and
everyone seemed surprised and confused, and I think thought I was being weird. :-P
If I were to have say in this aspect of the GNU coding standards, I would rather come
up with a more precise name for the PATH-style directory lists case than fight about what
does "path" mean.
>
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] Windows: Normalize backward slashes to forward slashes
2026-07-01 19:28 ` Pedro Alves
@ 2026-07-02 5:28 ` Eli Zaretskii
0 siblings, 0 replies; 10+ messages in thread
From: Eli Zaretskii @ 2026-07-02 5:28 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> Date: Wed, 1 Jul 2026 20:28:32 +0100
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <pedro@palves.net>
>
> >> +* 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\main.c
> >> +
> >> + GDB will now consistently show forward slashes:
> >> +
> >> + C:/proj/src/main.c
> >> +
> >> + This affects everywhere GDB shows a filename/dirname: source
> >> + filenames, executable filename, shared libraries, the cd/pwd
> >> + commands, etc.
> >
> > Should this mention GDB/MI output? Someone might not guess that it's
> > covered by "etc.", given that the other examples are from quite
> > different use cases.
>
> How about this?
>
> This impacts all interpreters, including the CLI, the TUI, the
> GDB/MI interface, and the Debug Adapter Protocol, and affects
> everywhere GDB shows a filename/dirname: source filenames,
> executable filename, shared libraries, the cd/pwd commands, etc.
Much better, thanks.
> >> +char *
> >> +normalize_slashes (char *path)
> >> +{
> >> + for (char *p = path; *p != '\0'; ++p)
> >> + if (*p == '\\')
> >> + *p = '/';
> >> + return path;
> >> +}
> >
> > Ehm... GNU Coding Standards frown on using "path" for anything but
> > PATH-style directory lists. So maybe we should use "filename" or
> > somesuch, here and elsewhere.
>
> Yeah, I had made an effort to avoid it in the NEWS entry for that reason.
>
> For the code itself, I think that's a losing battle, the file itself
> is called pathstuff.c, described at the top as:
>
> /* Path manipulation routines for GDB and gdbserver.
>
> It's full of functions using "path" as I was using, and then used throughout GDB,
> like:
>
> $ grep path ../gdbsupport/pathstuff.h | grep extern
> extern char *normalize_slashes (char *path);
> extern gdb::unique_xmalloc_ptr<char> gdb_realpath (const char *filename);
> extern std::string gdb_realpath_keepfile (const char *filename);
> extern std::string gdb_abspath (const char *path,
> extern const char *child_path (const char *parent, const char *child);
> extern std::string path_join (gdb::array_view<const char *> paths);
> extern bool contains_dir_separator (const char *path);
>
> Then you have standard functions/symbols like realpath, GetFullPathName, PATH_MAX, etc
> (used by that file).
>
> So "path" is pretty well established, including in POSIX and Windows APIs, and I don't
> think GDB developers end up confused.
I know, but I thought that maybe the new function you are adding could
use filename?
> Honestly, I think using the GNU terminology confuses more people than helps.
> Recently in the DWARF committee I pointed out the GNU terminology to people, and
> everyone seemed surprised and confused, and I think thought I was being weird. :-P
>
> If I were to have say in this aspect of the GNU coding standards, I would rather come
> up with a more precise name for the PATH-style directory lists case than fight about what
> does "path" mean.
I understand.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] Windows: Normalize backward slashes to forward slashes
2026-07-01 11:28 ` [PATCH v2] " Pedro Alves
2026-07-01 12:07 ` Eli Zaretskii
@ 2026-07-06 12:07 ` Andrew Burgess
2026-07-06 22:35 ` Pedro Alves
1 sibling, 1 reply; 10+ messages in thread
From: Andrew Burgess @ 2026-07-06 12:07 UTC (permalink / raw)
To: Pedro Alves, Eli Zaretskii; +Cc: gdb-patches
Pedro Alves <pedro@palves.net> writes:
> 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);
It's not a problem in any of the existing code, but maybe also:
gdb_assert (*path != nullptr);
otherwise we end up trying to create a std::string from NULL.
I looked through the rest of the changes, and it all looks reasonable to
me.
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
Thanks,
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] Windows: Normalize backward slashes to forward slashes
2026-07-06 12:07 ` Andrew Burgess
@ 2026-07-06 22:35 ` Pedro Alves
0 siblings, 0 replies; 10+ messages in thread
From: Pedro Alves @ 2026-07-06 22:35 UTC (permalink / raw)
To: Andrew Burgess, Eli Zaretskii; +Cc: gdb-patches
On 2026-07-06 13:07, Andrew Burgess wrote:
> Pedro Alves <pedro@palves.net> writes:
>> +struct scoped_normalized_path
>> +{
>> + explicit scoped_normalized_path (const char **path)
>> + {
>> + gdb_assert (path != nullptr);
>
> It's not a problem in any of the existing code, but maybe also:
>
> gdb_assert (*path != nullptr);
>
> otherwise we end up trying to create a std::string from NULL.
>
Thank you. I've merged the patch with this change.
Pedro Alves
> I looked through the rest of the changes, and it all looks reasonable to
> me.
>
> Reviewed-By: Andrew Burgess <aburgess@redhat.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-06 22:36 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-29 21:24 [PATCH] Windows: Normalize backward slashes to forward slashes Pedro Alves
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox