Skip to content

[PowerPC] missing CFI for ELF32 to unwind cr2, cr3, cr4 #83094

Closed
@kernigh

Description

@kernigh

For PowerPC ELF 32-bit targets, LLVM forgets to provide CFI like .cfi_offset cr2, -88 for fields cr2, cr3, cr4 in the condition register. Function calls must preserve cr2, cr3, cr4. Because the CFI is missing, an unwinder (like libunwind) can't restore cr2, cr3, cr4, when it unwinds a function call.

I found the bug after OpenBSD/macppc's clang 16.0.6 miscompiled gdb, when a C++ exception crashed gdb by not restoring cr2. I reproduced the bug in 19.0.0git with this example,

struct flip {
  int *p;
  flip(int *a): p(a) { if (p) *p = 1; }
  ~flip() { if (p) *p = 0; }
};
#define N __attribute__((noinline))
int i;
N void flip2(int *p) { flip f(p); throw 0; }
N void flip1(int *p) { flip f(p); flip2(&i); }
int main() { try { flip1(nullptr); } catch(int) {} }

I compiled it with clang++ -O2. The example is small enough to optimize out cr2; I added noinline to keep cr2 in the code. The functions flip1 and flip2 each use cr2 to test some pointer p, which is null in flip1 and non-null in flip2. The C++ exception from throw 0 unwinds flip2 without restoring cr2, then runs the C++ destructor ~flip in flip1 with a wrong cr2, so if (p) *p = 0 crashes by writing to a null p.

I will soon add a pull request.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions