The old code was wrong as uc_regs is not a registers array, but rather an mcontext_t pointer on glibc, therefore indexing it goes way past the memory bounds. The actual registers array is gregs inside the mcontext_t structure.
On non-glibc libcs (as well as inside the kernel headers that are the reference), the structure is defined differently, with uc_mcontext being an actual value member just like on ppc64, so we can use that. On glibc/ppc32, mcontext_t is an union of uc_regs and regs pointers, with the value of the member being a pointer to where the real uc_mcontext field would be.
Basically, this is how the structure looks like in the kernel as well as on musl etc:
typedef struct {
gregset_t gregs;
fpregset_t fpregs;
vrregset_t vrregs;
} mcontext_t;
typedef struct {
... some fields ...
mcontext_t *uc_regs; /* this is set to &ctx->uc_mcontext */
... more fields ....
int __pad[3];
mcontext_t uc_mcontext;
} ucontext_t;
on glibc the layout is broken, supposedly for compatibility with extremely ancient kernels (think pre-2.4 series) and looks like this instead:
typedef struct {
... some fields ...
union {
mcontext_t *uc_regs; /* this is set to &ctx->__pad */
struct pt_regs *regs;
} uc_mcontext;
... more fields ....
char __pre_pad[12];
char __pad[sizeof(mcontext_t)]; /* this would normally be uc_mcontext */
} ucontext_t;
The old code was wrong as
uc_regs
is not a registers array, but rather anmcontext_t
pointer on glibc, therefore indexing it goes way past the memory bounds. The actual registers array isgregs
inside themcontext_t
structure.On non-glibc libcs (as well as inside the kernel headers that are the reference), the structure is defined differently, with
uc_mcontext
being an actual value member just like on ppc64, so we can use that. On glibc/ppc32,mcontext_t
is an union ofuc_regs
andregs
pointers, with the value of the member being a pointer to where the realuc_mcontext
field would be.Basically, this is how the structure looks like in the kernel as well as on
musl
etc:on glibc the layout is broken, supposedly for compatibility with extremely ancient kernels (think pre-2.4 series) and looks like this instead: