Issue |
96401
|
Summary |
[lldb] `finish` doesn't work well with sanitizer coverage and if-else-chains.
|
Labels |
new issue
|
Assignees |
|
Reporter |
mvanotti
|
I'm trying to run the debugger on a program that was compiled with `-fsanitize-coverage=bb,no-prune,trace-pc-guard`, and I want to step-out of all the calls to `__sanitizer_cov_trace_pc_guard`.
I've found that when I attempt to do a `finish` in the `else` case of an `if` with an `else if` clause, lldb gets confused.
See the following example:
```c++
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/random.h>
[[clang::noinline]] void foo(void) {
uint64_t random_num = 0;
ssize_t res = getrandom(&random_num, sizeof(random_num), 0);
assert(res != -1);
assert(static_cast<size_t>(res) == sizeof(random_num));
if (random_num == UINT64_MAX) {
__asm__ volatile("nop");
} else if (random_num == 0) {
__asm__ volatile("nop");
} else if (random_num == 1) {
__asm__ volatile("nop");
} else {
__asm__ volatile("pause");
}
}
int main(void) {
foo();
fprintf(stderr,
"If we are single-stepping, we should have a stop here on main.\n");
return 0;
}
extern "C" [[clang::noinline]] void __sanitizer_cov_trace_pc_guard(uint32_t *) {
// Do (almost) nothing!
__asm__ volatile("pause");
}
extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t *, uint32_t *) {}
```
Compiled with:
```
$ clang++ -Wall -Wextra -pedantic -std=c++17 -gdwarf-5 -O0 -fsanitize-coverage=bb,no-prune,trace-pc-guard program.cc -o program
```
Running it under lldb, single stepping, and calling `finish` each time we are in `__sanitizer_cov_trace_pc_guard`:
```
(lldb) target create "./program"
Current executable set to '/home/user/lldb-test/program' (x86_64).
(lldb) breakpoint set --file program.cc --line 21
Breakpoint 1: where = program`foo() + 369 at program.cc:21:5, address = 0x000000000002e631
(lldb) run
Process 3612485 launched: '/home/user/lldb-test/program' (x86_64)
Process 3612485 stopped
* thread #1, name = 'program', stop reason = breakpoint 1.1
frame #0: 0x0000555555582631 program`foo() at program.cc:21:5
18 } else if (random_num == 1) {
19 __asm__ volatile("nop");
20 } else {
-> 21 __asm__ volatile("pause");
22 }
23 }
24
(lldb) s
Process 3612485 stopped
* thread #1, name = 'program', stop reason = step in
frame #0: 0x00005555555824a8 program`__sanitizer_cov_trace_pc_guard((null)=0x0000555555599b50) at program.cc:33:3
30 }
31
32 extern "C" [[clang::noinline]] void __sanitizer_cov_trace_pc_guard(uint32_t *) {
-> 33 // Do (almost) nothing!
34 __asm__ volatile("pause");
35 }
36
(lldb) finish
Process 3612485 stopped
* thread #1, name = 'program', stop reason = step out
frame #0: 0x0000555555582641 program`foo() at program.cc:21:5
18 } else if (random_num == 1) {
19 __asm__ volatile("nop");
20 } else {
-> 21 __asm__ volatile("pause");
22 }
23 }
24
(lldb) s
Process 3612485 stopped
* thread #1, name = 'program', stop reason = step in
frame #0: 0x00005555555824a8 program`__sanitizer_cov_trace_pc_guard((null)=0x0000555555599b54) at program.cc:33:3
30 }
31
32 extern "C" [[clang::noinline]] void __sanitizer_cov_trace_pc_guard(uint32_t *) {
-> 33 // Do (almost) nothing!
34 __asm__ volatile("pause");
35 }
36
(lldb) finish
If we are single-stepping, we should have a stop here on main.
Process 3612485 exited with status = 0 (0x00000000)
(lldb)
```
The outcome is less than ideal: instead of executing until the end of `__sanitizer_cov_trace_pc_guard`, the program executes until the end of the program.
Here is a python script that replicates this behavior (this is how I initially observed the issue):
```python
#!/usr/bin/python3
import lldb
import os
def main():
debugger = lldb.SBDebugger.Create()
debugger.SetAsync(False)
target_prog = './program'
argv = []
envp = []
target = debugger.CreateTargetWithFileAndArch(
target_prog, lldb.LLDB_ARCH_DEFAULT_64BIT
)
assert target.IsValid()
bp = target.BreakpointCreateByName('main')
error = lldb.SBError()
process = target.Launch(
debugger.GetListener(),
argv,
envp,
None,
None,
None,
os.getcwd(),
0, # launch_flags
False, # stop_at_entry
error,
)
assert error.Success(), error
traced_functions = set(['main', 'foo()'])
while process.GetState() == lldb.eStateStopped:
assert len(process.threads) == 1
thread = process.threads[0]
assert thread.IsValid()
frames = thread.get_thread_frames()
assert frames
frame = frames[0]
assert frame.IsValid()
func_name = frame.function.name
if func_name not in traced_functions:
print(f'Stepping out of function {func_name}')
thread.StepOutOfFrame(frame)
continue
print(f'Func {func_name:>10} | Location {os.path.basename(str(frame.line_entry.file)):>10}:{frame.line_entry.line:>3} | pc @ {hex(frame.pc)}')
thread.StepInto()
if __name__ == '__main__':
main()
```
Output:
```
Func main | Location program.cc: 25 | pc @ 0x555555582688
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func main | Location program.cc: 25 | pc @ 0x555555582694
Func main | Location program.cc: 26 | pc @ 0x55555558269b
Func foo() | Location program.cc: 8 | pc @ 0x5555555824c8
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 9 | pc @ 0x5555555824d4
Func foo() | Location program.cc: 10 | pc @ 0x5555555824dc
Stepping out of function __GI___getrandom
Func foo() | Location program.cc: 10 | pc @ 0x5555555824ec
Func foo() | Location program.cc: 11 | pc @ 0x5555555824f0
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 11 | pc @ 0x55555558250b
Func foo() | Location program.cc: 12 | pc @ 0x55555558253f
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 12 | pc @ 0x55555558254f
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 12 | pc @ 0x55555558256a
Func foo() | Location program.cc: 14 | pc @ 0x55555558259e
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 14 | pc @ 0x5555555825ae
Func foo() | Location program.cc: 16 | pc @ 0x5555555825cf
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 16 | pc @ 0x5555555825df
Func foo() | Location program.cc: 18 | pc @ 0x555555582600
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 18 | pc @ 0x555555582610
Func foo() | Location program.cc: 21 | pc @ 0x555555582631
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
Func foo() | Location program.cc: 21 | pc @ 0x555555582641
Stepping out of function ::__sanitizer_cov_trace_pc_guard(uint32_t *)
```
I haven't tried this with the `lldb` version at trunk yet, will report back once I do.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs