Use architecture-specific accessors to get information from the user_regs_struct, and treat the structure itself as an opaque cookie.
Code:
#if defined(__x86_64)
/* x86-64 user_regs_struct accessors:
*/
#define REG_IP_NAME "rip"
#define REG_IP_TYPE unsigned long
#define REG_IP_FMT "lu"
#define REG_IP_HEX "lx"
#define REG_IP_VALUE(r) ((r).rip)
#define REG_ALL_PATTERN "rip=0x%lx r15=0x%lx ... sp=0x%lx"
#define REG_ALL_VALUES(r) (r).rip, (r).r15, (r).sp
#elif defined(__i386)
/* x86 user_regs_struct accessors:
*/
#define REG_IP_NAME "ip"
#define REG_IP_TYPE unsigned long
#define REG_IP_FMT "lu"
#define REG_IP_HEX "lx"
#define REG_IP_VALUE(r) ((r).ip)
#define REG_ALL_PATTERN "ip=0x%lx ax=0x%lx ... sp=0x%lx"
#define REG_ALL_VALUES(r) (r).ip, (r).ax, (r).sp
#else
#error Unsupported architecture
#endif
/* Example: output the values of all generic registers to a string.
*/
static size_t generic_registers(char *const buffer, const size_t len, const struct user_regs_struct regs)
{
return snprintf(buffer, len, REG_ALL_PATTERN, REG_ALL_VALUES(regs));
}
These accessors are just examples. You may also wish to use static inline functions, but preprocessor macros let you use any type in your program.
If you need to modify the register values, then I recommend you create an array of all
logical register names categorized by type, the use an accessor function which returns a void pointer to that value in the user_regs_struct, and wrap it around a macro which dereferences the pointer using the correct type. (This way the macro is an lvalue.)
If you want a more detailed example, describe some of the actions you need to do wrt. the user_regs_struct, and I'd be happy to oblige.