public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t
@ 2022-12-06 19:50 Björn Schäpers
  2022-12-06 19:50 ` [PATCH 2/4] libbacktrace: detect executable path on windows Björn Schäpers
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Björn Schäpers @ 2022-12-06 19:50 UTC (permalink / raw)
  To: gcc-patches, iant

From: Björn Schäpers <bjoern@hazardy.de>

It's the right thing to do, since the PC shouldn't go out of the
uintptr_t domain, and in backtrace_pcinfo the pc is uintptr_t.
This is a preparation for a following patch.

Tested on x86_64-linux and i686-w64-mingw32.

-- >8 --

	* dwarf.c: changed variables holding pc values from uint64_t to
	uintptr_t.

Signed-off-by: Björn Schäpers <bjoern@hazardy.de>
---
 libbacktrace/dwarf.c | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index 45cc9e77e40..0707ccddd3e 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -274,8 +274,8 @@ struct function
 struct function_addrs
 {
   /* Range is LOW <= PC < HIGH.  */
-  uint64_t low;
-  uint64_t high;
+  uintptr_t low;
+  uintptr_t high;
   /* Function for this address range.  */
   struct function *function;
 };
@@ -356,8 +356,8 @@ struct unit
 struct unit_addrs
 {
   /* Range is LOW <= PC < HIGH.  */
-  uint64_t low;
-  uint64_t high;
+  uintptr_t low;
+  uintptr_t high;
   /* Compilation unit for this address range.  */
   struct unit *u;
 };
@@ -1094,7 +1094,7 @@ resolve_addr_index (const struct dwarf_sections *dwarf_sections,
 		    uint64_t addr_base, int addrsize, int is_bigendian,
 		    uint64_t addr_index,
 		    backtrace_error_callback error_callback, void *data,
-		    uint64_t *address)
+		    uintptr_t *address)
 {
   uint64_t offset;
   struct dwarf_buf addr_buf;
@@ -1194,7 +1194,7 @@ function_addrs_search (const void *vkey, const void *ventry)
 
 static int
 add_unit_addr (struct backtrace_state *state, void *rdata,
-	       uint64_t lowpc, uint64_t highpc,
+	       uintptr_t lowpc, uintptr_t highpc,
 	       backtrace_error_callback error_callback, void *data,
 	       void *pvec)
 {
@@ -1530,10 +1530,10 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code,
    lowpc/highpc is set or ranges is set.  */
 
 struct pcrange {
-  uint64_t lowpc;		/* The low PC value.  */
+  uintptr_t lowpc;		/* The low PC value.  */
   int have_lowpc;		/* Whether a low PC value was found.  */
   int lowpc_is_addr_index;	/* Whether lowpc is in .debug_addr.  */
-  uint64_t highpc;		/* The high PC value.  */
+  uintptr_t highpc;		/* The high PC value.  */
   int have_highpc;		/* Whether a high PC value was found.  */
   int highpc_is_relative;	/* Whether highpc is relative to lowpc.  */
   int highpc_is_addr_index;	/* Whether highpc is in .debug_addr.  */
@@ -1613,16 +1613,16 @@ add_low_high_range (struct backtrace_state *state,
 		    uintptr_t base_address, int is_bigendian,
 		    struct unit *u, const struct pcrange *pcrange,
 		    int (*add_range) (struct backtrace_state *state,
-				      void *rdata, uint64_t lowpc,
-				      uint64_t highpc,
+				      void *rdata, uintptr_t lowpc,
+				      uintptr_t highpc,
 				      backtrace_error_callback error_callback,
 				      void *data, void *vec),
 		    void *rdata,
 		    backtrace_error_callback error_callback, void *data,
 		    void *vec)
 {
-  uint64_t lowpc;
-  uint64_t highpc;
+  uintptr_t lowpc;
+  uintptr_t highpc;
 
   lowpc = pcrange->lowpc;
   if (pcrange->lowpc_is_addr_index)
@@ -1663,7 +1663,7 @@ add_ranges_from_ranges (
     struct unit *u, uint64_t base,
     const struct pcrange *pcrange,
     int (*add_range) (struct backtrace_state *state, void *rdata,
-		      uint64_t lowpc, uint64_t highpc,
+		      uintptr_t lowpc, uintptr_t highpc,
 		      backtrace_error_callback error_callback, void *data,
 		      void *vec),
     void *rdata,
@@ -1727,10 +1727,10 @@ add_ranges_from_rnglists (
     struct backtrace_state *state,
     const struct dwarf_sections *dwarf_sections,
     uintptr_t base_address, int is_bigendian,
-    struct unit *u, uint64_t base,
+    struct unit *u, uintptr_t base,
     const struct pcrange *pcrange,
     int (*add_range) (struct backtrace_state *state, void *rdata,
-		      uint64_t lowpc, uint64_t highpc,
+		      uintptr_t lowpc, uintptr_t highpc,
 		      backtrace_error_callback error_callback, void *data,
 		      void *vec),
     void *rdata,
@@ -1796,8 +1796,8 @@ add_ranges_from_rnglists (
 	case DW_RLE_startx_endx:
 	  {
 	    uint64_t index;
-	    uint64_t low;
-	    uint64_t high;
+	    uintptr_t low;
+	    uintptr_t high;
 
 	    index = read_uleb128 (&rnglists_buf);
 	    if (!resolve_addr_index (dwarf_sections, u->addr_base,
@@ -1819,8 +1819,8 @@ add_ranges_from_rnglists (
 	case DW_RLE_startx_length:
 	  {
 	    uint64_t index;
-	    uint64_t low;
-	    uint64_t length;
+	    uintptr_t low;
+	    uintptr_t length;
 
 	    index = read_uleb128 (&rnglists_buf);
 	    if (!resolve_addr_index (dwarf_sections, u->addr_base,
@@ -1905,7 +1905,7 @@ add_ranges (struct backtrace_state *state,
 	    uintptr_t base_address, int is_bigendian,
 	    struct unit *u, uint64_t base, const struct pcrange *pcrange,
 	    int (*add_range) (struct backtrace_state *state, void *rdata, 
-			      uint64_t lowpc, uint64_t highpc,
+			      uintptr_t lowpc, uintptr_t highpc,
 			      backtrace_error_callback error_callback,
 			      void *data, void *vec),
 	    void *rdata,
@@ -3183,7 +3183,7 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
 
 static int
 add_function_range (struct backtrace_state *state, void *rdata,
-		    uint64_t lowpc, uint64_t highpc,
+		    uintptr_t lowpc, uintptr_t highpc,
 		    backtrace_error_callback error_callback, void *data,
 		    void *pvec)
 {
@@ -3223,7 +3223,7 @@ add_function_range (struct backtrace_state *state, void *rdata,
 
 static int
 read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
-		     struct unit *u, uint64_t base, struct dwarf_buf *unit_buf,
+		     struct unit *u, uintptr_t base, struct dwarf_buf *unit_buf,
 		     const struct line_header *lhdr,
 		     backtrace_error_callback error_callback, void *data,
 		     struct function_vector *vec_function,
-- 
2.38.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/4] libbacktrace: detect executable path on windows
  2022-12-06 19:50 [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t Björn Schäpers
@ 2022-12-06 19:50 ` Björn Schäpers
  2022-12-06 19:50 ` [PATCH 3/4] libbacktrace: work with aslr " Björn Schäpers
  2022-12-06 19:50 ` [PATCH 4/4] libbacktrace: get debug information for loaded dlls Björn Schäpers
  2 siblings, 0 replies; 17+ messages in thread
From: Björn Schäpers @ 2022-12-06 19:50 UTC (permalink / raw)
  To: gcc-patches, iant

From: Björn Schäpers <bjoern@hazardy.de>

This is actually needed so that libstdc++'s <stacktrace> implementation
to be able to work on windows.

Tested on x86_64-linux and i686-w64-mingw32.

-- >8 --

	* configure.ac: Add a check for windows.h.
	* configure, config.h.in: Regenerate.
	* fileline.c: Add windows_get_executable_path.
	* fileline.c (fileline_initialiez): Add a pass using
	windows_get_executable_path.

Signed-off-by: Björn Schäpers <bjoern@hazardy.de>
---
 libbacktrace/configure.ac |  2 ++
 libbacktrace/fileline.c   | 43 ++++++++++++++++++++++++++++++++++++++-
 4 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 1daaa2f62d2..b5feb29bcdc 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -377,6 +377,8 @@ if test "$have_loadquery" = "yes"; then
   AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.])
 fi
 
+AC_CHECK_HEADERS(windows.h)
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index a40cd498114..73c2c8e8bc9 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include <mach-o/dyld.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#ifndef WIN32_MEAN_AND_LEAN
+#define WIN32_MEAN_AND_LEAN
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include <windows.h>
+#endif
+
 #include "backtrace.h"
 #include "internal.h"
 
@@ -155,6 +167,28 @@ macho_get_executable_path (struct backtrace_state *state,
 
 #endif /* !defined (HAVE_MACH_O_DYLD_H) */
 
+#ifdef HAVE_WINDOWS_H
+
+static char *
+windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
+			     void *data)
+{
+  if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0)
+    {
+      error_callback (data,
+		      "could not get the filename of the current executable",
+		      (int) GetLastError ());
+      return NULL;
+    }
+  return buf;
+}
+
+#else /* !defined (HAVE_WINDOWS_H) */
+
+#define windows_get_executable_path(buf, error_callback, data) NULL
+
+#endif /* !defined (HAVE_WINDOWS_H) */
+
 /* Initialize the fileline information from the executable.  Returns 1
    on success, 0 on failure.  */
 
@@ -168,7 +202,11 @@ fileline_initialize (struct backtrace_state *state,
   int called_error_callback;
   int descriptor;
   const char *filename;
+#ifdef HAVE_WINDOWS_H
+  char buf[MAX_PATH];
+#else
   char buf[64];
+#endif
 
   if (!state->threaded)
     failed = state->fileline_initialization_failed;
@@ -192,7 +230,7 @@ fileline_initialize (struct backtrace_state *state,
 
   descriptor = -1;
   called_error_callback = 0;
-  for (pass = 0; pass < 8; ++pass)
+  for (pass = 0; pass < 9; ++pass)
     {
       int does_not_exist;
 
@@ -224,6 +262,9 @@ fileline_initialize (struct backtrace_state *state,
 	case 7:
 	  filename = macho_get_executable_path (state, error_callback, data);
 	  break;
+	case 8:
+	  filename = windows_get_executable_path (buf, error_callback, data);
+	  break;
 	default:
 	  abort ();
 	}
-- 
2.38.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 3/4] libbacktrace: work with aslr on windows
  2022-12-06 19:50 [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t Björn Schäpers
  2022-12-06 19:50 ` [PATCH 2/4] libbacktrace: detect executable path on windows Björn Schäpers
@ 2022-12-06 19:50 ` Björn Schäpers
  2022-12-06 19:50 ` [PATCH 4/4] libbacktrace: get debug information for loaded dlls Björn Schäpers
  2 siblings, 0 replies; 17+ messages in thread
From: Björn Schäpers @ 2022-12-06 19:50 UTC (permalink / raw)
  To: gcc-patches, iant

From: Björn Schäpers <bjoern@hazardy.de>

Any underflow which might happen, will be countered by an overflow in
dwarf.c.

Tested on x86_64-linux and i686-w64-mingw32.

-- >8 --

Fixes https://github.com/ianlancetaylor/libbacktrace/issues/89 and
https://github.com/ianlancetaylor/libbacktrace/issues/82.

	* pecoff.c (coff_add): Set the base_address of the module, to
	find the debug information on moved applications.

Signed-off-by: Björn Schäpers <bjoern@hazardy.de>
---
 libbacktrace/pecoff.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c
index 87b3c0cc647..296f1357b5f 100644
--- a/libbacktrace/pecoff.c
+++ b/libbacktrace/pecoff.c
@@ -39,6 +39,18 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include "backtrace.h"
 #include "internal.h"
 
+#ifdef HAVE_WINDOWS_H
+#ifndef WIN32_MEAN_AND_LEAN
+#define WIN32_MEAN_AND_LEAN
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include <windows.h>
+#endif
+
 /* Coff file header.  */
 
 typedef struct {
@@ -610,6 +622,8 @@ coff_add (struct backtrace_state *state, int descriptor,
   int debug_view_valid;
   int is_64;
   uintptr_t image_base;
+  uintptr_t base_address = 0;
+  uintptr_t module_handle;
   struct dwarf_sections dwarf_sections;
 
   *found_sym = 0;
@@ -856,7 +870,12 @@ coff_add (struct backtrace_state *state, int descriptor,
 				  + (sections[i].offset - min_offset));
     }
 
-  if (!backtrace_dwarf_add (state, /* base_address */ 0, &dwarf_sections,
+#ifdef HAVE_WINDOWS_H
+    module_handle = (uintptr_t) GetModuleHandleW (NULL);
+    base_address = module_handle - image_base;
+#endif
+
+  if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
 			    0, /* FIXME: is_bigendian */
 			    NULL, /* altlink */
 			    error_callback, data, fileline_fn,
-- 
2.38.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 4/4] libbacktrace: get debug information for loaded dlls
  2022-12-06 19:50 [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t Björn Schäpers
  2022-12-06 19:50 ` [PATCH 2/4] libbacktrace: detect executable path on windows Björn Schäpers
  2022-12-06 19:50 ` [PATCH 3/4] libbacktrace: work with aslr " Björn Schäpers
@ 2022-12-06 19:50 ` Björn Schäpers
  2 siblings, 0 replies; 17+ messages in thread
From: Björn Schäpers @ 2022-12-06 19:50 UTC (permalink / raw)
  To: gcc-patches, iant

From: Björn Schäpers <bjoern@hazardy.de>

Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except
that libraries loaded after the backtrace_initialize are not handled.
But as far as I can see that's the same for elf.

Tested on x86_64-linux and i686-w64-mingw32.

-- >8 --

	* pecoff.c (coff_add): New argument for the module handle of the
	file, to get the base address.
	* pecoff.c (backtrace_initialize): Iterate over loaded libraries
	and call coff_add.

Signed-off-by: Björn Schäpers <bjoern@hazardy.de>
---
 libbacktrace/pecoff.c | 76 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 72 insertions(+), 4 deletions(-)

diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c
index 296f1357b5f..40395109e51 100644
--- a/libbacktrace/pecoff.c
+++ b/libbacktrace/pecoff.c
@@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #endif
 
 #include <windows.h>
+#include <psapi.h>
 #endif
 
 /* Coff file header.  */
@@ -592,7 +593,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr,
 static int
 coff_add (struct backtrace_state *state, int descriptor,
 	  backtrace_error_callback error_callback, void *data,
-	  fileline *fileline_fn, int *found_sym, int *found_dwarf)
+	  fileline *fileline_fn, int *found_sym, int *found_dwarf,
+	  uintptr_t module_handle ATTRIBUTE_UNUSED)
 {
   struct backtrace_view fhdr_view;
   off_t fhdr_off;
@@ -623,7 +625,6 @@ coff_add (struct backtrace_state *state, int descriptor,
   int is_64;
   uintptr_t image_base;
   uintptr_t base_address = 0;
-  uintptr_t module_handle;
   struct dwarf_sections dwarf_sections;
 
   *found_sym = 0;
@@ -871,7 +872,6 @@ coff_add (struct backtrace_state *state, int descriptor,
     }
 
 #ifdef HAVE_WINDOWS_H
-    module_handle = (uintptr_t) GetModuleHandleW (NULL);
     base_address = module_handle - image_base;
 #endif
 
@@ -914,12 +914,80 @@ backtrace_initialize (struct backtrace_state *state,
   int found_sym;
   int found_dwarf;
   fileline coff_fileline_fn;
+  uintptr_t module_handle = 0;
+
+#ifdef HAVE_WINDOWS_H
+  DWORD i;
+  DWORD module_count;
+  DWORD bytes_needed_for_modules;
+  HMODULE *modules;
+  char module_name[MAX_PATH];
+  int module_found_sym;
+  fileline module_fileline_fn;
+
+  module_handle = (uintptr_t) GetModuleHandleW (NULL);
+#endif
 
   ret = coff_add (state, descriptor, error_callback, data,
-		  &coff_fileline_fn, &found_sym, &found_dwarf);
+		  &coff_fileline_fn, &found_sym, &found_dwarf, module_handle);
   if (!ret)
     return 0;
 
+#ifdef HAVE_WINDOWS_H
+  module_count = 1000;
+ alloc_modules:
+  modules = backtrace_alloc (state, module_count * sizeof(HMODULE),
+			     error_callback, data);
+  if (modules == NULL)
+    goto skip_modules;
+  if (!EnumProcessModules (GetCurrentProcess (), modules, module_count,
+			   &bytes_needed_for_modules))
+    {
+      error_callback(data, "Could not enumerate process modules",
+		     (int) GetLastError ());
+      goto free_modules;
+    }
+  if (bytes_needed_for_modules > module_count * sizeof(HMODULE))
+    {
+      backtrace_free (state, modules, module_count * sizeof(HMODULE),
+		      error_callback, data);
+      // Add an extra of 2, if some module is loaded in another thread.
+      module_count = bytes_needed_for_modules / sizeof(HMODULE) + 2;
+      modules = NULL;
+      goto alloc_modules;
+    }
+
+  for (i = 0; i < bytes_needed_for_modules / sizeof(HMODULE); ++i)
+    {
+      if (GetModuleFileNameA (modules[i], module_name, MAX_PATH - 1))
+	{
+	  if (strcmp (filename, module_name) == 0)
+	    continue;
+
+	  module_handle = (uintptr_t) GetModuleHandleA (module_name);
+	  if (module_handle == 0)
+	    continue;
+
+	  descriptor = backtrace_open (module_name, error_callback, data, NULL);
+	  if (descriptor < 0)
+	    continue;
+
+	  coff_add (state, descriptor, error_callback, data,
+		    &module_fileline_fn, &module_found_sym, &found_dwarf,
+		    module_handle);
+	  if (module_found_sym)
+	    found_sym = 1;
+	}
+    }
+
+ free_modules:
+  if (modules)
+    backtrace_free(state, modules, module_count * sizeof(HMODULE),
+		   error_callback, data);
+  modules = NULL;
+ skip_modules:
+#endif
+
   if (!state->threaded)
     {
       if (found_sym)
-- 
2.38.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-11-20 19:56                     ` Björn Schäpers
@ 2023-11-29 22:05                       ` Ian Lance Taylor
  0 siblings, 0 replies; 17+ messages in thread
From: Ian Lance Taylor @ 2023-11-29 22:05 UTC (permalink / raw)
  To: Björn Schäpers; +Cc: Eli Zaretskii, gcc-patches, gcc

[-- Attachment #1: Type: text/plain, Size: 551 bytes --]

On Mon, Nov 20, 2023 at 11:57 AM Björn Schäpers <gcc@hazardy.de> wrote:
>
> this is what I'm using with GCC 12 and 13 on my windows machines, rebased onto
> the current HEAD.

Thanks.  Committed as follows.

Ian

            * fileline.c: Include <windows.h> if available.
            (windows_get_executable_path): New static function.
            (fileline_initialize): Call windows_get_executable_path.
            * configure.ac: Checked for windows.h
            * configure: Regenerate.
            * config.h.in: Regenerate.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 3728 bytes --]

0ee01dfacbcc9bc05d11433a69c0a0ac13afa42f
diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index a4f5bddddf6..ee2616335c7 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -104,6 +104,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
 /* Define if -lz is available. */
 #undef HAVE_ZLIB
 
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 0ccc060901d..7ade966b54d 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -13509,6 +13509,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h
 
 fi
 
+for ac_header in windows.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default"
+if test "x$ac_cv_header_windows_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_WINDOWS_H 1
+_ACEOF
+
+fi
+
+done
+
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 71cd50f8cdf..00acb42eb6d 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -379,6 +379,8 @@ if test "$have_loadquery" = "yes"; then
   AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.])
 fi
 
+AC_CHECK_HEADERS(windows.h)
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 0e560b44e7a..773f3a92969 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include <mach-o/dyld.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#ifndef WIN32_MEAN_AND_LEAN
+#define WIN32_MEAN_AND_LEAN
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include <windows.h>
+#endif
+
 #include "backtrace.h"
 #include "internal.h"
 
@@ -165,6 +177,37 @@ macho_get_executable_path (struct backtrace_state *state,
 
 #endif /* !HAVE_DECL__PGMPTR */
 
+#ifdef HAVE_WINDOWS_H
+
+#define FILENAME_BUF_SIZE (MAX_PATH)
+
+static char *
+windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
+			     void *data)
+{
+  size_t got;
+  int error;
+
+  got = GetModuleFileNameA (NULL, buf, FILENAME_BUF_SIZE - 1);
+  error = GetLastError ();
+  if (got == 0
+      || (got == FILENAME_BUF_SIZE - 1 && error == ERROR_INSUFFICIENT_BUFFER))
+    {
+      error_callback (data,
+		      "could not get the filename of the current executable",
+		      error);
+      return NULL;
+    }
+  return buf;
+}
+
+#else /* !defined (HAVE_WINDOWS_H) */
+
+#define windows_get_executable_path(buf, error_callback, data) NULL
+#define FILENAME_BUF_SIZE 64
+
+#endif /* !defined (HAVE_WINDOWS_H) */
+
 /* Initialize the fileline information from the executable.  Returns 1
    on success, 0 on failure.  */
 
@@ -178,7 +221,7 @@ fileline_initialize (struct backtrace_state *state,
   int called_error_callback;
   int descriptor;
   const char *filename;
-  char buf[64];
+  char buf[FILENAME_BUF_SIZE];
 
   if (!state->threaded)
     failed = state->fileline_initialization_failed;
@@ -202,7 +245,7 @@ fileline_initialize (struct backtrace_state *state,
 
   descriptor = -1;
   called_error_callback = 0;
-  for (pass = 0; pass < 9; ++pass)
+  for (pass = 0; pass < 10; ++pass)
     {
       int does_not_exist;
 
@@ -239,6 +282,9 @@ fileline_initialize (struct backtrace_state *state,
 	case 8:
 	  filename = macho_get_executable_path (state, error_callback, data);
 	  break;
+	case 9:
+	  filename = windows_get_executable_path (buf, error_callback, data);
+	  break;
 	default:
 	  abort ();
 	}

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-02-06  0:22                   ` Ian Lance Taylor
@ 2023-11-20 19:56                     ` Björn Schäpers
  2023-11-29 22:05                       ` Ian Lance Taylor
  0 siblings, 1 reply; 17+ messages in thread
From: Björn Schäpers @ 2023-11-20 19:56 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Eli Zaretskii, gcc-patches, gcc

[-- Attachment #1: Type: text/plain, Size: 982 bytes --]

Hi,

this is what I'm using with GCC 12 and 13 on my windows machines, rebased onto 
the current HEAD.

Kind regards,
Björn.

Am 06.02.2023 um 01:22 schrieb Ian Lance Taylor:
> On Sun, Feb 5, 2023 at 1:21 AM Björn Schäpers <gcc@hazardy.de> wrote:
>>
>> Am 24.01.2023 um 19:32 schrieb Ian Lance Taylor:
>>> On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches
>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>
>>>>> From: Ian Lance Taylor <iant@golang.org>
>>>>> Date: Tue, 24 Jan 2023 09:58:10 -0800
>>>>> Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
>>>>>
>>>>> I'd rather that the patch look like the appended.  Can someone with a
>>>>> Windows system test to see what that builds and passes the tests?
>>>>
>>>> ENOPATCH
>>>
>>> Gah.
>>>
>>> Ian
>>>
>> That seems to be my original patch, right? That one I have tested (and
>> am actually using) on x86 and x64 windows.
> 
> It's very similar but I changed the windows_get_executable_path function.
> 
> Ian

[-- Attachment #2: 0001-libbacktrace-detect-executable-path-on-windows.patch --]
[-- Type: text/plain, Size: 4635 bytes --]

From e0ee58b71f726606205aa1f0168a724859162c21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= <bjoern@hazardy.de>
Date: Sun, 30 Apr 2023 23:48:18 +0200
Subject: [PATCH 1/3] libbacktrace: detect executable path on windows
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Tested on x86_64-linux with GCC 12, i686-w64-mingw32 and
x86_64-w64-mingw32 with GCC 12 & 13. This patch is rebased onto the
current HEAD.

-- >8 --

	* configure.ac: Add a check for windows.h.
	* configure, config.h.in: Regenerate.
	* fileline.c: Add windows_get_executable_path.
	* fileline.c (fileline_initialize): Add a pass using
	windows_get_executable_path.

Signed-off-by: Björn Schäpers <bjoern@hazardy.de>
---
 libbacktrace/config.h.in  |  3 +++
 libbacktrace/configure    | 13 +++++++++++
 libbacktrace/configure.ac |  2 ++
 libbacktrace/fileline.c   | 49 ++++++++++++++++++++++++++++++++++++++-
 4 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index a4f5bddddf6..ee2616335c7 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -104,6 +104,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
 /* Define if -lz is available. */
 #undef HAVE_ZLIB
 
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 0ccc060901d..7ade966b54d 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -13509,6 +13509,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h
 
 fi
 
+for ac_header in windows.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default"
+if test "x$ac_cv_header_windows_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_WINDOWS_H 1
+_ACEOF
+
+fi
+
+done
+
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 71cd50f8cdf..00acb42eb6d 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -379,6 +379,8 @@ if test "$have_loadquery" = "yes"; then
   AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.])
 fi
 
+AC_CHECK_HEADERS(windows.h)
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 0e560b44e7a..28d752e2625 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include <mach-o/dyld.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#ifndef WIN32_MEAN_AND_LEAN
+#define WIN32_MEAN_AND_LEAN
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include <windows.h>
+#endif
+
 #include "backtrace.h"
 #include "internal.h"
 
@@ -165,6 +177,34 @@ macho_get_executable_path (struct backtrace_state *state,
 
 #endif /* !HAVE_DECL__PGMPTR */
 
+#ifdef HAVE_WINDOWS_H
+
+static char *
+windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
+			     void *data)
+{
+  size_t got;
+  int error;
+
+  got = GetModuleFileNameA (NULL, buf, MAX_PATH - 1);
+  error = GetLastError ();
+  if (got == 0
+      || (got == MAX_PATH - 1 && error == ERROR_INSUFFICIENT_BUFFER))
+    {
+      error_callback (data,
+		      "could not get the filename of the current executable",
+		      error);
+      return NULL;
+    }
+  return buf;
+}
+
+#else /* !defined (HAVE_WINDOWS_H) */
+
+#define windows_get_executable_path(buf, error_callback, data) NULL
+
+#endif /* !defined (HAVE_WINDOWS_H) */
+
 /* Initialize the fileline information from the executable.  Returns 1
    on success, 0 on failure.  */
 
@@ -178,7 +218,11 @@ fileline_initialize (struct backtrace_state *state,
   int called_error_callback;
   int descriptor;
   const char *filename;
+#ifdef HAVE_WINDOWS_H
+  char buf[MAX_PATH];
+#else
   char buf[64];
+#endif
 
   if (!state->threaded)
     failed = state->fileline_initialization_failed;
@@ -202,7 +246,7 @@ fileline_initialize (struct backtrace_state *state,
 
   descriptor = -1;
   called_error_callback = 0;
-  for (pass = 0; pass < 9; ++pass)
+  for (pass = 0; pass < 10; ++pass)
     {
       int does_not_exist;
 
@@ -239,6 +283,9 @@ fileline_initialize (struct backtrace_state *state,
 	case 8:
 	  filename = macho_get_executable_path (state, error_callback, data);
 	  break;
+	case 9:
+	  filename = windows_get_executable_path (buf, error_callback, data);
+	  break;
 	default:
 	  abort ();
 	}
-- 
2.42.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-02-05  9:20                 ` Björn Schäpers
@ 2023-02-06  0:22                   ` Ian Lance Taylor
  2023-11-20 19:56                     ` Björn Schäpers
  0 siblings, 1 reply; 17+ messages in thread
From: Ian Lance Taylor @ 2023-02-06  0:22 UTC (permalink / raw)
  To: Björn Schäpers; +Cc: Eli Zaretskii, gcc-patches, gcc

On Sun, Feb 5, 2023 at 1:21 AM Björn Schäpers <gcc@hazardy.de> wrote:
>
> Am 24.01.2023 um 19:32 schrieb Ian Lance Taylor:
> > On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> >>
> >>> From: Ian Lance Taylor <iant@golang.org>
> >>> Date: Tue, 24 Jan 2023 09:58:10 -0800
> >>> Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
> >>>
> >>> I'd rather that the patch look like the appended.  Can someone with a
> >>> Windows system test to see what that builds and passes the tests?
> >>
> >> ENOPATCH
> >
> > Gah.
> >
> > Ian
> >
> That seems to be my original patch, right? That one I have tested (and
> am actually using) on x86 and x64 windows.

It's very similar but I changed the windows_get_executable_path function.

Ian

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-24 18:32               ` Ian Lance Taylor
@ 2023-02-05  9:20                 ` Björn Schäpers
  2023-02-06  0:22                   ` Ian Lance Taylor
  0 siblings, 1 reply; 17+ messages in thread
From: Björn Schäpers @ 2023-02-05  9:20 UTC (permalink / raw)
  To: Ian Lance Taylor, Eli Zaretskii; +Cc: gcc-patches, gcc

Am 24.01.2023 um 19:32 schrieb Ian Lance Taylor:
> On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>>> From: Ian Lance Taylor <iant@golang.org>
>>> Date: Tue, 24 Jan 2023 09:58:10 -0800
>>> Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
>>>
>>> I'd rather that the patch look like the appended.  Can someone with a
>>> Windows system test to see what that builds and passes the tests?
>>
>> ENOPATCH
> 
> Gah.
> 
> Ian
> 
That seems to be my original patch, right? That one I have tested (and 
am actually using) on x86 and x64 windows.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-24 16:52         ` Eli Zaretskii
  2023-01-24 17:58           ` Ian Lance Taylor
@ 2023-01-24 21:00           ` Björn Schäpers
  1 sibling, 0 replies; 17+ messages in thread
From: Björn Schäpers @ 2023-01-24 21:00 UTC (permalink / raw)
  To: Eli Zaretskii, Ian Lance Taylor; +Cc: gcc-patches, gcc

Am 24.01.2023 um 17:52 schrieb Eli Zaretskii:
>> From: Ian Lance Taylor <iant@golang.org>
>> Date: Tue, 24 Jan 2023 06:35:21 -0800
>> Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
>>
>>>> On Windows it seems that MAX_PATH is not
>>>> a true limit, as an extended length path may be up to 32767 bytes.
>>>
>>> The limit of 32767 characters (not bytes, AFAIK) is only applicable
>>> when using the Unicode (a.k.a. "wide") versions of the Windows Win32
>>> APIs, see
>>>
>>>    https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
>>>
>>> Since the above code uses GetModuleFileNameA, which is an "ANSI"
>>> single-byte API, it is still subject to the MAX_PATH limitation, and
>>> MAX_PATH is defined as 260 on Windows headers.
>>
>> Thanks.  Should this code be using GetModuleFileNameW?  Or would that
>> mean that the later call to open will fail?
> 
> We'd need to use _wopen or somesuch, and the file name will have to be
> a wchar_t array, not a char array, yes.  So this is not very practical
> when file names need to be passed between functions, unless they are
> converted to UTF-8 (and back again before using them in Windows APIs).
> 
> And note that even then, the 260-byte limit could be lifted only if
> the user has a new enough Windows version _and_ has opted in to the
> long-name feature by turning it on in the Registry.  Otherwise, file
> names used in "wide" APIs can only break the 260-byte limit if they
> use the special format "\\?\D:\foo\bar", which means file names
> specified by user outside of the program or file names that come from
> other programs will need to be reformatted to this special format.
> 
>> 260 bytes does not seem like very much for a path name these days.
> 
> That's true.  But complications with using longer file names are still
> a PITA on Windows, even though they are a step closer to practically
> possible.

That was basically also my reasoning for choosing the A variant instead of W.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-24 18:11             ` Eli Zaretskii
@ 2023-01-24 18:32               ` Ian Lance Taylor
  2023-02-05  9:20                 ` Björn Schäpers
  0 siblings, 1 reply; 17+ messages in thread
From: Ian Lance Taylor @ 2023-01-24 18:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gcc, gcc-patches, gcc

[-- Attachment #1: Type: text/plain, Size: 422 bytes --]

On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> > From: Ian Lance Taylor <iant@golang.org>
> > Date: Tue, 24 Jan 2023 09:58:10 -0800
> > Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
> >
> > I'd rather that the patch look like the appended.  Can someone with a
> > Windows system test to see what that builds and passes the tests?
>
> ENOPATCH

Gah.

Ian

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 3480 bytes --]

diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index 94621c2e385..29d1ad3911a 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -100,6 +100,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
 /* Define if -lz is available. */
 #undef HAVE_ZLIB
 
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 6af2c04c81a..0a27cfb7799 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -13409,6 +13409,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h
 
 fi
 
+for ac_header in windows.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default"
+if test "x$ac_cv_header_windows_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_WINDOWS_H 1
+_ACEOF
+
+fi
+
+done
+
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 39e6bf41e35..e3e10abd7b5 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -377,6 +377,8 @@ if test "$have_loadquery" = "yes"; then
   AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.])
 fi
 
+AC_CHECK_HEADERS(windows.h)
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 674bf33cdcf..e110b54ee24 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include <mach-o/dyld.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#ifndef WIN32_MEAN_AND_LEAN
+#define WIN32_MEAN_AND_LEAN
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include <windows.h>
+#endif
+
 #include "backtrace.h"
 #include "internal.h"
 
@@ -155,6 +167,27 @@ macho_get_executable_path (struct backtrace_state *state,
 
 #endif /* !defined (HAVE_MACH_O_DYLD_H) */
 
+#ifdef HAVE_WINDOWS_H
+
+static char *
+windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
+			     void *data)
+{
+  size_t got;
+
+  got = GetModuleFileNameA (NULL, buf, MAX_PATH - 1);
+  if (got == 0
+      || (got == MAX_PATH - 1 && GetLastError () == ERROR_INSUFFICIENT_BUFFER))
+    return NULL;
+  return buf;
+}
+
+#else /* !defined (HAVE_WINDOWS_H) */
+
+#define windows_get_executable_path(buf, error_callback, data) NULL
+
+#endif /* !defined (HAVE_WINDOWS_H) */
+
 /* Initialize the fileline information from the executable.  Returns 1
    on success, 0 on failure.  */
 
@@ -168,7 +201,11 @@ fileline_initialize (struct backtrace_state *state,
   int called_error_callback;
   int descriptor;
   const char *filename;
+#ifdef HAVE_WINDOWS_H
+  char buf[MAX_PATH];
+#else
   char buf[64];
+#endif
 
   if (!state->threaded)
     failed = state->fileline_initialization_failed;
@@ -192,7 +229,7 @@ fileline_initialize (struct backtrace_state *state,
 
   descriptor = -1;
   called_error_callback = 0;
-  for (pass = 0; pass < 8; ++pass)
+  for (pass = 0; pass < 9; ++pass)
     {
       int does_not_exist;
 
@@ -224,6 +261,9 @@ fileline_initialize (struct backtrace_state *state,
 	case 7:
 	  filename = macho_get_executable_path (state, error_callback, data);
 	  break;
+	case 8:
+	  filename = windows_get_executable_path (buf, error_callback, data);
+	  break;
 	default:
 	  abort ();
 	}

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-24 17:58           ` Ian Lance Taylor
@ 2023-01-24 18:11             ` Eli Zaretskii
  2023-01-24 18:32               ` Ian Lance Taylor
  0 siblings, 1 reply; 17+ messages in thread
From: Eli Zaretskii @ 2023-01-24 18:11 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc, gcc-patches, gcc

> From: Ian Lance Taylor <iant@golang.org>
> Date: Tue, 24 Jan 2023 09:58:10 -0800
> Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
> 
> I'd rather that the patch look like the appended.  Can someone with a
> Windows system test to see what that builds and passes the tests?

ENOPATCH

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-24 16:52         ` Eli Zaretskii
@ 2023-01-24 17:58           ` Ian Lance Taylor
  2023-01-24 18:11             ` Eli Zaretskii
  2023-01-24 21:00           ` Björn Schäpers
  1 sibling, 1 reply; 17+ messages in thread
From: Ian Lance Taylor @ 2023-01-24 17:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gcc, gcc-patches, gcc

On Tue, Jan 24, 2023 at 8:53 AM Eli Zaretskii via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> > From: Ian Lance Taylor <iant@golang.org>
> > Date: Tue, 24 Jan 2023 06:35:21 -0800
> > Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
> >
> > > > On Windows it seems that MAX_PATH is not
> > > > a true limit, as an extended length path may be up to 32767 bytes.
> > >
> > > The limit of 32767 characters (not bytes, AFAIK) is only applicable
> > > when using the Unicode (a.k.a. "wide") versions of the Windows Win32
> > > APIs, see
> > >
> > >   https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
> > >
> > > Since the above code uses GetModuleFileNameA, which is an "ANSI"
> > > single-byte API, it is still subject to the MAX_PATH limitation, and
> > > MAX_PATH is defined as 260 on Windows headers.
> >
> > Thanks.  Should this code be using GetModuleFileNameW?  Or would that
> > mean that the later call to open will fail?
>
> We'd need to use _wopen or somesuch, and the file name will have to be
> a wchar_t array, not a char array, yes.  So this is not very practical
> when file names need to be passed between functions, unless they are
> converted to UTF-8 (and back again before using them in Windows APIs).
>
> And note that even then, the 260-byte limit could be lifted only if
> the user has a new enough Windows version _and_ has opted in to the
> long-name feature by turning it on in the Registry.  Otherwise, file
> names used in "wide" APIs can only break the 260-byte limit if they
> use the special format "\\?\D:\foo\bar", which means file names
> specified by user outside of the program or file names that come from
> other programs will need to be reformatted to this special format.
>
> > 260 bytes does not seem like very much for a path name these days.
>
> That's true.  But complications with using longer file names are still
> a PITA on Windows, even though they are a step closer to practically
> possible.


OK, thanks.

I'd rather that the patch look like the appended.  Can someone with a
Windows system test to see what that builds and passes the tests?
Thanks.

Ian

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-24 14:35       ` Ian Lance Taylor
@ 2023-01-24 16:52         ` Eli Zaretskii
  2023-01-24 17:58           ` Ian Lance Taylor
  2023-01-24 21:00           ` Björn Schäpers
  0 siblings, 2 replies; 17+ messages in thread
From: Eli Zaretskii @ 2023-01-24 16:52 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc, gcc-patches, gcc

> From: Ian Lance Taylor <iant@golang.org>
> Date: Tue, 24 Jan 2023 06:35:21 -0800
> Cc: gcc@hazardy.de, gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
> 
> > > On Windows it seems that MAX_PATH is not
> > > a true limit, as an extended length path may be up to 32767 bytes.
> >
> > The limit of 32767 characters (not bytes, AFAIK) is only applicable
> > when using the Unicode (a.k.a. "wide") versions of the Windows Win32
> > APIs, see
> >
> >   https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
> >
> > Since the above code uses GetModuleFileNameA, which is an "ANSI"
> > single-byte API, it is still subject to the MAX_PATH limitation, and
> > MAX_PATH is defined as 260 on Windows headers.
> 
> Thanks.  Should this code be using GetModuleFileNameW?  Or would that
> mean that the later call to open will fail?

We'd need to use _wopen or somesuch, and the file name will have to be
a wchar_t array, not a char array, yes.  So this is not very practical
when file names need to be passed between functions, unless they are
converted to UTF-8 (and back again before using them in Windows APIs).

And note that even then, the 260-byte limit could be lifted only if
the user has a new enough Windows version _and_ has opted in to the
long-name feature by turning it on in the Registry.  Otherwise, file
names used in "wide" APIs can only break the 260-byte limit if they
use the special format "\\?\D:\foo\bar", which means file names
specified by user outside of the program or file names that come from
other programs will need to be reformatted to this special format.

> 260 bytes does not seem like very much for a path name these days.

That's true.  But complications with using longer file names are still
a PITA on Windows, even though they are a step closer to practically
possible.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-24 13:11     ` Eli Zaretskii
@ 2023-01-24 14:35       ` Ian Lance Taylor
  2023-01-24 16:52         ` Eli Zaretskii
  0 siblings, 1 reply; 17+ messages in thread
From: Ian Lance Taylor @ 2023-01-24 14:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gcc, gcc-patches, gcc

On Tue, Jan 24, 2023 at 5:11 AM Eli Zaretskii via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> > Date: Mon, 23 Jan 2023 15:00:56 -0800
> > Cc: gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
> > From: Ian Lance Taylor via Gcc <gcc@gcc.gnu.org>
> >
> > > +#ifdef HAVE_WINDOWS_H
> > > +
> > > +static char *
> > > +windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
> > > +                            void *data)
> > > +{
> > > +  if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0)
> > > +    {
> > > +      error_callback (data,
> > > +                     "could not get the filename of the current executable",
> > > +                     (int) GetLastError ());
> > > +      return NULL;
> > > +    }
> > > +  return buf;
> > > +}
> >
> > Thanks, but this seems incomplete.  The docs for GetModuleFileNameA
> > say that if the pathname is too long to fit into the buffer it returns
> > the size of the buffer and sets the error to
> > ERROR_INSUFFICIENT_BUFFER.  It seems to me that in that case we should
> > allocate a larger buffer and try again.
>
> This is correct in general, but not in this particular case.
>
> > On Windows it seems that MAX_PATH is not
> > a true limit, as an extended length path may be up to 32767 bytes.
>
> The limit of 32767 characters (not bytes, AFAIK) is only applicable
> when using the Unicode (a.k.a. "wide") versions of the Windows Win32
> APIs, see
>
>   https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
>
> Since the above code uses GetModuleFileNameA, which is an "ANSI"
> single-byte API, it is still subject to the MAX_PATH limitation, and
> MAX_PATH is defined as 260 on Windows headers.

Thanks.  Should this code be using GetModuleFileNameW?  Or would that
mean that the later call to open will fail?

260 bytes does not seem like very much for a path name these days.

Ian

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-23 23:00   ` Ian Lance Taylor
@ 2023-01-24 13:11     ` Eli Zaretskii
  2023-01-24 14:35       ` Ian Lance Taylor
  0 siblings, 1 reply; 17+ messages in thread
From: Eli Zaretskii @ 2023-01-24 13:11 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc, gcc-patches, gcc

> Date: Mon, 23 Jan 2023 15:00:56 -0800
> Cc: gcc-patches@gcc.gnu.org, gcc@gcc.gnu.org
> From: Ian Lance Taylor via Gcc <gcc@gcc.gnu.org>
> 
> > +#ifdef HAVE_WINDOWS_H
> > +
> > +static char *
> > +windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
> > +                            void *data)
> > +{
> > +  if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0)
> > +    {
> > +      error_callback (data,
> > +                     "could not get the filename of the current executable",
> > +                     (int) GetLastError ());
> > +      return NULL;
> > +    }
> > +  return buf;
> > +}
> 
> Thanks, but this seems incomplete.  The docs for GetModuleFileNameA
> say that if the pathname is too long to fit into the buffer it returns
> the size of the buffer and sets the error to
> ERROR_INSUFFICIENT_BUFFER.  It seems to me that in that case we should
> allocate a larger buffer and try again.

This is correct in general, but not in this particular case.

> On Windows it seems that MAX_PATH is not
> a true limit, as an extended length path may be up to 32767 bytes.

The limit of 32767 characters (not bytes, AFAIK) is only applicable
when using the Unicode (a.k.a. "wide") versions of the Windows Win32
APIs, see

  https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation

Since the above code uses GetModuleFileNameA, which is an "ANSI"
single-byte API, it is still subject to the MAX_PATH limitation, and
MAX_PATH is defined as 260 on Windows headers.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-20 10:54 ` [PATCH 2/4] libbacktrace: detect executable path on windows Björn Schäpers
@ 2023-01-23 23:00   ` Ian Lance Taylor
  2023-01-24 13:11     ` Eli Zaretskii
  0 siblings, 1 reply; 17+ messages in thread
From: Ian Lance Taylor @ 2023-01-23 23:00 UTC (permalink / raw)
  To: Björn Schäpers; +Cc: gcc-patches, gcc

On Fri, Jan 20, 2023 at 2:56 AM Björn Schäpers <gcc@hazardy.de> wrote:
>
> From: Björn Schäpers <bjoern@hazardy.de>
>
> This is actually needed so that libstdc++'s <stacktrace> implementation
> to be able to work on windows.
>
> Tested on x86_64-linux and i686-w64-mingw32.
>
> -- >8 --
>
>         * configure.ac: Add a check for windows.h.
>         * configure, config.h.in: Regenerate.
>         * fileline.c: Add windows_get_executable_path.
>         * fileline.c (fileline_initialiez): Add a pass using
>         windows_get_executable_path.
>
> +#ifdef HAVE_WINDOWS_H
> +
> +static char *
> +windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
> +                            void *data)
> +{
> +  if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0)
> +    {
> +      error_callback (data,
> +                     "could not get the filename of the current executable",
> +                     (int) GetLastError ());
> +      return NULL;
> +    }
> +  return buf;
> +}

Thanks, but this seems incomplete.  The docs for GetModuleFileNameA
say that if the pathname is too long to fit into the buffer it returns
the size of the buffer and sets the error to
ERROR_INSUFFICIENT_BUFFER.  It seems to me that in that case we should
allocate a larger buffer and try again.  And, in general, it will be
simpler if we always allocate the buffer, as macho_get_executable_path
does.  Unfortunately it appears that Windows does not provide a way to
ask for the required length.  On Windows it seems that MAX_PATH is not
a true limit, as an extended length path may be up to 32767 bytes.

So probably something like (untested)

static char *
windows_get_executable_path (struct backtrace_state *state,
     backtrace_error_callback error_callback,
     void *data)
{
  uint32_t len;
  char *buf;

  len = MAX_PATH;
  while (1)
    {
      uint32_t got;

      name = (char *) backtrace_alloc (state, len, error_callback, data);
      if (name == NULL)
return NULL;
      got = GetModuleFileNameA (NULL, name, len);
      if (got < len - 1) /* -1 because NULB is not counted */
return name;
      backtrace_free (state, name, len, error_callback, data);
      if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
return NULL;
      len *= 2;
    }
}

Ian

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/4] libbacktrace: detect executable path on windows
  2023-01-20 10:54 [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t Björn Schäpers
@ 2023-01-20 10:54 ` Björn Schäpers
  2023-01-23 23:00   ` Ian Lance Taylor
  0 siblings, 1 reply; 17+ messages in thread
From: Björn Schäpers @ 2023-01-20 10:54 UTC (permalink / raw)
  To: gcc-patches, gcc

From: Björn Schäpers <bjoern@hazardy.de>

This is actually needed so that libstdc++'s <stacktrace> implementation
to be able to work on windows.

Tested on x86_64-linux and i686-w64-mingw32.

-- >8 --

	* configure.ac: Add a check for windows.h.
	* configure, config.h.in: Regenerate.
	* fileline.c: Add windows_get_executable_path.
	* fileline.c (fileline_initialiez): Add a pass using
	windows_get_executable_path.

Signed-off-by: Björn Schäpers <bjoern@hazardy.de>
---
 libbacktrace/config.h.in  |  3 +++
 libbacktrace/configure    | 13 ++++++++++++
 libbacktrace/configure.ac |  2 ++
 libbacktrace/fileline.c   | 43 ++++++++++++++++++++++++++++++++++++++-
 4 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index a21e2eaf525..355e820741b 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -100,6 +100,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
 /* Define if -lz is available. */
 #undef HAVE_ZLIB
 
diff --git a/libbacktrace/configure b/libbacktrace/configure
index a5bd133f4e4..ef677423733 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -13403,6 +13403,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h
 
 fi
 
+for ac_header in windows.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default"
+if test "x$ac_cv_header_windows_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_WINDOWS_H 1
+_ACEOF
+
+fi
+
+done
+
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 1daaa2f62d2..b5feb29bcdc 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -377,6 +377,8 @@ if test "$have_loadquery" = "yes"; then
   AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.])
 fi
 
+AC_CHECK_HEADERS(windows.h)
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index a40cd498114..73c2c8e8bc9 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include <mach-o/dyld.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#ifndef WIN32_MEAN_AND_LEAN
+#define WIN32_MEAN_AND_LEAN
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include <windows.h>
+#endif
+
 #include "backtrace.h"
 #include "internal.h"
 
@@ -155,6 +167,28 @@ macho_get_executable_path (struct backtrace_state *state,
 
 #endif /* !defined (HAVE_MACH_O_DYLD_H) */
 
+#ifdef HAVE_WINDOWS_H
+
+static char *
+windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
+			     void *data)
+{
+  if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0)
+    {
+      error_callback (data,
+		      "could not get the filename of the current executable",
+		      (int) GetLastError ());
+      return NULL;
+    }
+  return buf;
+}
+
+#else /* !defined (HAVE_WINDOWS_H) */
+
+#define windows_get_executable_path(buf, error_callback, data) NULL
+
+#endif /* !defined (HAVE_WINDOWS_H) */
+
 /* Initialize the fileline information from the executable.  Returns 1
    on success, 0 on failure.  */
 
@@ -168,7 +202,11 @@ fileline_initialize (struct backtrace_state *state,
   int called_error_callback;
   int descriptor;
   const char *filename;
+#ifdef HAVE_WINDOWS_H
+  char buf[MAX_PATH];
+#else
   char buf[64];
+#endif
 
   if (!state->threaded)
     failed = state->fileline_initialization_failed;
@@ -192,7 +230,7 @@ fileline_initialize (struct backtrace_state *state,
 
   descriptor = -1;
   called_error_callback = 0;
-  for (pass = 0; pass < 8; ++pass)
+  for (pass = 0; pass < 9; ++pass)
     {
       int does_not_exist;
 
@@ -224,6 +262,9 @@ fileline_initialize (struct backtrace_state *state,
 	case 7:
 	  filename = macho_get_executable_path (state, error_callback, data);
 	  break;
+	case 8:
+	  filename = windows_get_executable_path (buf, error_callback, data);
+	  break;
 	default:
 	  abort ();
 	}
-- 
2.38.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2023-11-29 22:05 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-06 19:50 [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t Björn Schäpers
2022-12-06 19:50 ` [PATCH 2/4] libbacktrace: detect executable path on windows Björn Schäpers
2022-12-06 19:50 ` [PATCH 3/4] libbacktrace: work with aslr " Björn Schäpers
2022-12-06 19:50 ` [PATCH 4/4] libbacktrace: get debug information for loaded dlls Björn Schäpers
2023-01-20 10:54 [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t Björn Schäpers
2023-01-20 10:54 ` [PATCH 2/4] libbacktrace: detect executable path on windows Björn Schäpers
2023-01-23 23:00   ` Ian Lance Taylor
2023-01-24 13:11     ` Eli Zaretskii
2023-01-24 14:35       ` Ian Lance Taylor
2023-01-24 16:52         ` Eli Zaretskii
2023-01-24 17:58           ` Ian Lance Taylor
2023-01-24 18:11             ` Eli Zaretskii
2023-01-24 18:32               ` Ian Lance Taylor
2023-02-05  9:20                 ` Björn Schäpers
2023-02-06  0:22                   ` Ian Lance Taylor
2023-11-20 19:56                     ` Björn Schäpers
2023-11-29 22:05                       ` Ian Lance Taylor
2023-01-24 21:00           ` Björn Schäpers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).