Bug 19487 - Result of call to __errno_location() is truncated to 32 bit on amd64
Summary: Result of call to __errno_location() is truncated to 32 bit on amd64
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: 7.10
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 19488 (view as bug list)
Depends on:
Blocks:
 
Reported: 2016-01-18 11:38 UTC by Ruslan
Modified: 2018-04-26 14:11 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ruslan 2016-01-18 11:38:34 UTC
Consider the following C program:

#include <stdio.h>
#include <errno.h>
int main()
{
    printf("%p\n",&errno);
}

If I run it in gdb, I get wrong results of attempt to print errno and even just its location. Here's the debugging session log:

-------------------------------------------------
$ gdb -q ./gdb-bug -ex 'b main' -ex r
Reading symbols from ./gdb-bug...(no debugging symbols found)...done.
Breakpoint 1 at 0x40059a
Starting program: /tmp/gdb-bug 

Breakpoint 1, 0x000000000040059a in main ()
(gdb) p/x __errno_location()
$1 = 0xf7fbf6a0
(gdb) p *__errno_location()
Cannot access memory at address 0xfffffffff7fbf6a0
(gdb) c
Continuing.
0x7ffff7fbf6a0
[Inferior 1 (process 869) exited normally]
----------------------------------------------------

See that "p/x" truncates the value to 32 bits, then "p *..." sign-extends the result of truncation, while on "c" we get actual value printed by the program itself, which is neither of the former two.
Comment 1 Ruslan 2016-01-18 11:39:58 UTC
*** Bug 19488 has been marked as a duplicate of this bug. ***
Comment 2 Pedro Alves 2016-01-18 15:32:04 UTC
What does:

 (gdb) ptype __errno_location 

say?  I think you'll get this if you don't have debug info for __errno_location, and then gdb assumes the function return "int" (not "int *").
Comment 3 Ruslan 2016-01-18 15:39:10 UTC
(In reply to Pedro Alves from comment #2)
> What does:
> 
>  (gdb) ptype __errno_location 
> 
> say?  I think you'll get this if you don't have debug info for
> __errno_location, and then gdb assumes the function return "int" (not "int
> *").

It says `type = int ()`, both with debug info ("gcc -g") and without.
Comment 4 Pedro Alves 2016-01-18 15:42:30 UTC
> both with debug info ("gcc -g") and without.

That sounds like debug info for your program.  __errno_location lives in glibc, so check if you have debug info for that.
Comment 5 Ruslan 2016-01-18 18:23:59 UTC
Tracing into __errno_location reveals that actual implementation is in __GI___errno_location, into which the _dl_runtime_resolve RETs. For __GI___errno_location I do have line numbers and file name showed. Still, for __errno_location the result is as it was, unlike for __GI___errno_location:

(gdb) ptype __errno_location
type = int ()
(gdb) ptype __GI___errno_location
type = int *(void)
Comment 6 Sourceware Commits 2017-08-21 10:37:12 UTC
The master branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=bf223d3e808e6fec9ee165d3d48beb74837796de

commit bf223d3e808e6fec9ee165d3d48beb74837796de
Author: Pedro Alves <palves@redhat.com>
Date:   Mon Aug 21 11:34:32 2017 +0100

    Handle function aliases better (PR gdb/19487, errno printing)
    
    (Ref: https://sourceware.org/ml/gdb/2017-06/msg00048.html)
    
    This patch improves GDB support for function aliases defined with
    __attribute__ alias.  For example, in the test added by this commit,
    there is no reference to "func_alias" in the debug info at all, only
    to "func"'s definition:
    
     $ nm  ./testsuite/outputs/gdb.base/symbol-alias/symbol-alias  | grep " func"
     00000000004005ae t func
     00000000004005ae T func_alias
    
     $ readelf -w ./testsuite/outputs/gdb.base/symbol-alias/symbol-alias | grep func -B 1 -A 8
     <1><db>: Abbrev Number: 5 (DW_TAG_subprogram)
        <dc>   DW_AT_name        : (indirect string, offset: 0x111): func
        <e0>   DW_AT_decl_file   : 1
        <e1>   DW_AT_decl_line   : 27
        <e2>   DW_AT_prototyped  : 1
        <e2>   DW_AT_type        : <0xf8>
        <e6>   DW_AT_low_pc      : 0x4005ae
        <ee>   DW_AT_high_pc     : 0xb
        <f6>   DW_AT_frame_base  : 1 byte block: 9c         (DW_OP_call_frame_cfa)
        <f8>   DW_AT_GNU_all_call_sites: 1
    
    So all GDB knows about "func_alias" is from the minsym (elf symbol):
    
     (gdb) p func_alias
     $1 = {<text variable, no debug info>} 0x4005ae <func>
     (gdb) ptype func_alias
     type = int ()
    
     (gdb) p func
     $2 = {struct S *(void)} 0x4005ae <func>
     (gdb) ptype func
     type = struct S {
         int field1;
         int field2;
     } *(void)
    
    The result is that calling func_alias from the command line produces
    incorrect results.
    
    This is similar (though not exactly the same) to the glibc
    errno/__errno_location/__GI___errno_location situation.  On glibc,
    errno is defined like this:
    
      extern int *__errno_location (void);
      #define errno (*__errno_location ())
    
    with __GI___errno_location being an internal alias for
    __errno_location.  On my system's libc (F23), I do see debug info for
    __errno_location, in the form of name vs linkage name:
    
     <1><95a5>: Abbrev Number: 18 (DW_TAG_subprogram)
        <95a6>   DW_AT_external    : 1
        <95a6>   DW_AT_name        : (indirect string, offset: 0x2c26): __errno_location
        <95aa>   DW_AT_decl_file   : 1
        <95ab>   DW_AT_decl_line   : 24
        <95ac>   DW_AT_linkage_name: (indirect string, offset: 0x2c21): __GI___errno_location
        <95b0>   DW_AT_prototyped  : 1
        <95b0>   DW_AT_type        : <0x9206>
        <95b4>   DW_AT_low_pc      : 0x20f40
        <95bc>   DW_AT_high_pc     : 0x11
        <95c4>   DW_AT_frame_base  : 1 byte block: 9c       (DW_OP_call_frame_cfa)
        <95c6>   DW_AT_GNU_all_call_sites: 1
    
    however that doesn't matter in practice, because GDB doesn't record
    demangled names anyway, and so we end up with the exact same situation
    covered by the testcase.
    
    So the fix is to make the expression parser find a debug symbol for
    the same address as the just-found minsym, when a lookup by name
    didn't find a debug symbol by name.  We now get:
    
     (gdb) p func_alias
     $1 = {struct S *(void)} 0x4005ae <func>
     (gdb) p __errno_location
     $2 = {int *(void)} 0x7ffff6e92830 <__errno_location>
    
    I've made the test exercise variable aliases too, for completeness.
    Those already work correctly, because unlike for function aliases, GCC
    emits debug information for variable aliases.
    
    Tested on GNU/Linux.
    
    gdb/ChangeLog:
    2017-08-21  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/19487
    	* c-exp.y (variable production): Handle function aliases.
    	* minsyms.c (msymbol_is_text): New function.
    	* minsyms.h (msymbol_is_text): Declare.
    	* symtab.c (find_function_alias_target): New function.
    	* symtab.h (find_function_alias_target): Declare.
    
    gdb/testsuite/ChangeLog:
    2017-08-21  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/19487
    	* gdb.base/symbol-alias.c: New.
    	* gdb.base/symbol-alias2.c: New.
    	* gdb.base/symbol-alias.exp: New.
Comment 7 Pedro Alves 2017-08-21 11:02:17 UTC
The original issue should be fixed, provided you have glibc debug
info installed.

There's a follow up series pending that will improve things further, by
stopping GDB from silently assuming that functions without debug info
have type "int ()":

 https://sourceware.org/ml/gdb-patches/2017-07/msg00137.html
Comment 8 Sourceware Commits 2018-04-26 12:16:32 UTC
The master branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a376e11d84ba7ea8cc7333c77043e20c7b0cfc91

commit a376e11d84ba7ea8cc7333c77043e20c7b0cfc91
Author: Pedro Alves <palves@redhat.com>
Date:   Thu Apr 26 13:01:26 2018 +0100

    Fix calling ifunc functions when resolver has debug info and different name
    
    Currently, on Fedora 27 (glibc 2.26), if you try to call strlen in the
    inferior you get:
    
     (gdb) p strlen ("hello")
     $1 = (size_t (*)(const char *)) 0x7ffff554aac0 <__strlen_avx2>
    
    strlen is an ifunc function, and what we see above is the result of
    calling the ifunc resolver in the inferior.  That returns a pointer to
    the actual target function that implements strlen on my machine.  GDB
    should have turned around and called the resolver automatically
    without the user noticing.
    
    This is was caused by commit:
    
      commit bf223d3e808e6fec9ee165d3d48beb74837796de
      Date: Mon Aug 21 11:34:32 2017 +0100
    
          Handle function aliases better (PR gdb/19487, errno printing)
    
    which added the find_function_alias_target call to c-exp.y, to try to
    find an alias with debug info for a minsym.  For ifunc symbols, that
    finds the ifunc's resolver if it has debug info (in the example it's
    called "strlen_ifunc"), with the result that GDB calls that as a
    regular function.
    
    After this commit, we get now get:
    
      (top-gdb) p strlen ("hello")
      '__strlen_avx2' has unknown return type; cast the call to its declared return type
    
    Which is correct, because __strlen_avx2 is written in assembly.
    That'll be improved in a following patch, though.
    
    gdb/ChangeLog:
    2018-04-26  Pedro Alves  <palves@redhat.com>
    
    	* c-exp.y (variable production): Skip finding an alias for ifunc
    	symbols.
Comment 9 Pedro Alves 2018-04-26 14:11:50 UTC
I think we can close this one now, the series pointed at by comment 7 above has been merged a while ago.