diff mbox

GDB internal error in pc_in_thread_step_range

Message ID 8336qxfpjo.fsf@gnu.org
State New
Headers show

Commit Message

Eli Zaretskii Dec. 16, 2018, 3:40 p.m. UTC
> Cc: gdb-patches@sourceware.org
> From: Simon Marchi <simon.marchi@polymtl.ca>
> Date: Sat, 15 Dec 2018 22:57:57 -0500
> 
> Hi Eli,
> 
> Sorry for the wait.  I don't really have an good answer for you, but I thought I'd
> reply anyway, maybe this will help generate ideas.

Thanks for replying.

> >   if (address)
> >     {
> >       if (pc_in_unmapped_range (pc, section))
> > 	*address = overlay_unmapped_address (cache_pc_function_low, section);
> >       else
> > 	*address = cache_pc_function_low;
> >     }
> > 
> >   if (name)
> >     *name = cache_pc_function_name;
> > 
> >   if (endaddr)
> >     {
> >       if (pc_in_unmapped_range (pc, section))
> > 	{
> > 	  /* Because the high address is actually beyond the end of
> > 	     the function (and therefore possibly beyond the end of
> > 	     the overlay), we must actually convert (high - 1) and
> > 	     then add one to that.  */
> > 
> > 	  *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
> > 						   section);
> > 	}
> >       else
> > 	*endaddr = cache_pc_function_high;
> >     }
> > 
> > The cached values are zero and 1, correspondingly.
> 
> Do you mean that cache_pc_function_low is 0 and cache_pc_function_high is 1?

Yes.

> Do these values even make sense?

What else can we expect from a code at PC for which there's absolutely
no symbolic information?  So yes, I think it's reasonable, but I'm far
from being an expert on these parts of GDB.

> They are supposed to hold a range of program addresses, so 0 and 1
> seem bogus.  Maybe this is the result of something going wrong
> before?  It would be interesting to understand how they end up with
> these values.

They are assigned here:

  cache_pc_function_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
  cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
  cache_pc_function_section = section;
  cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
  cache_pc_function_block = nullptr;

This is part of find_pc_partial_function.  I verified that
minimal_symbol_upper_bound returns 1 in this case, and that this value
of 1 is assigned here:

  obj_section = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym);
  if (MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL
      && (MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i)
	  < obj_section_endaddr (obj_section)))
    result = MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i); <<<<<<
  else

Once again, I'm not an expert on this stuff, but just thinking about
the situation, what else could GDB return in this case?

> If find_pc_partial_function is unable to determine a proper symbol and some proper
> bounds, it should return 0.  So if it returns 1 but returns some wrong data,
> something is fishy.

If it returns zero, we will emit an error message:

	      if (find_pc_partial_function (pc, &name,
					    &tp->control.step_range_start,
					    &tp->control.step_range_end) == 0)
		error (_("Cannot find bounds of current function"));

So I'm not sure this is a good idea.  Instead, I propose the following
change:



Thanks.

Comments

Simon Marchi Dec. 16, 2018, 5:06 p.m. UTC | #1
On 2018-12-16 10:40 a.m., Eli Zaretskii wrote:
> What else can we expect from a code at PC for which there's absolutely
> no symbolic information?  So yes, I think it's reasonable, but I'm far
> from being an expert on these parts of GDB.

I can't see any mention or even clue that these values would have a special
meaning, it looks to me like they are returned by mistake more than on purpose.

>> They are supposed to hold a range of program addresses, so 0 and 1
>> seem bogus.  Maybe this is the result of something going wrong
>> before?  It would be interesting to understand how they end up with
>> these values.
> 
> They are assigned here:
> 
>   cache_pc_function_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
>   cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
>   cache_pc_function_section = section;
>   cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
>   cache_pc_function_block = nullptr;
> 
> This is part of find_pc_partial_function.  I verified that
> minimal_symbol_upper_bound returns 1 in this case, and that this value
> of 1 is assigned here:
> 
>   obj_section = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym);
>   if (MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL
>       && (MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i)
> 	  < obj_section_endaddr (obj_section)))
>     result = MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i); <<<<<<
>   else
> 
> Once again, I'm not an expert on this stuff, but just thinking about
> the situation, what else could GDB return in this case?

This means that BMSYMBOL_VALUE_ADDRESS (msymbol) returned 0?  What is that symbol?
How come by looking up a symbol for PC (what is PC's value, btw) we found this symbol?

>> If find_pc_partial_function is unable to determine a proper symbol and some proper
>> bounds, it should return 0.  So if it returns 1 but returns some wrong data,
>> something is fishy.
> 
> If it returns zero, we will emit an error message:
> 
> 	      if (find_pc_partial_function (pc, &name,
> 					    &tp->control.step_range_start,
> 					    &tp->control.step_range_end) == 0)
> 		error (_("Cannot find bounds of current function"));
> 
> So I'm not sure this is a good idea.

That sounds like a reasonable thing to happen if the user tries to use "step" and
we are not able to compute the function bounds.  The question is, are we really
unable to compute the function bounds, or are able, we are just messing it up.

The goal of find_pc_partial_function's ADDRESS and ENDADDR out parameters is to give
the range of the function PC is in.  If find_pc_partial_function returns "success" but
[ADDRESS,ENDADDR[ does not enclose PC, that really sounds like a bug to me, and this is
where I'd dig.

Instead, I propose the following
> change:
> 
> --- gdb/infrun.c~0	2018-07-04 18:41:59.000000000 +0300
> +++ gdb/infrun.c	2018-12-16 11:02:24.103425700 +0200
> @@ -2713,7 +2713,13 @@ resume_1 (enum gdb_signal sig)
>        displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
>      }
>  
> -  if (tp->control.may_range_step)
> +  if (tp->control.may_range_step
> +      /* If .step_range_start == 0 and .step_range_end == 1, we don't
> +	 really know the step range, so don't check in that case.
> +	 (This is known to happen on MinGW when stepping the program
> +	 epilogue code after 'main' returns.)  */
> +      && !(tp->control.step_range_start == 0x0
> +	   && tp->control.step_range_end == 0x1))
>      {
>        /* If we're resuming a thread with the PC out of the step
>  	 range, then we're doing some nested/finer run control

This is treating 0 and 1 as special values, which I don't think they are.

Simon
Eli Zaretskii Dec. 16, 2018, 5:22 p.m. UTC | #2
> Cc: gdb-patches@sourceware.org
> From: Simon Marchi <simon.marchi@polymtl.ca>
> Date: Sun, 16 Dec 2018 12:06:07 -0500
> 
> I can't see any mention or even clue that these values would have a special
> meaning, it looks to me like they are returned by mistake more than on purpose.

If the start address is zero and the length is zero, this is what we
will get, right?

> >   cache_pc_function_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
> >   cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
> >   cache_pc_function_section = section;
> >   cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
> >   cache_pc_function_block = nullptr;
> > 
> > This is part of find_pc_partial_function.  I verified that
> > minimal_symbol_upper_bound returns 1 in this case, and that this value
> > of 1 is assigned here:
> > 
> >   obj_section = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym);
> >   if (MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL
> >       && (MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i)
> > 	  < obj_section_endaddr (obj_section)))
> >     result = MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i); <<<<<<
> >   else
> > 
> > Once again, I'm not an expert on this stuff, but just thinking about
> > the situation, what else could GDB return in this case?
> 
> This means that BMSYMBOL_VALUE_ADDRESS (msymbol) returned 0?  What is that symbol?

Please help me understand what field of which struct do I need to show
to answer that question.  IOW, when you ask "what is that symbol",
what kind of answer do you expect me to provide?

> How come by looking up a symbol for PC (what is PC's value, btw) we found this symbol?

It comes from this loop, just before the above-mentioned snippet from
minimal_symbol_upper_bound:

  msymbol = minsym.minsym;
  section = MSYMBOL_SECTION (msymbol);
  for (i = 1; MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
    {
      if ((MSYMBOL_VALUE_RAW_ADDRESS (msymbol + i)
	   != MSYMBOL_VALUE_RAW_ADDRESS (msymbol))
	  && MSYMBOL_SECTION (msymbol + i) == section)
	break;
    }

> > --- gdb/infrun.c~0	2018-07-04 18:41:59.000000000 +0300
> > +++ gdb/infrun.c	2018-12-16 11:02:24.103425700 +0200
> > @@ -2713,7 +2713,13 @@ resume_1 (enum gdb_signal sig)
> >        displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
> >      }
> >  
> > -  if (tp->control.may_range_step)
> > +  if (tp->control.may_range_step
> > +      /* If .step_range_start == 0 and .step_range_end == 1, we don't
> > +	 really know the step range, so don't check in that case.
> > +	 (This is known to happen on MinGW when stepping the program
> > +	 epilogue code after 'main' returns.)  */
> > +      && !(tp->control.step_range_start == 0x0
> > +	   && tp->control.step_range_end == 0x1))
> >      {
> >        /* If we're resuming a thread with the PC out of the step
> >  	 range, then we're doing some nested/finer run control
> 
> This is treating 0 and 1 as special values, which I don't think they are.

It definitely looked to me as if they were special.  But I will try to
answer your other questions, maybe I was wrong.

Thanks.
Simon Marchi Dec. 16, 2018, 6:06 p.m. UTC | #3
On 2018-12-16 12:22 p.m., Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org
>> From: Simon Marchi <simon.marchi@polymtl.ca>
>> Date: Sun, 16 Dec 2018 12:06:07 -0500
>>
>> I can't see any mention or even clue that these values would have a special
>> meaning, it looks to me like they are returned by mistake more than on purpose.
> 
> If the start address is zero and the length is zero, this is what we
> will get, right?

Technically, I think this is what we would get if address was 0 and length 1.  If
address was 0 and length 0 (en empty range?), *ENDADDR would also be 0.

>>>   cache_pc_function_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
>>>   cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
>>>   cache_pc_function_section = section;
>>>   cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
>>>   cache_pc_function_block = nullptr;
>>>
>>> This is part of find_pc_partial_function.  I verified that
>>> minimal_symbol_upper_bound returns 1 in this case, and that this value
>>> of 1 is assigned here:
>>>
>>>   obj_section = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym);
>>>   if (MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL
>>>       && (MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i)
>>> 	  < obj_section_endaddr (obj_section)))
>>>     result = MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i); <<<<<<
>>>   else
>>>
>>> Once again, I'm not an expert on this stuff, but just thinking about
>>> the situation, what else could GDB return in this case?
>>
>> This means that BMSYMBOL_VALUE_ADDRESS (msymbol) returned 0?  What is that symbol?
> 
> Please help me understand what field of which struct do I need to show
> to answer that question.  IOW, when you ask "what is that symbol",
> what kind of answer do you expect me to provide?

In particular, I am looking for why we identified the symbol represented by MSYMBOL
as the function containing PC.  What is this symbol's name?  That would be printed
with MSYMBOL_LINKAGE_NAME(msymbol.minsym), I think.  Or if you expand,
"msymbol.minsym.mginfo.name".

What is its address (should be msymbol.minsym.mginfo.value.address)?

> 
>> How come by looking up a symbol for PC (what is PC's value, btw) we found this symbol?
> 
> It comes from this loop, just before the above-mentioned snippet from
> minimal_symbol_upper_bound:
> 
>   msymbol = minsym.minsym;
>   section = MSYMBOL_SECTION (msymbol);
>   for (i = 1; MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
>     {
>       if ((MSYMBOL_VALUE_RAW_ADDRESS (msymbol + i)
> 	   != MSYMBOL_VALUE_RAW_ADDRESS (msymbol))
> 	  && MSYMBOL_SECTION (msymbol + i) == section)
> 	break;
>     }

Actually, I think I would investigate this line in find_pc_partial_function:

  msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);

This is where we ask the question "which is the closest minimal symbol that is <= than PC".
I would then try to see if the returned msymbol makes sense.  If you can give its name and
address, it would be a good start.  If we find it doesn't make sense, I'd start looking at
why lookup_minimal_symbol_by_pc_section returned that.

I am not familiar with PE/Windows executables, but I would try to compare what I see there
with the output of "objdump -t" and "objdump -d" to see if the minimal symbols in GDB
correspond to something there.

>>> --- gdb/infrun.c~0	2018-07-04 18:41:59.000000000 +0300
>>> +++ gdb/infrun.c	2018-12-16 11:02:24.103425700 +0200
>>> @@ -2713,7 +2713,13 @@ resume_1 (enum gdb_signal sig)
>>>        displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
>>>      }
>>>  
>>> -  if (tp->control.may_range_step)
>>> +  if (tp->control.may_range_step
>>> +      /* If .step_range_start == 0 and .step_range_end == 1, we don't
>>> +	 really know the step range, so don't check in that case.
>>> +	 (This is known to happen on MinGW when stepping the program
>>> +	 epilogue code after 'main' returns.)  */
>>> +      && !(tp->control.step_range_start == 0x0
>>> +	   && tp->control.step_range_end == 0x1))
>>>      {
>>>        /* If we're resuming a thread with the PC out of the step
>>>  	 range, then we're doing some nested/finer run control
>>
>> This is treating 0 and 1 as special values, which I don't think they are.
> 
> It definitely looked to me as if they were special.  But I will try to
> answer your other questions, maybe I was wrong.

I think that for "absence of range", a 0/0 value would make more sense.  But that isn't
how find_pc_partial_function is documented to work:

   If it succeeds, it sets *NAME, *ADDRESS, and *ENDADDR to real
   information and returns 1.  If it fails, it sets *NAME, *ADDRESS
   and *ENDADDR to zero and returns 0.

find_pc_partial_function returns 1 in our case, and the information it returns in
*ADDRESS and *ENDADDR doesn't seem "real", as the comment says.

Also, if you read to complete comment of find_pc_partial_function (in symtab.h), it
reinforces the idea that the *ADDRESS <= PC < *ENDADDR invariant should hold.

Simon
Eli Zaretskii Dec. 19, 2018, 3:50 p.m. UTC | #4
> Cc: gdb-patches@sourceware.org
> From: Simon Marchi <simon.marchi@polymtl.ca>
> Date: Sun, 16 Dec 2018 13:06:27 -0500
> 
> >>>   cache_pc_function_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
> >>>   cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
> >>>   cache_pc_function_section = section;
> >>>   cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
> >>>   cache_pc_function_block = nullptr;
> >>>
> >>> This is part of find_pc_partial_function.  I verified that
> >>> minimal_symbol_upper_bound returns 1 in this case, and that this value
> >>> of 1 is assigned here:
> >>>
> >>>   obj_section = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym);
> >>>   if (MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL
> >>>       && (MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i)
> >>> 	  < obj_section_endaddr (obj_section)))
> >>>     result = MSYMBOL_VALUE_ADDRESS (minsym.objfile, msymbol + i); <<<<<<
> >>>   else
> >>>
> >>> Once again, I'm not an expert on this stuff, but just thinking about
> >>> the situation, what else could GDB return in this case?
> >>
> >> This means that BMSYMBOL_VALUE_ADDRESS (msymbol) returned 0?  What is that symbol?

The symbol is the one shown by GDB:

   0x0040126d in __register_frame_info ()
   Single stepping until exit from function __register_frame_info,
   which has no line number information.

Here it is as shown in the debugging session:

  227       msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
  (top-gdb)
  228       ALL_OBJFILES (objfile)
  (top-gdb) p msymbol
  $3 = {minsym = 0x10450d38, objfile = 0x10443b48}
  (top-gdb) p msymbol.minsym.mginfo.name
  $4 = 0x104485cd "__register_frame_info"
  (top-gdb) p msymbol.minsym.mginfo
  $5 = {name = 0x104485cd "__register_frame_info", value = {ivalue = 0,
      block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
      chain = 0x0}, language_specific = {obstack = 0x0, demangled_name = 0x0},
    language = language_auto, ada_mangled = 0, section = 0}

> In particular, I am looking for why we identified the symbol represented by MSYMBOL
> as the function containing PC.  What is this symbol's name?  That would be printed
> with MSYMBOL_LINKAGE_NAME(msymbol.minsym), I think.  Or if you expand,
> "msymbol.minsym.mginfo.name".
> 
> What is its address (should be msymbol.minsym.mginfo.value.address)?
> 
> > 
> >> How come by looking up a symbol for PC (what is PC's value, btw) we found this symbol?

That's because it's the symbol with the lowest address that satisfies
all the conditions in lookup_minimal_symbol_by_pc_section.  It goes
like this:

The loop which does a binary search through the minsyms finds the the
symbol immediately preceding the address of PC is this:

  (top-gdb) p newobj
  $28 = 26
  (top-gdb) p msymbol[newobj]
  $29 = {mginfo = {name = 0x10448845 "_image_base__", value = {
	ivalue = 4194304, block = 0x400000, bytes = 0x400000 "MZ\220",
	address = 0x400000, common_block = 0x400000, chain = 0x400000},
      language_specific = {obstack = 0x0, demangled_name = 0x0},
      language = language_auto, ada_mangled = 0, section = 0}, size = 0,
    filename = 0x0, type = mst_abs, created_by_gdb = 0, target_flag_1 = 0,
    target_flag_2 = 0, has_size = 0, hash_next = 0x0, demangled_hash_next = 0x0}

(our PC is 0x40126d).

Then this loop:

	      /* Skip various undesirable symbols.  */
	      while (hi >= 0)
		{

decrements 'hi' all the way down to 5, because all the preceding
symbols have the type mst_abs:

  (top-gdb) p hi
  $46 = 5
  (top-gdb) p msymbol[hi]
  $47 = {mginfo = {name = 0x1044858d "__register_frame_info", value = {
	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_text,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}

Note that this symbol's address is zero.  This symbol is then
returned, and so cache_pc_function_low becomes zero.  Then we get to
this:

   cache_pc_function_high = minimal_symbol_upper_bound (msymbol);

minimal_symbol_upper_bound then looks at the following symbols trying
to find the one whose address is different from zero:

  for (i = 1; MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
    {
      if ((MSYMBOL_VALUE_RAW_ADDRESS (msymbol + i)
	   != MSYMBOL_VALUE_RAW_ADDRESS (msymbol))
	  && MSYMBOL_SECTION (msymbol + i) == section)
	break;
    }

It finds such a symbol in the 10th entry:

  (top-gdb) p msymbol[1]
  $76 = {mginfo = {name = 0x10448a55 "__set_app_type", value = {ivalue = 0,
	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
	chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[2]
  $77 = {mginfo = {name = 0x104487ad "_dll__", value = {ivalue = 0,
	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
	chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[3]
  $78 = {mginfo = {name = 0x104483cd "_dll_characteristics__", value = {
	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[3]
  $79 = {mginfo = {name = 0x104483cd "_dll_characteristics__", value = {
	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[4]
  $80 = {mginfo = {name = 0x1044868d "_fpreset", value = {ivalue = 0,
	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
	chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[5]
  $81 = {mginfo = {name = 0x1044fead "_loader_flags__", value = {ivalue = 0,
	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
	chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[6]
  $82 = {mginfo = {name = 0x1044ff9d "_minor_image_version__", value = {
	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[7]
  $83 = {mginfo = {name = 0x104487cd "_minor_os_version__", value = {
	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[8]
  $84 = {mginfo = {name = 0x1044ff65 "_minor_subsystem_version__", value = {
	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[9]
  $85 = {mginfo = {name = 0x10448b35 "_rt_psrelocs_size", value = {ivalue = 0,
	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
	chain = 0x0}, language_specific = {obstack = 0x0,
	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
      section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}
  (top-gdb) p msymbol[10]
  $86 = {mginfo = {name = 0x1044fe8d "_major_image_version__", value = {
	ivalue = 1, block = 0x1,
	bytes = 0x1 <error: Cannot access memory at address 0x1>,
	address = 0x1, common_block = 0x1, chain = 0x1}, language_specific = {
	obstack = 0x0, demangled_name = 0x0}, language = language_auto,
      ada_mangled = 0, section = 0}, size = 0, filename = 0x0, type = mst_abs,
    created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size = 0,
    hash_next = 0x0, demangled_hash_next = 0x0}

And so cache_pc_function_high becomes 1.

> Actually, I think I would investigate this line in find_pc_partial_function:
> 
>   msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
> 
> This is where we ask the question "which is the closest minimal symbol that is <= than PC".
> I would then try to see if the returned msymbol makes sense.  If you can give its name and
> address, it would be a good start.  If we find it doesn't make sense, I'd start looking at
> why lookup_minimal_symbol_by_pc_section returned that.

That's what I did.  The problem seems to be that the low value of PC
doesn't allow GDB to find a reasonable symbol; what it finds are
symbols with very low addresses, which don't look like symbols
relevant to the issue at hand.  I see the same symbols and addresses
in the output of "objdump -t" (I can show it if you want).

Where do we go from here?

Thanks.
Simon Marchi Dec. 20, 2018, 12:16 a.m. UTC | #5
On 2018-12-19 10:50, Eli Zaretskii wrote:
> The symbol is the one shown by GDB:
> 
>    0x0040126d in __register_frame_info ()
>    Single stepping until exit from function __register_frame_info,
>    which has no line number information.
> 
> Here it is as shown in the debugging session:
> 
>   227       msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, 
> section);
>   (top-gdb)
>   228       ALL_OBJFILES (objfile)
>   (top-gdb) p msymbol
>   $3 = {minsym = 0x10450d38, objfile = 0x10443b48}
>   (top-gdb) p msymbol.minsym.mginfo.name
>   $4 = 0x104485cd "__register_frame_info"
>   (top-gdb) p msymbol.minsym.mginfo
>   $5 = {name = 0x104485cd "__register_frame_info", value = {ivalue = 0,
>       block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
>       chain = 0x0}, language_specific = {obstack = 0x0, demangled_name 
> = 0x0},
>     language = language_auto, ada_mangled = 0, section = 0}

Ok.  Well this is already strange.  Why is there an mst_text (code) 
symbol with a value of 0?  If your binary is anything like those I can 
produce with x86_64-w64-mingw32-gcc (and it looks similar, given the 
addresses you show), your "image base" is likely 0x400000, and "base of 
code" 0x1000 (0x401000 in absolute).  I found this information using 
"objdump -x", in the header somewhere.  I therefore expect all text 
symbols to be >= 0x401000.  I would start digging why this text symbol 
with a value of 0 exists.

It would be interesting to look at some other symbols in the msymbols 
vector.  Are the other mst_text symbols >= 0x401000?

When printing the symbols with "objdump -t", the addresses are also 
relative to 0x401000, but when they become minimal symbols in GDB, they 
are saved as the absolute address (e.g. a text symbol at 0x1c88 becomes 
0x401000).

Assuming this minimal symbol is wrong and assuming it wasn't there, then 
I guess the search would fail and we would fall in the "Cannot find 
bounds of current function" case of prepare_one_step?  That would be 
appropriate in this case.

>> In particular, I am looking for why we identified the symbol 
>> represented by MSYMBOL
>> as the function containing PC.  What is this symbol's name?  That 
>> would be printed
>> with MSYMBOL_LINKAGE_NAME(msymbol.minsym), I think.  Or if you expand,
>> "msymbol.minsym.mginfo.name".
>> 
>> What is its address (should be msymbol.minsym.mginfo.value.address)?
>> 
>> >
>> >> How come by looking up a symbol for PC (what is PC's value, btw) we found this symbol?
> 
> That's because it's the symbol with the lowest address that satisfies
> all the conditions in lookup_minimal_symbol_by_pc_section.  It goes
> like this:
> 
> The loop which does a binary search through the minsyms finds the the
> symbol immediately preceding the address of PC is this:
> 
>   (top-gdb) p newobj
>   $28 = 26
>   (top-gdb) p msymbol[newobj]
>   $29 = {mginfo = {name = 0x10448845 "_image_base__", value = {
> 	ivalue = 4194304, block = 0x400000, bytes = 0x400000 "MZ\220",
> 	address = 0x400000, common_block = 0x400000, chain = 0x400000},
>       language_specific = {obstack = 0x0, demangled_name = 0x0},
>       language = language_auto, ada_mangled = 0, section = 0}, size = 
> 0,
>     filename = 0x0, type = mst_abs, created_by_gdb = 0, target_flag_1 = 
> 0,
>     target_flag_2 = 0, has_size = 0, hash_next = 0x0, 
> demangled_hash_next = 0x0}
> 
> (our PC is 0x40126d).
> 
> Then this loop:
> 
> 	      /* Skip various undesirable symbols.  */
> 	      while (hi >= 0)
> 		{
> 
> decrements 'hi' all the way down to 5, because all the preceding
> symbols have the type mst_abs:
> 
>   (top-gdb) p hi
>   $46 = 5
>   (top-gdb) p msymbol[hi]
>   $47 = {mginfo = {name = 0x1044858d "__register_frame_info", value = {
> 	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
> 	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_text,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
> 
> Note that this symbol's address is zero.  This symbol is then
> returned, and so cache_pc_function_low becomes zero.  Then we get to
> this:
> 
>    cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
> 
> minimal_symbol_upper_bound then looks at the following symbols trying
> to find the one whose address is different from zero:
> 
>   for (i = 1; MSYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
>     {
>       if ((MSYMBOL_VALUE_RAW_ADDRESS (msymbol + i)
> 	   != MSYMBOL_VALUE_RAW_ADDRESS (msymbol))
> 	  && MSYMBOL_SECTION (msymbol + i) == section)
> 	break;
>     }
> 
> It finds such a symbol in the 10th entry:
> 
>   (top-gdb) p msymbol[1]
>   $76 = {mginfo = {name = 0x10448a55 "__set_app_type", value = {ivalue 
> = 0,
> 	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
> 	chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[2]
>   $77 = {mginfo = {name = 0x104487ad "_dll__", value = {ivalue = 0,
> 	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
> 	chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[3]
>   $78 = {mginfo = {name = 0x104483cd "_dll_characteristics__", value = 
> {
> 	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
> 	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[3]
>   $79 = {mginfo = {name = 0x104483cd "_dll_characteristics__", value = 
> {
> 	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
> 	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[4]
>   $80 = {mginfo = {name = 0x1044868d "_fpreset", value = {ivalue = 0,
> 	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
> 	chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[5]
>   $81 = {mginfo = {name = 0x1044fead "_loader_flags__", value = {ivalue 
> = 0,
> 	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
> 	chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[6]
>   $82 = {mginfo = {name = 0x1044ff9d "_minor_image_version__", value = 
> {
> 	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
> 	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[7]
>   $83 = {mginfo = {name = 0x104487cd "_minor_os_version__", value = {
> 	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
> 	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[8]
>   $84 = {mginfo = {name = 0x1044ff65 "_minor_subsystem_version__", 
> value = {
> 	ivalue = 0, block = 0x0, bytes = 0x0, address = 0x0,
> 	common_block = 0x0, chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[9]
>   $85 = {mginfo = {name = 0x10448b35 "_rt_psrelocs_size", value = 
> {ivalue = 0,
> 	block = 0x0, bytes = 0x0, address = 0x0, common_block = 0x0,
> 	chain = 0x0}, language_specific = {obstack = 0x0,
> 	demangled_name = 0x0}, language = language_auto, ada_mangled = 0,
>       section = 0}, size = 0, filename = 0x0, type = mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
>   (top-gdb) p msymbol[10]
>   $86 = {mginfo = {name = 0x1044fe8d "_major_image_version__", value = 
> {
> 	ivalue = 1, block = 0x1,
> 	bytes = 0x1 <error: Cannot access memory at address 0x1>,
> 	address = 0x1, common_block = 0x1, chain = 0x1}, language_specific = {
> 	obstack = 0x0, demangled_name = 0x0}, language = language_auto,
>       ada_mangled = 0, section = 0}, size = 0, filename = 0x0, type = 
> mst_abs,
>     created_by_gdb = 0, target_flag_1 = 0, target_flag_2 = 0, has_size 
> = 0,
>     hash_next = 0x0, demangled_hash_next = 0x0}
> 
> And so cache_pc_function_high becomes 1.

Ok, from what I understand, all these "mst_abs" symbols do not represent 
addresses.  They just represent numerical "values", like version 
numbers, alignment sizes, etc.  So it seems right to skip them when 
looking for the minimal symbol preceding pc.

It looks like minimal_symbol_upper_bound is buggy, in that it should not 
consider these mst_abs.  If we are looking for the end of a memory 
range, we should not consider those symbols that do not even represent 
memory addresses...

>> Actually, I think I would investigate this line in 
>> find_pc_partial_function:
>> 
>>   msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
>> 
>> This is where we ask the question "which is the closest minimal symbol 
>> that is <= than PC".
>> I would then try to see if the returned msymbol makes sense.  If you 
>> can give its name and
>> address, it would be a good start.  If we find it doesn't make sense, 
>> I'd start looking at
>> why lookup_minimal_symbol_by_pc_section returned that.
> 
> That's what I did.  The problem seems to be that the low value of PC
> doesn't allow GDB to find a reasonable symbol; what it finds are
> symbols with very low addresses, which don't look like symbols
> relevant to the issue at hand.  I see the same symbols and addresses
> in the output of "objdump -t" (I can show it if you want).

If you could pastebin it, or send it as an attachment, I think it would 
be useful.  Consider sending the output of "objdump -x", which I think 
gives a superset of "objdump -t".

> Where do we go from here?

I would say

1. investigate if the text symbol at address 0 really has business being 
there.
2. investigate if there should be some text symbol that should really 
contain 0x0040126d, that for some reason does not end up in GDB's 
minimal symbol table.

Simon
diff mbox

Patch

--- gdb/infrun.c~0	2018-07-04 18:41:59.000000000 +0300
+++ gdb/infrun.c	2018-12-16 11:02:24.103425700 +0200
@@ -2713,7 +2713,13 @@  resume_1 (enum gdb_signal sig)
       displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
     }
 
-  if (tp->control.may_range_step)
+  if (tp->control.may_range_step
+      /* If .step_range_start == 0 and .step_range_end == 1, we don't
+	 really know the step range, so don't check in that case.
+	 (This is known to happen on MinGW when stepping the program
+	 epilogue code after 'main' returns.)  */
+      && !(tp->control.step_range_start == 0x0
+	   && tp->control.step_range_end == 0x1))
     {
       /* If we're resuming a thread with the PC out of the step
 	 range, then we're doing some nested/finer run control