This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [OB PATCH] Frame static link: Handle null pointer.


> 2016-06-07  Bernhard Heckel  <bernhard.heckel@intel.com>
> 
> gdb/Changelog:
> 	* findvar.c (follow_static_link): Check for valid pointer.

I was going to approve the patch, but then commit the version I had,
because the revision log describes in detail what happens. But
unfortunately for me, the patch has already been pushed. So I'll
post the revision log here.

| Subject: crash trying to print value of variable from up-level scope
|
| One of our users reported a crash trying to print the value of
| his variable. All we got to work with was an executable and
| a core file, representing the program's state where, trying
| to print the variable, causes the error.
|
| What we have been able to determine is that the variable is not
| defined in the currently selected frame. Instead, the currently
| selected frame corresponds to a subprogram which is nested inside
| another, where I expect the variable to be defined. As a result,
| GDB tries to find the frame where this variable is defined, and
| for this, calls findvar.c::follow_static_link.
|
| This function goes up the frame chain until it finds the frame
| whose frame base is equal to the value given to us by the static
| link. While doing so, it encounters a function whose corresponding
| symbol has a NULL SYMBOL_BLOCK_OPS, which leads to a SEGV when
| trying to dereference it to get the get_frame_base function:
|
|     /* If we don't know how to compute FRAME's base address, don't give up:
|        maybe the frame we are looking for is upper in the stace frame.  */
|     if (framefunc != NULL
|         && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base != NULL
|         && (SYMBOL_BLOCK_OPS (framefunc)->get_frame_base (framefunc, frame)
|             == upper_frame_base))
|
| Looking at the function's debugging info, I can see that it does
| not have a DW_AT_frame_base attribute, probably because it is
| inlined. As a result, dwarf2_symbol_mark_computed does not get
| called:
|
|   /* If there is a location expression for DW_AT_frame_base, record
|      it.  */
|   attr = dwarf2_attr (die, DW_AT_frame_base, cu);
|   if (attr)
|     dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
|
| This means that the symbol we're building ends up keeping its default
| SYMBOL_ACLASS_INDEX (LOCK_BLOCK, see dwarf2read.c::new_symbol_full).
| This is the index that SYMBOL_BLOCK_OPS indirectly uses to get
| the associated block_ops:
|
|   SYMBOL_BLOCK_OPS resolves to:
|     -> SYMBOL_IMPL (symbol).ops_block, which resolves to:
|          -> symbol_impls[(symbol)->aclass_index].ops_block
|
| And since aclass_index (SYMBOL_ACLASS_INDEX) is still LOCK_BLOCK,
| we're using the first elements few elements of the symbol_impls
| array, which are initialized as follow:
|
|     /* Initialize elements of 'symbol_impl' for the constants in enum
|        address_class.  */
|
|     static void
|     initialize_ordinary_address_classes (void)
|     {
|       int i;
|
|       for (i = 0; i < LOC_FINAL_VALUE; ++i)
|         symbol_impl[i].aclass = (enum address_class) i;
|     }
|
| This is why SYMBOL_BLOCK_OPS(framefunc) is NULL in our case.
|
| This patch fixes the issue, by adding a SYMBOL_BLOCK_OPS != NULL
| check.
|
| gdb/ChangeLog:
|
|         * findvar.c (follow_static_link): Add SYMBOL_BLOCK_OPS != NULL
|         check before trying to access its get_frame_base field.
|
| Tested on x86_64-linux with both the FSF and the AdaCore gdb testsuite.
| No test, unfortunately, because despite a few hours of efforts trying
| to play with inlined subroutines, I was unable to create a reproducer.


-- 
Joel


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]