From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id bUd8BbbiQmoVUR4AWB0awg (envelope-from ) for ; Mon, 29 Jun 2026 17:25:10 -0400 Received: by simark.ca (Postfix, from userid 112) id C64C61E098; Mon, 29 Jun 2026 17:25:09 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.3 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 6C9321E070 for ; Mon, 29 Jun 2026 17:25:07 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D88054BA7984 for ; Mon, 29 Jun 2026 21:25:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D88054BA7984 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) by sourceware.org (Postfix) with ESMTPS id B92674BA23CA for ; Mon, 29 Jun 2026 21:24:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B92674BA23CA Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B92674BA23CA Authentication-Results: sourceware.org; arc=none smtp.remote-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782768276; cv=none; b=kLojhATS+s8+JU9PRz8gjxr+0XJdN6FyHu+Jok2XRzD5WphMQDRX1aM5UsrOOutH/6icKtubeQ3JmuxWqRiuH7PYw6obX4b12D2ZXW/MzttprbJEm3spt3Vls3wZ9S2Fbxs4D1xnEQNg9LgUB7tNaDgPZti41T3dB8AMHv/4j+o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782768276; c=relaxed/simple; bh=TmkK/jpe1f1POerhBYm45i6Or6Hv7vOVrPjWtbuNMhU=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=KOv1w97Rt/biZgKcvPFRqOyRTT3TDOQPU5kshNpfjlzrILQcTEqGId1M00U73uM4r78pQcJY7domK2XAU3AXPnCS975W0H1TurRcKezEGYCmsfmOeBHa1NCJ/kFoTHaNe8riYDHV6av30fAbnT9BfnvcECjv2QBo+E3E6rfQF6I= ARC-Authentication-Results: i=1; sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B92674BA23CA Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-4703bc0a99aso1414300f8f.3 for ; Mon, 29 Jun 2026 14:24:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782768274; x=1783373074; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=pwQ24Qa+IwxC5dG/q1R2MNNSuzPjlmG9fq4g8r/zXQQ=; b=fQIpqg1GJfxj7fWyJjHCECkX0npedv6S8DKXuHP3HlBksLiBdH2vx0dOVSyaE7MJt8 69o4RKbM45loZSzNY9Xk1PH6igxCpOoVPjYpbkXQtVjTCRs3QQV+cSkWQZTZbMGxUiuc 61eLDq316WcVIuAu2M6hciNXJ8xFhTNI/9eq36E7UkLMhU20zQ6MrQC7yAF8kJsM78Wc fqnBy2FZW5zcJTPH+H68bKyMOfjS0px0wFO71GsnBnoz1h4h7NX2xPeJA+z77mfdjzgK 1yYQxe+KeZ/eBwicBi5L1WuFFuM9uJerYfbPtlZkbyYcCl0aRQ9XMvYYVt9Qe1DdXYtU QCrg== X-Gm-Message-State: AOJu0YxvqeQNqOFMdn00936o/C2BCTReJeJdLgKLQpqX1wJt2EnKXoE9 onB9eUUk9JsHRRLohV6814KlO+afCWXaNEv4DAEKndQ0ackP15rOvRcrbLuI/w== X-Gm-Gg: AfdE7cnv0rKBKlxGogjswuTabSRtVISShCnRMKXI/55cRBLOJEYzRyYM35Cmj+Ro5/k PBL9Qoojy33uEFodNU0a9gJ07X19oNVMfzgAxTiUBuXYM7U8jMb4RIru06IB0BIecHIPpSGsuWV gQrFY25fau9FE8xAa4ijflttd9San+LKoX7i7szSbQpXhXs9ZdXLh/BFSzoF3eMHTkCPNCyd/ZT 6zkDq4ciiuri3hruAoPHkR6HYKDkKm9viDZRAp/JEKSdhZjfWMZVsGCRgOm7u6SpWbDe3jdq/4P Dms0P2sHZu+t+TZms9TMINkSYSlJqQ2cS3yQXZpVghBW/vHIrVP+bgbAxRSHFEqOUw7bsmtty1g G8+gIpMZ9Ls6MKL4ZFs1DZsjn5RGqtYCIKr4FsoKgtHiJAdj1leTUMxpsiYRaph/PR1WQGmiqZH 28DMkDwu8BMzs= X-Received: by 2002:a5d:588e:0:b0:465:81cb:bb20 with SMTP id ffacd0b85a97d-475507ddc81mr1207163f8f.9.1782768273837; Mon, 29 Jun 2026 14:24:33 -0700 (PDT) Received: from localhost ([2001:8a0:fae3:2600:3cd9:9bfa:6f9d:80e4]) by smtp.gmail.com with UTF8SMTPSA id ffacd0b85a97d-47563e0eee5sm1247809f8f.5.2026.06.29.14.24.33 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 29 Jun 2026 14:24:33 -0700 (PDT) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH] Windows: Normalize backward slashes to forward slashes Date: Mon, 29 Jun 2026 22:24:30 +0100 Message-ID: <20260629212430.340516-1-pedro@palves.net> X-Mailer: git-send-email 2.54.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org 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 cwd (getcwd (NULL, 0)); + gdb::unique_xmalloc_ptr 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 cwd (getcwd (NULL, 0)); + gdb::unique_xmalloc_ptr 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 #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 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 . */ #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 #include @@ -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 #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 cwd (getcwd (NULL, 0)); + gdb::unique_xmalloc_ptr 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 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 #include @@ -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 (&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 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