mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2026-08-27 00:26:02 -04:00
Consider test.c:
...
1 namespace mod_a {
2 int xxx = 10;
3 }
4
5 static inline int __attribute__((always_inline))
6 inlined () {
7 return 0;
8 }
9
10 int main () {
11 using namespace mod_a;
12 int res = inlined ();
13 return res + xxx;
14 }
...
compiled with "g++ test.c -g".
Trying to print variable xxx at line 12 fails:
...
$ gdb -q -batch a.out -ex start -ex "p xxx"
...
Temporary breakpoint 1, main () at test.c:12
12 int res = inlined ();
No symbol "xxx" in current context.
...
The problem is here in function using_direct::valid_line:
...
CORE_ADDR curr_pc = get_frame_pc (get_selected_frame (nullptr));
symtab_and_line curr_sal = find_sal_for_pc (curr_pc, 0);
return (decl_line <= curr_sal.line)
|| (decl_line >= boundary);
...
where we're trying to decide whether "using namespace mod_a" is applicable.
The decl_line is 11, as expected.
If curr_sal.line were 12, decl_line <= curr_sal.line would be true, and
using_direct::valid_line would return true.
But instead, curr_sal.line is 7.
This is sort of correct, the current PC maps to that line. It's just that gdb
steps into inlined functions in two steps, each with identical PC:
- once stopping at the call site (line 12 in this case)
- once stopping at the PC line (line 7 in this case)
The function using_direct::valid_line doesn't apply this logic, and
consequently line 7 is used for both cases.
Fix this by using find_frame_sal instead.
Tested on x86_64-linux.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34201
128 lines
3.9 KiB
C
128 lines
3.9 KiB
C
/* Code dealing with "using" directives for GDB.
|
|
Copyright (C) 2003-2026 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "namespace.h"
|
|
#include "frame.h"
|
|
#include "symtab.h"
|
|
|
|
/* Add a using directive to USING_DIRECTIVES. If the using directive
|
|
in question has already been added, don't add it twice.
|
|
|
|
Create a new struct using_direct which imports the namespace SRC
|
|
into the scope DEST. ALIAS is the name of the imported namespace
|
|
in the current scope. If ALIAS is NULL then the namespace is known
|
|
by its original name. DECLARATION is the name if the imported
|
|
variable if this is a declaration import (Eg. using A::x),
|
|
otherwise it is NULL. EXCLUDES is a list of names not to import
|
|
from an imported module or NULL. For EXCLUDES the contents of the
|
|
vector are copied, but the pointed to characters are not
|
|
copied. */
|
|
|
|
void
|
|
add_using_directive (struct using_direct **using_directives,
|
|
const char *dest,
|
|
const char *src,
|
|
const char *alias,
|
|
const char *declaration,
|
|
const std::vector<const char *> &excludes,
|
|
unsigned int decl_line,
|
|
struct obstack *obstack)
|
|
{
|
|
struct using_direct *current;
|
|
struct using_direct *newobj;
|
|
int alloc_len;
|
|
|
|
/* Has it already been added? */
|
|
|
|
for (current = *using_directives; current != NULL; current = current->next)
|
|
{
|
|
int ix;
|
|
|
|
if (!streq (current->import_src, src))
|
|
continue;
|
|
if (!streq (current->import_dest, dest))
|
|
continue;
|
|
if ((alias == NULL && current->alias != NULL)
|
|
|| (alias != NULL && current->alias == NULL)
|
|
|| (alias != NULL && current->alias != NULL
|
|
&& !streq (alias, current->alias)))
|
|
continue;
|
|
if ((declaration == NULL && current->declaration != NULL)
|
|
|| (declaration != NULL && current->declaration == NULL)
|
|
|| (declaration != NULL && current->declaration != NULL
|
|
&& !streq (declaration, current->declaration)))
|
|
continue;
|
|
|
|
/* Compare the contents of EXCLUDES. */
|
|
for (ix = 0; ix < excludes.size (); ++ix)
|
|
if (current->excludes[ix] == NULL
|
|
|| !streq (excludes[ix], current->excludes[ix]))
|
|
break;
|
|
if (ix < excludes.size () || current->excludes[ix] != NULL)
|
|
continue;
|
|
|
|
if (decl_line != current->decl_line)
|
|
continue;
|
|
|
|
/* Parameters exactly match CURRENT. */
|
|
return;
|
|
}
|
|
|
|
alloc_len = (sizeof(*newobj)
|
|
+ (excludes.size () * sizeof(*newobj->excludes)));
|
|
newobj = (struct using_direct *) obstack_alloc (obstack, alloc_len);
|
|
memset (newobj, 0, sizeof (*newobj));
|
|
|
|
newobj->import_src = src;
|
|
newobj->import_dest = dest;
|
|
newobj->alias = alias;
|
|
newobj->declaration = declaration;
|
|
|
|
if (!excludes.empty ())
|
|
memcpy (newobj->excludes, excludes.data (),
|
|
excludes.size () * sizeof (*newobj->excludes));
|
|
newobj->excludes[excludes.size ()] = NULL;
|
|
|
|
newobj->decl_line = decl_line;
|
|
|
|
newobj->next = *using_directives;
|
|
*using_directives = newobj;
|
|
}
|
|
|
|
/* See namespace.h. */
|
|
|
|
bool
|
|
using_direct::valid_line (unsigned int boundary) const
|
|
{
|
|
try
|
|
{
|
|
frame_info_ptr frame = get_selected_frame ();
|
|
symtab_and_line curr_sal = find_frame_sal (frame);
|
|
|
|
/* Apply GCC PR debug/108716 workaround. */
|
|
if (boundary != 0
|
|
&& decl_line >= boundary)
|
|
return true;
|
|
|
|
return decl_line <= curr_sal.line;
|
|
}
|
|
catch (const gdb_exception &ex)
|
|
{
|
|
return true;
|
|
}
|
|
}
|