#include "stdint.h"
int a, b, c;
int16_t func() {
int64_t l[4] = {0x5C253C716A15F506LL, 0x5C253C716A15F506LL,
0x5C253C716A15F506LL, 0x5C253C716A15F506LL};
c = l[0];
b = 6;
return c;
}
int main() {
func();
return 0;
}
(gdb) p l
$1 = {6639779683436459270, <synthetic pointer>, <synthetic pointer>, <synthetic pointer>}
(lldb) p l
(int64_t[4]) ([0] = 6639779683436459270, [1] = 0, [2] = 0, [3] = 0)
This intriguing code snippet is able to trigger three different bugs that are rooted in Clang, GDB, and LLDB repectively.
Clang: After communicating with Clang developer, he confirms that this bug is caused by Clang mistakenly putting the local array l into an anonymous global variable. Therefore, the globalopt deletes the rest part of this array and only keeps the referenced first elements.
LLDB: Despite Clang "mis-optimized" the elements of array l, LLDB is still expected to correctly output these values as <optimized-out> instead of giving out a misleading value of 0. This is presumably due to certain faulty handling regarding to DW_OP_piece of LLDB.
GDB: The developer of GDB promptly replied to us that this bug might come from a loose check in GDB. The check identifies whether a DWARF entry is an <synthetic pointer>. Moreover, an attempt to dereference such false synthetic pointers in the debugger directly leads to a crash.
#include "stdint.h"
int a, b = 9067;
volatile uint16_t *c = (volatile uint16_t*)&b;
int *d = &a;
int func_1() {
uint16_t e[7][2][8];
uint32_t f = 37455;
int32_t l;
a = 0;
l = *c * f;
*d = e[3][1][5]; /* error point */
return l;
}
int main() { func_1(); return 0; }
(gdb) p l
Incompatible types on DWARF stack
(lldb) p l
(uint32_t) $1 = 46522
The DWARF expression generated by Clang here is corrupted, which tries to multiply a generic typed value with an unsigned value.
This violates the type restriction specified in the DWARF standard.
#pragma pack(1)
struct {
unsigned : 6;
signed : 8;
signed : 27;
signed : 6;
unsigned b : 14;
signed : 4;
} c, d;
int d_1, e, f, k, aa, l, af, ag, ah, h, iab, i_5;
long m;
int main() {
int l_212;
int *r[42] = {&e, &l_212, &f, &e, &f, &f, &l_212, &e, &f, &l_212, &f};
l_212 = (m = (d.b |= 0) | 0); /* error point */
}
(gdb) p l
That operation is not available on integers of more than 8 bytes.
(lldb) p l
(uint32_t) $1 = 0
The root cause of this bug is that Clang generates a DWARF entry DW_OP_convert<DW_ATE_unsigned_72 [0x27]>, which exceeds the maximum length of primitive types (64-bit). Therefore, it must be evaluated using multi-precision arithmetic, which is not supported by GDB in the latest release version. Fortunately, this multi-precision arithmetic has been added to the development branch of GDB.
int a = 1;
int func() {
int i;
for (; i < 1; i++);
if (a) {
short b = 2; /* error point */
{ int i; }
}
}
int main() { func(); }
(gdb) p i
<optimized-out>
(lldb) p i
(uint32_t) $1 = 1
This bug is due to the fact that GDB picks the wrong variable i from the nested unused scope { int i; }.
int a = 0xdeadbeef, b;
int func() {
int *l = 0;
int **c = &l;
*c = &a;
b = 0; /* error point */
return a;
}
int main() { func(); }
(gdb) p/x *l
Cannot access memory at address 0x0
(lldb) p/x *l
(int) $1 = 0xdeadbeef
This is due to a faulty variable selection at the function entry point. GDB is supposed to perform an exhausted search for available DWARF entries, but it fails to do so at function entry points.
#include <stdio.h>
int main() {
static int S; /* error point */
printf("%d\n", S);
return 0;
}
(gdb) info locals
S = 0
(lldb) frame v
{Nothing listed}
(lldb) ta v
error: no global variables in current compile unit
We are working on locating the root cause of this issue.
Note that this is a rather common bug triggered in our test. We select a most simple error-triggering case here for demonstration purposes.
int a, b;
union {
short f0;
unsigned char f1;
int f2;
long f3;
} static g_55 = {255};
int c() {
char *d = (char*)&g_55;
*d = b;
return 0;
}
int main() { a = g_55.f1; } /* error point */
(gdb) p g_55.f1
$1 = 255 '\377'
(lldb) p g_55.f1
error: Couldn't materialize: couldn't get the value of variable g_55: failed to read memory DW_OP_piece(1) from file address 0x201028
In this case, despite the fact that Clang generates valid DWARF information about g_55, LLDB still cannot evaluate it.
This bug is due to a faulty evaluation on DW_OP_piece(1).
(gdb) b *main
(gdb) r
(gdb) si 22598
(gdb) p $pc
$1 = (void (*)()) 0x40113e <crc32_byte+8>
(gdb) p b
$2 = 35 '#'
(lldb) b &main
(lldb) r
(lldb) si -c 22598
(lldb) p/x $pc
(unsigned long) $1 = 0x40113e
(lldb) p b
error: Couldn't materialize: couldn't get the value of variable b: Could not evaluate DW_OP_entry_value.
We are working actively to reduce this case.
However, its characteristic is pretty straightforward; on the same pc, GDB can obtain the value of b while LLDB reports an error on DW_OP_entry_value.
int main(){
static int A = 11; /* error point */
static int S = 11;
return 0;
}
(gdb) p A
$1 = (int) 11
(gdb) p S
$2 = (int) 11
(lldb) p A
error: <lldb wrapper prefix>:45:31: no member named 'A' in namespace '$__lldb_local_vars' using $__lldb_local_vars::A;
(lldb) p S
error: <lldb wrapper prefix>:45:31: no member named 'S' in namespace '$__lldb_local_vars' using $__lldb_local_vars::S;
We are working on locating the root cause of this issue.
Note that this is a rather common bug triggered in our test. We select a most simple error-triggering case here for demonstration purposes.
#include "stdint.h"
struct a {
signed b : 2;
} c;
int d, e;
int f[1][10][10];
static int func_2(struct a g) {
int8_t h = -24;
uint64_t *i = (uint64_t*)&d;
int32_t *j = (uint32_t*)f;
int8_t *p;
int8_t **k = &p;
int32_t l = e = g.b | (*i = 9);
*j = (l = j && ((*k = &h) || 7) << f[1][2][7]) && *j; /* error point */
}
int main() { func_2(c); }
(gdb) p *p
$1 = -24
(lldb) p g_55.f1
error: error: Couldn't materialize: couldn't get the value of variable p: Could not evaluate DW_OP_implicit_pointer.
This bug is due to the fact that LLDB lacks the support for DW_OP_implicit_pointer, despite it being a legit part of the DWARFv5 standard, which is expected to be supported by LLDB.
int a;
volatile int b;
static int func_11(int b) {
int i = 0;
for (; i < 10; i++) {
int c;
continue;
}
a = 0; /* error point */
return 0;
}
int main() { func_11(b); }
(gdb) p i
$1 = 10
(lldb) p i
error: expression failed to parse:
error: <user expression 0>:1:1: use of undeclared identifier 'i'
This bug is due to the fact that LLDB does not correctly discard "empty ranges" in DWARF information, causing the variable i to be matched with one of these empty ranges.
#pragma pack(1)
struct {
signed f0 : 27;
unsigned f5 : 30;
} g = {5070, 1795821};
int main() {return 0;} /* error point */
(gdb) p g
$0 = (f0 = 5070, f5 = 1795821)
(lldb) p g
$0 = (f0 = 5070, f5 = 0)
This bug is due to the fact that LLDB uses an unsigned value to represent the offset of bitfields.
However, for bitfields that may have negative offset, e.g., f5 here. This causes an arithmetic underflow and leads to an unexpectedly large left shift being applied to the bitfield.
#include "stdint.h"
static volatile uint64_t g = 0;
static const int32_t f()
{
uint32_t i;
for (i = 0; (i != 10); i++)
++g; /* error point */
return 0;
}
int main()
{
f();
return 0;
}
(gdb) p i
$0 = 0
$1 = 1
$2 = 2
$3 = 3
(lldb) p i
$0 = 0
$1 = 1
$2 = 0
$3 = 0
The standard specifies that
The DW_OP_div operation pops the top two stack values, divides the former second entry by the former top of the stack using signed division, and pushes the result.
However, LLDB does not follow this, which causes an arithmetic underflow when evaluating DW_OP_div.
UPDATE:
Our fix for this issue has been landed on the latest LLDB build.
#include <stdio.h>
int a;
signed char b = -48;
static int func_12(int p_13) {
for (;a;) /* error point */
;
return 0;
}
int main() {
func_12(0 > b);
printf(0);
return 0;
}
(gdb) p i
$0 = 1
(lldb) p i
$0 = 0
Similar to Bug 13, this bug is also caused by a type system inconsistency between LLDB and the DWARF standard.
According to the standard, values represented via DW_OP_deref are of a generic type with unspecified signedness. However, LLDB does not support this type and treats values as unsigned by default, causing all values represented by this particular expression to be wrongly evaluated.
int a, b;
union {
short f0;
unsigned char f1;
int f2;
long f3;
} static g_55 = {65535};
int c() {
char *d = (char*)&g_55;
*d = b; /* error point */
return 0;
}
int main() { a = g_55.f1; } /* error point */
(gdb) p g_55.f1
$0 = 255
(lldb) p g_55.f1
error: Couldn't materialize: couldn't get the value of variable g_55: failed to read memory DW_OP_piece(1)
Clang discarded the members of the union except for the referenced f1. However, f1 is an unsigned char that can only hold values from 0 to 255.
Consequently, an incorrect value of 255 is kept in the debugging information.
static int a = 209, b;
int *volatile c = &b;
int d[5];
int g;
int func_5(int h) {
int e[5];
char l_96 = 82;
int f = 0;
for (; f < 5; f++)
e[f] |= h;
return 0;
}
int func_1() {
int f = 0;
for (; f < 4; f++)
d[f] = 4;
*c = a;
func_5(*c);
a = 3;
return 0;
}
int main() {
int argc = g = 1;
func_1();
}
18 func_5(*c);
(gdb) p l_96
$1 = 82 'R'
We can see that, despite GDB still displaying Line 18 "func_5(*c);" as the current line, which is right before func_5 is called, its frame is already inside func_5, where local variable l_96 is already visible.