Bug 31563

Summary: Problems with accessing errno
Product: gdb Reporter: Kevin Buettner <kevinb>
Component: gdbAssignee: Kevin Buettner <kevinb>
Status: ASSIGNED ---    
Severity: normal CC: pedro, vries
Priority: P2    
Version: HEAD   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Attachments: C program for demonstrating problems w/ errno

Description Kevin Buettner 2024-03-27 02:10:18 UTC
Created attachment 15437 [details]
C program for demonstrating problems w/ errno

I am writing a new gdb test, gdb.base/check-errno.exp.  (Actually, it's a rewrite of an old test written by Jan Kratochvil from a while back, perhaps as far back as 2008.) The test compiles a simple program multiple times, each time using different compile flags. In some cases, GDB is able to print errno correctly and in other cases it does not. The program is named check-errno.c.

Here are the instances where GDB is unable to access errno:

1) -static:

kev@f39-1:ce$ gcc -static -g -o check-errno-static check-errno.c 
kev@f39-1:ce$ $GDB -q check-errno-static
Reading symbols from check-errno-static...
(gdb) b 24
Breakpoint 1 at 0x401794: file check-errno.c, line 24.
(gdb) run
Starting program: /tmp/ce/check-errno-static 

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.fedoraproject.org/>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
Downloading separate debug info for system-supplied DSO at 0x7ffff7ffd000
                                                                                
Breakpoint 1, main () at check-errno.c:24
24	  return 0;	/* breakpoint */
(gdb) p errno
Cannot find thread-local storage for process 14409, executable file /tmp/ce/check-errno-static:
Cannot find thread-local variables on this target

2) -static -g3:

kev@f39-1:ce$ gcc -static -g3 -o check-errno-static check-errno.c 
kev@f39-1:ce$ $GDB -q check-errno-static
Reading symbols from check-errno-static...
(gdb) b 24
Breakpoint 1 at 0x401794: file check-errno.c, line 24.
(gdb) run
Starting program: /tmp/ce/check-errno-static 

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.fedoraproject.org/>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.

Breakpoint 1, main () at check-errno.c:24
24	  return 0;	/* breakpoint */
(gdb) p errno
'__errno_location' has unknown return type; cast the call to its declared return type

3, 4) Same as above, but use gcore to make a core file for above two cases.

5) -lpthread -g3, from corefile:

kev@f39-1:ce$ gcc -lpthreads -g3 -o check-errno-pthreads-g3 check-errno.c 
/usr/bin/ld: cannot find -lpthreads: No such file or directory
collect2: error: ld returned 1 exit status
kev@f39-1:ce1$ gcc -lpthread -g3 -o check-errno-pthreads-g3 check-errno.c 
kev@f39-1:ce$ $GDB -q check-errno-pthreads-g3
Reading symbols from check-errno-pthreads-g3...
(gdb) b 24
Breakpoint 1 at 0x401135: file check-errno.c, line 24.
(gdb) run
Starting program: /tmp/ce/check-errno-pthreads-g3 

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.fedoraproject.org/>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, main () at check-errno.c:24
24	  return 0;	/* breakpoint */
(gdb) p errno
$1 = 42
(gdb) gcore check-errno-pthreads-gc.core
warning: Memory read failed for corefile section, 4096 bytes at 0xffffffffff600000.
Saved corefile check-errno-pthreads-gc.core
(gdb) core check-errno-pthreads-gc.core
A program is being debugged already.  Kill it? (y or n) y
[New LWP 14550]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `/tmp/ce/check-errno-pthreads-g3'.
Program terminated with signal SIGTRAP, Trace/breakpoint trap.
#0  main () at check-errno.c:24
24	  return 0;	/* breakpoint */
(gdb) p errno
You can't do that without a process to debug.

The above behavior was observed on Fedora 39, which is using the following version of gcc:

gcc (GCC) 13.2.1 20240316 (Red Hat 13.2.1-7)

Fedora GDB has a hack which causes errno to be printed correctly for each of these cases. However, IMO, it truly is a hack and is not acceptable for upstream.  I would like to figure out and fix (if possible) the root cause of each of the problems above so that the hack may be discarded.
Comment 1 Kevin Buettner 2024-03-27 02:10:59 UTC
I plan to look into these various errno problems...
Comment 2 Tom de Vries 2024-05-10 07:00:24 UTC
FWIW, this:
...
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 23d5652dd21..bf836c93152 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -1092,9 +1092,13 @@ call_function_by_hand_dummy (struct value *function,
     {
       const char *name = get_function_name (funaddr,
 					    name_buf, sizeof (name_buf));
-      error (_("'%s' has unknown return type; "
-	       "cast the call to its declared return type"),
-	     name);
+      if (gdbarch_osabi (gdbarch) == GDB_OSABI_LINUX
+	  && strcmp (name, "__errno_location") == 0)
+	values_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_int);
+      else
+	error (_("'%s' has unknown return type; "
+		 "cast the call to its declared return type"),
+	       name);
     }
 
   values_type = check_typedef (values_type);
...
gives a few xpasses on the new test-case:
...
XPASS: gdb.base/check-errno.exp: macros: print errno
XPASS: gdb.base/check-errno.exp: macros: print (int) errno
XPASS: gdb.base/check-errno.exp: pthreads-macros: print errno
XPASS: gdb.base/check-errno.exp: pthreads-macros: print (int) errno
...

But it's still a bit hacky, in the sense that it doesn't fix ptype __errno_location, in other words, it only has effect when doing an inferior call.
Comment 3 Pedro Alves 2024-05-10 10:56:03 UTC
The macro case should be fixed by adding the cast to the macro itself, IMNSHO.  I.e., with a patch to glibc's errno header to insert the explicit cast there.
Comment 4 Kevin Buettner 2024-05-10 20:10:53 UTC
Regarding the type of __errno_location...

When I run the test, compiled with -g3, on a machine without installed glibc debuginfo and also with debuginfod disabled, I see:

(gdb) p errno
'__errno_location' has unknown return type; cast the call to its declared return type

But, when I look at the DWARF for the binary, I see:

 <1><32>: Abbrev Number: 2 (DW_TAG_subprogram)
    <33>   DW_AT_external    : 1
    <33>   DW_AT_name        : (indirect string, offset: 0x1f7e): __errno_location
    <37>   DW_AT_decl_file   : 2
    <38>   DW_AT_decl_line   : 37
    <39>   DW_AT_decl_column : 13
    <3a>   DW_AT_prototyped  : 1
    <3a>   DW_AT_type        : <0x3e>
    <3e>   DW_AT_declaration : 1
 <1><3e>: Abbrev Number: 3 (DW_TAG_pointer_type)
    <3f>   DW_AT_byte_size   : 8
    <40>   DW_AT_type        : <0x44>
 <1><44>: Abbrev Number: 4 (DW_TAG_base_type)
    <45>   DW_AT_byte_size   : 4
    <46>   DW_AT_encoding    : 5	(signed)
    <47>   DW_AT_name        : int

So gdb could know the type if it didn't ignore it.  (It is ignored in read_func_scope in gdb/dwarf2/read.c due to not having low and high pc attributes.)
Comment 5 Pedro Alves 2024-05-13 15:05:10 UTC
Indeed.  It has no pc range because it's a declaration (DW_AT_declaration).


It would also be interesting to test accessing errno in a program that never references it.  Like:

int main()
{
  return 0; // stop here and access errno.
}

This models a program that actually calls some function that sets errno, but in a different translation unit, potentially even in a library, and then the user wants to inspect errno.

Does your testcase cover this scenario?


This reminded me of clang's -fstandalone-debug, which is on by default:

 https://clang.llvm.org/docs/UsersManual.html#cmdoption-fstandalone-debug

which I guess could also affect some of these scenarios.
Comment 6 Kevin Buettner 2024-05-14 03:00:48 UTC
(In reply to Pedro Alves from comment #5)

> It would also be interesting to test accessing errno in a program that never
> references it.  Like:
> 
> int main()
> {
>   return 0; // stop here and access errno.
> }
> 
> This models a program that actually calls some function that sets errno, but
> in a different translation unit, potentially even in a library, and then the
> user wants to inspect errno.
> 
> Does your testcase cover this scenario?

No.  I'd be inclined to write another/different test for that scenario.

Also, I think that such a test should make a library/system call since the above example need not provide access to errno.