Bug 20077 - gdb.Value string object has strlen of 1 after backtrace
Summary: gdb.Value string object has strlen of 1 after backtrace
Status: WAITING
Alias: None
Product: gdb
Classification: Unclassified
Component: python (show other bugs)
Version: 7.3
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-05-12 08:38 UTC by Kieran Bingham
Modified: 2023-11-24 13:29 UTC (History)
6 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 Kieran Bingham 2016-05-12 08:38:36 UTC
So this is an odd bug to reproduce.

As part of integrating extra debug commands into the Linux Kernel, we created an lx-version command. It's simple enough and just finds, and displays the version string from the kernel.

 http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/scripts/gdb/linux/proc.py

However, if you run a backtrace, before you use the python lx-version command, then the string returned prints only one character.
It actually has a strlen of 0 - but I traced through the gdb.Value code, and found that somewhere it gets +1 added to it, which means it prints just one char.


(gdb) bt
#0  cpu_v7_do_idle () at .../linux/arch/arm/mm/proc-v7.S:74
#1  0xc0308728 in arch_cpu_idle () at .../linux/arch/arm/kernel/process.c:72
#2  0xc0376b28 in cpuidle_idle_call () at .../linux/kernel/sched/idle.c:151
#3  cpu_idle_loop () at .../linux/kernel/sched/idle.c:242
#4  cpu_startup_entry (state=<optimized out>) at .../linux/kernel/sched/idle.c:291
#5  0xc0ae8a30 in rest_init () at .../linux/init/main.c:408
#6  0xc0f00c5c in start_kernel () at .../linux/init/main.c:661
#7  0x8020807c in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) lx-version 
L(gdb) print linux_banner       #### Note the 'L' at the beginning of the line ####
$1 = 0xc0b00074 <linux_banner> "Linux version 4.6.0-rc1 (kbingham@CookieMonster) (gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu1) ) #13 SMP Thu Mar 31 10:33:19 BST 2016\n"
(gdb) print &linux_banner
$2 = (const char (*)[]) 0xc0b00074 <linux_banner>
(gdb) lx-version 
L(gdb) 

If however, upon connecting to the target, you run 'lx-version', *then* 'bt', both operate as expected.
Perhaps the string / value gets cached somewhere?

/me is puzzled :D
Comment 1 Pedro Alves 2016-08-08 23:01:28 UTC
Did you ever find out what's going on?
Comment 2 Kieran Bingham 2016-08-13 09:18:59 UTC
Hi Pedro,

No we never did quite get to the bottom of this.

I'm afraid I'm on honeymoon now so apologies for the delays,  I'll find you on IRC when I'm back and we can see what we can do to get this resolved or at least understand the root cause.
Comment 3 Peter Griffin 2016-08-25 14:40:55 UTC
Hi,

I just entered this bug in the Linaro GDB bugzilla, in the hope that somebody in the Linaro toolchain working group will have some time to debug this issue.

Unfortunately I haven't had time to debug it further, as I'm busy trying to prepare the linux-kthread GDB patches to send to the ML.

Pete.
Comment 4 Tom Tromey 2018-09-15 05:38:19 UTC
Does this still happen?
Comment 5 Kieran Bingham 2018-09-17 19:06:44 UTC
Hi Tom,

It's a long time since I've tried this.

I'll try to see if I can recreate this issue this week.
Please ping me, either here or on IRC if it slips my radar.
--
Kieran
Comment 6 Kieran Bingham 2018-10-17 12:36:25 UTC
So I've been sent a patch that simply adds a cast to the string pointer here, to workaround this issue.

In the patch - the submitter describes this issue as only happening on GBD 7.3 and below.

https://lore.kernel.org/lkml/20181017023652.6867-1-changbin.du@gmail.com/t/#u

I'm afraid I haven't been able to find time to replicate this issue again yet. But if it's not causing problems in mainline GDB then I don't think there's much action to take.

We'll likely apply the cast patch to the linux kernel command to support older versions if it works. It should be 'forwards' compatible.
Comment 7 Kieran Bingham 2018-10-25 09:09:50 UTC
So this issue is still present in mainline GDB.

The following thread [0] shows the workaround which will handle this for us. But the bug might still be interesting for someone to investigate: 

[0] https://lkml.org/lkml/2018/10/17/798
Comment 8 Hannes Domani 2023-11-24 13:29:23 UTC
There are 2 different declarations of the linux_banner variable:

https://github.com/torvalds/linux/blob/master/init/version.c#L50:

const char linux_banner[] __weak;

https://github.com/torvalds/linux/blob/master/init/version-timestamp.c#L28-L30:

const char linux_banner[] =
	"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
	LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";


We can try this ourselves with this reproducer:

main.c:
```

int part1();
int part2();

int main()
{
  int sum = part1();
  sum += part2();
  return sum;
}
```

part1.c:
```

const char linux_banner[] __attribute__((weak));

int part1()
{
  return 1;
}
```

part2.c:
```

const char linux_banner[] = "Linux version 1.2.3.4";

int part2()
{
  return 2;
}
```

$ gcc -g -o example main.c part1.c part2.c


Depending on the declaration that was last 'used', this gives different results.

With a breakpoint in part1.c with the weak declaration:
```
$ gdb -q example.exe
Reading symbols from example.exe...
(gdb) b part1
Breakpoint 1 at 0x140001634: file part1.c, line 6, column 10.
(gdb) b 9
Breakpoint 2 at 0x14000161d: file main.c, line 9, column 10.
(gdb) r
Starting program: C:\src\tests\example.exe

Breakpoint 1, part1 () at part1.c:6
6         return 1;
                 ^
(gdb) c
Continuing.

Breakpoint 2, main () at main.c:9
9         return sum;
                 ^
(gdb) py print(repr(gdb.parse_and_eval("linux_banner").string()))
''
(gdb) pt linux_banner
type = const char []
```


With a breakpoint in part2.c with the full declaration:
```
$ gdb -q example.exe
Reading symbols from example.exe...
(gdb) b part2
Breakpoint 1 at 0x140001644: file part2.c, line 6, column 10.
(gdb) b 9
Breakpoint 2 at 0x14000161d: file main.c, line 9, column 10.
(gdb) r
Starting program: C:\src\tests\example.exe

Breakpoint 1, part2 () at part2.c:6
6         return 2;
                 ^
(gdb) c
Continuing.

Breakpoint 2, main () at main.c:9
9         return sum;
                 ^
(gdb) py print(repr(gdb.parse_and_eval("linux_banner").string()))
'Linux version 1.2.3.4'
(gdb) pt linux_banner
type = const char [22]
```