llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.8k stars 11.91k forks source link

The sequence of step commands in LLDB is incorrect for a binary compiled with "-g -O1" #103931

Open edumoot opened 2 months ago

edumoot commented 2 months ago

The execution sequence of step commands is inaccurate. Initially, a breakpoint is set at line 26, and after executing the step command, it skips to line 58. When the step command is run again, it jumps back to line 32.

In LLVM18.1.8, we can reproduce with:

clang -g -O1 310.c -o 310_O1.out
lldb 310_O1.out
(lldb) b 26
(lldb) r
[...]
* thread #1, name = '310_O1.out', stop reason = breakpoint 1.1
    frame #0: 0x000055555555516c 310_O1.out`main [inlined] func_1 at 310.c:26:44
   23       int16_t l_56 = 0x3218L;
   24       for (int i = 0; i < 9; i++)
   25           l_2[i] = 1L;
-> 26       for (g_3[0] = 5; (g_3[0] >= 2); g_3[0] -= 1)
   27       { 
   28           uint8_t l_34 = 255UL;
   29           uint32_t l_35[1];
(lldb) s
Process 87168 stopped
* thread #1, name = '310_O1.out', stop reason = step in
    frame #0: 0x0000555555555140 310_O1.out`main at 310.c:58
   55   }
   56   
   57   int main (void)
-> 58   {   int i = 0;
   59       union U1 a = func_1();
   60       return i;
   61   }
(lldb) s
Process 87168 stopped
* thread #1, name = '310_O1.out', stop reason = step in
    frame #0: 0x0000555555555144 310_O1.out`main [inlined] func_1 at 310.c:32:16
   29           uint32_t l_35[1];
   30           for (int i = 0; i < 1; i++)
   31               l_35[i] = 2UL;
-> 32           l_56 = func_6(func_17(l_2[g_3[0] + 3], g_3[2]), l_34, l_35[0], l_56, l_28);        
   33       }
   34       (*g_39) ^= l_56;
   35       return g_58;
(lldb) s
Process 87168 stopped
* thread #1, name = '310_O1.out', stop reason = step in
    frame #0: 0x0000555555555144 310_O1.out`main [inlined] func_6(p_7=<unavailable>, p_8=<unavailable>, p_9=-25, p_10=<unavailable>, p_11=<unavailable>) at 310.c:58
   55   }
   56   
   57   int main (void)
-> 58   {   int i = 0;
   59       union U1 a = func_1();
   60       return i;
   61   }

cat 310.c

#include "stdint.h"

union U1 {
   uint32_t  f0;
   int8_t  f1;
};

static int32_t g_3[10] = {1L,0L,(-10L),(-10L),0L,1L,0L,(-10L),(-10L),0L};
static int32_t g_5 = 8L;
static int32_t g_40 = 1L;
static int32_t * volatile g_39 = &g_40;
static union U1 g_58 = {18446744073709551615UL};

static union U1  func_1(void);
static uint8_t  func_6(uint32_t  p_7, uint8_t  p_8, int16_t  p_9, int16_t  p_10, uint32_t  p_11);
static int16_t  func_17(int32_t  p_18, int32_t  p_19);

static union U1  func_1(void)
{ 
    int8_t l_2[9];
    int32_t l_28 = 0x1F4A1AB7L;
    int64_t l_55 = 0xE56B76AF746A6ECCLL;
    int16_t l_56 = 0x3218L;
    for (int i = 0; i < 9; i++)
        l_2[i] = 1L;
    for (g_3[0] = 5; (g_3[0] >= 2); g_3[0] -= 1)
    { 
        uint8_t l_34 = 255UL;
        uint32_t l_35[1];
        for (int i = 0; i < 1; i++)
            l_35[i] = 2UL;
        l_56 = func_6(func_17(l_2[g_3[0] + 3], g_3[2]), l_34, l_35[0], l_56, l_28);        
    }
    (*g_39) ^= l_56;
    return g_58;
}

static uint8_t  func_6(uint32_t  p_7, uint8_t  p_8, int16_t  p_9, int16_t  p_10, uint32_t  p_11)
{ 
    int8_t l_44 = 0x88L;
    for (p_9 = (-25); (p_9 < (-23)); ++p_9)
    { 
        int16_t l_38 = (-8L);
        int32_t *l_45 = &g_40;
        (*g_39) = l_38;
        (*l_45) = func_17(l_38, *l_45);
    }
    return l_44;
}

static int16_t  func_17(int32_t  p_18, int32_t  p_19)
{ 
    uint8_t l_21[5] = {0UL,0UL,0UL,0UL,0UL};
    return l_21[3];
}

int main (void)
{   int i = 0;
    i =func_1().f1;
    return i;
}
edumoot commented 2 months ago

This case has no problem in GDB context.

$ gdb 310_O1.out
(gdb) b 26
(gdb) r
[...]
Breakpoint 1, func_1 () at 310.c:26
26      for (g_3[0] = 5; (g_3[0] >= 2); g_3[0] -= 1)
(gdb) s
func_6 (p_9=-25, p_7=<optimised out>, p_8=<optimised out>, p_10=<optimised out>, p_11=<optimised out>) at 310.c:45
45          (*g_39) = l_38;
(gdb) s
46          (*l_45) = func_17(l_38, *l_45);
(gdb) s
41      for (p_9 = (-25); (p_9 < (-23)); ++p_9)
(gdb) s
45          (*g_39) = l_38;

$ gdb --version
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
llvmbot commented 2 months ago

@llvm/issue-subscribers-lldb

Author: Yachao Zhu (edumoot)

The execution sequence of step commands is inaccurate. Initially, a breakpoint is set at line 26, and after executing the step command, it skips to line 58. When the step command is run again, it jumps back to line 32. In LLVM18.1.8, we can reproduce with: ``` clang -g -O1 310.c -o 310_O1.out lldb 310_O1.out (lldb) b 26 (lldb) r [...] * thread #1, name = '310_O1.out', stop reason = breakpoint 1.1 frame #0: 0x000055555555516c 310_O1.out`main [inlined] func_1 at 310.c:26:44 23 int16_t l_56 = 0x3218L; 24 for (int i = 0; i < 9; i++) 25 l_2[i] = 1L; -> 26 for (g_3[0] = 5; (g_3[0] >= 2); g_3[0] -= 1) 27 { 28 uint8_t l_34 = 255UL; 29 uint32_t l_35[1]; (lldb) s Process 87168 stopped * thread #1, name = '310_O1.out', stop reason = step in frame #0: 0x0000555555555140 310_O1.out`main at 310.c:58 55 } 56 57 int main (void) -> 58 { int i = 0; 59 union U1 a = func_1(); 60 return i; 61 } (lldb) s Process 87168 stopped * thread #1, name = '310_O1.out', stop reason = step in frame #0: 0x0000555555555144 310_O1.out`main [inlined] func_1 at 310.c:32:16 29 uint32_t l_35[1]; 30 for (int i = 0; i < 1; i++) 31 l_35[i] = 2UL; -> 32 l_56 = func_6(func_17(l_2[g_3[0] + 3], g_3[2]), l_34, l_35[0], l_56, l_28); 33 } 34 (*g_39) ^= l_56; 35 return g_58; (lldb) s Process 87168 stopped * thread #1, name = '310_O1.out', stop reason = step in frame #0: 0x0000555555555144 310_O1.out`main [inlined] func_6(p_7=<unavailable>, p_8=<unavailable>, p_9=-25, p_10=<unavailable>, p_11=<unavailable>) at 310.c:58 55 } 56 57 int main (void) -> 58 { int i = 0; 59 union U1 a = func_1(); 60 return i; 61 } ``` `cat 310.c` ``` #include "stdint.h" union U1 { uint32_t f0; int8_t f1; }; static int32_t g_3[10] = {1L,0L,(-10L),(-10L),0L,1L,0L,(-10L),(-10L),0L}; static int32_t g_5 = 8L; static int32_t g_40 = 1L; static int32_t * volatile g_39 = &g_40; static union U1 g_58 = {18446744073709551615UL}; static union U1 func_1(void); static uint8_t func_6(uint32_t p_7, uint8_t p_8, int16_t p_9, int16_t p_10, uint32_t p_11); static int16_t func_17(int32_t p_18, int32_t p_19); static union U1 func_1(void) { int8_t l_2[9]; int32_t l_28 = 0x1F4A1AB7L; int64_t l_55 = 0xE56B76AF746A6ECCLL; int16_t l_56 = 0x3218L; for (int i = 0; i < 9; i++) l_2[i] = 1L; for (g_3[0] = 5; (g_3[0] >= 2); g_3[0] -= 1) { uint8_t l_34 = 255UL; uint32_t l_35[1]; for (int i = 0; i < 1; i++) l_35[i] = 2UL; l_56 = func_6(func_17(l_2[g_3[0] + 3], g_3[2]), l_34, l_35[0], l_56, l_28); } (*g_39) ^= l_56; return g_58; } static uint8_t func_6(uint32_t p_7, uint8_t p_8, int16_t p_9, int16_t p_10, uint32_t p_11) { int8_t l_44 = 0x88L; for (p_9 = (-25); (p_9 < (-23)); ++p_9) { int16_t l_38 = (-8L); int32_t *l_45 = &g_40; (*g_39) = l_38; (*l_45) = func_17(l_38, *l_45); } return l_44; } static int16_t func_17(int32_t p_18, int32_t p_19) { uint8_t l_21[5] = {0UL,0UL,0UL,0UL,0UL}; return l_21[3]; } int main (void) { int i = 0; i =func_1().f1; return i; } ```