diff --git a/src/client/linux/dump_writer_common/raw_context_cpu.h b/src/client/linux/dump_writer_common/raw_context_cpu.h index e2ef45d..805971e 100644 --- a/src/client/linux/dump_writer_common/raw_context_cpu.h +++ b/src/client/linux/dump_writer_common/raw_context_cpu.h @@ -44,6 +44,13 @@ typedef MDRawContextARM RawContextCPU; typedef MDRawContextARM64 RawContextCPU; #elif defined(__mips__) typedef MDRawContextMIPS RawContextCPU; +#elif defined(__PPC64__) +/* Most of the PPC-specific changes in breakpad's source code are referred from + Commit - https://github.com/ibmsoe/phantomjs/commit/2867533b02b6407523deb0c603673142c3f8c1b1 + Repo - https://github.com/ibmsoe/phantomjs + Done by - Ayappan P (github_id: ayappanec) +*/ +typedef MDRawContextPPC RawContextCPU; #else #error "This code has not been ported to your platform yet." #endif diff --git a/src/client/linux/dump_writer_common/thread_info.cc b/src/client/linux/dump_writer_common/thread_info.cc index 0a1041d..d319b82 100644 --- a/src/client/linux/dump_writer_common/thread_info.cc +++ b/src/client/linux/dump_writer_common/thread_info.cc @@ -270,7 +270,27 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const { out->float_save.fir = mcontext.fpc_eir; #endif } -#endif // __mips__ + +#elif defined (__PPC__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.nip; +} +void ThreadInfo::FillCPUContext(RawContextCPU* out ) const { + out->context_flags = MD_CONTEXT_PPC_FULL; + + for (int i = 0; i < MD_CONTEXT_PPC64_GPR_COUNT; ++i) + out->gpr[i] = regs.gpr[i]; + + out->srr0 = regs.nip; + out->srr1 = regs.msr; + out->cr = regs.ccr; + out->xer = regs.xer; + out->lr = regs.link; + out->ctr = regs.ctr; + +} +#endif // __PPC___ void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) { assert(gp_regs || size); @@ -294,6 +314,11 @@ void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) { *fp_regs = &mcontext.fpregs; if (size) *size = sizeof(mcontext.fpregs); +#elif defined(__PPC64__) + if (fp_regs) + *fp_regs = ®s; + if (size) + *size = sizeof(regs); #else if (fp_regs) *fp_regs = &fpregs; diff --git a/src/client/linux/dump_writer_common/thread_info.h b/src/client/linux/dump_writer_common/thread_info.h index 99093d2..b9b5fa7 100644 --- a/src/client/linux/dump_writer_common/thread_info.h +++ b/src/client/linux/dump_writer_common/thread_info.h @@ -71,6 +71,8 @@ struct ThreadInfo { #elif defined(__mips__) // Use the structure defined in . mcontext_t mcontext; +#elif defined(__PPC__) + struct pt_regs regs; #endif // Returns the instruction pointer (platform-dependent impl.). diff --git a/src/client/linux/dump_writer_common/ucontext_reader.cc b/src/client/linux/dump_writer_common/ucontext_reader.cc index c80724d..d9112be 100644 --- a/src/client/linux/dump_writer_common/ucontext_reader.cc +++ b/src/client/linux/dump_writer_common/ucontext_reader.cc @@ -254,6 +254,33 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) { out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused. #endif } +#elif defined(__PPC64__) + + uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.regs->gpr[1]; + } + + uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.regs->nip; + } + + void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fpregs) { + typedef unsigned long greg_t; + const greg_t* regs = uc->uc_mcontext.gp_regs; + + out->context_flags = MD_CONTEXT_PPC_FULL; + + for (int i = 0; i < MD_CONTEXT_PPC64_GPR_COUNT; ++i) + out->gpr[i] = regs[i]; + + out->vrsave = uc->uc_mcontext.v_regs->vrsave; + + for (int i = 0; i < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; ++i) + out->float_save.fpregs[i] = fpregs->fpregs[i]; + + out->float_save.fpscr = fpregs->fpscr; +} #endif } // namespace google_breakpad diff --git a/src/client/linux/dump_writer_common/ucontext_reader.h b/src/client/linux/dump_writer_common/ucontext_reader.h index b6e77b4..8f62fc1 100644 --- a/src/client/linux/dump_writer_common/ucontext_reader.h +++ b/src/client/linux/dump_writer_common/ucontext_reader.h @@ -37,6 +37,15 @@ #include "common/memory.h" #include "google_breakpad/common/minidump_format.h" +#if defined(__PPC__) +struct _libc_fpstate + { + double fpregs[32]; + double fpscr; + unsigned int _pad[2]; + }; +#endif + namespace google_breakpad { // Wraps platform-dependent implementations of accessors to ucontext structs. @@ -54,6 +63,9 @@ struct UContextReader { #elif defined(__aarch64__) static void FillCPUContext(RawContextCPU *out, const ucontext *uc, const struct fpsimd_context* fpregs); +#elif defined(__PPC__) + static void FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fpregs_); #else static void FillCPUContext(RawContextCPU *out, const ucontext *uc); #endif diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc index 586d84e..abc627d 100644 --- a/src/client/linux/handler/exception_handler.cc +++ b/src/client/linux/handler/exception_handler.cc @@ -471,10 +471,17 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) { // In case of MIPS Linux FP state is already part of struct ucontext // and 'float_state' is not a member of CrashContext. struct ucontext* uc_ptr = (struct ucontext*)uc; - if (uc_ptr->uc_mcontext.fpregs) { + #if defined(__PPC64__) + if (uc_ptr->uc_mcontext.fp_regs) { + memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fp_regs, + sizeof(g_crash_context_.float_state)); + } + #else + if (uc_ptr->uc_mcontext.fpregs) { memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs, sizeof(g_crash_context_.float_state)); } + #endif #endif g_crash_context_.tid = syscall(__NR_gettid); if (crash_handler_ != NULL) { @@ -708,8 +715,13 @@ bool ExceptionHandler::WriteMinidump() { #if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) // FPU state is not part of ARM EABI ucontext_t. - memcpy(&context.float_state, context.context.uc_mcontext.fpregs, - sizeof(context.float_state)); + #if defined(__PPC64__) + memcpy(&context.float_state, context.context.uc_mcontext.fp_regs, + sizeof(context.float_state)); + #else + memcpy(&context.float_state, context.context.uc_mcontext.fpregs, + sizeof(context.float_state)); + #endif #endif context.tid = sys_gettid(); @@ -731,6 +743,9 @@ bool ExceptionHandler::WriteMinidump() { #elif defined(__mips__) context.siginfo.si_addr = reinterpret_cast(context.context.uc_mcontext.pc); +#elif defined(__PPC64__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.gp_regs[PT_NIP]); #else #error "This code has not been ported to your platform yet." #endif diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h index daba57e..e318695 100644 --- a/src/client/linux/handler/exception_handler.h +++ b/src/client/linux/handler/exception_handler.h @@ -196,7 +196,17 @@ class ExceptionHandler { // #ifdef this out because FP state is not part of user ABI for Linux ARM. // In case of MIPS Linux FP state is already part of struct // ucontext so 'float_state' is not required. - fpstate_t float_state; + #if defined(__PPC__) + struct _libc_fpstate + { + double fpregs[32]; + double fpscr; + unsigned int _pad[2]; + }; + struct _libc_fpstate float_state; + #else + fpstate_t float_state; + #endif #endif }; diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc index 3764eec..6fff850 100644 --- a/src/client/linux/microdump_writer/microdump_writer.cc +++ b/src/client/linux/microdump_writer/microdump_writer.cc @@ -138,7 +138,7 @@ class MicrodumpWriter { const MicrodumpExtraInfo& microdump_extra_info, LinuxDumper* dumper) : ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if !defined(__ARM_EABI__) && !defined(__mips__)&& !defined(__PPC__) float_state_(context ? &context->float_state : NULL), #endif dumper_(dumper), @@ -326,6 +326,8 @@ class MicrodumpWriter { # else # error "This mips ABI is currently not supported (n32)" #endif +#elif defined(__PPC__) + const char kArch[] = "ppc"; #else #error "This code has not been ported to your platform yet" #endif @@ -594,8 +596,10 @@ class MicrodumpWriter { void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } const struct ucontext* const ucontext_; -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__PPC__) const google_breakpad::fpstate_t* const float_state_; +#elif defined(__PPC__) + const _libc_fpstate* const float_state_ = NULL; #endif LinuxDumper* dumper_; const MappingList& mapping_list_; diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc index 622f050..ad8bfcf 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper.cc +++ b/src/client/linux/minidump_writer/linux_core_dumper.cc @@ -111,6 +111,8 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { #elif defined(__mips__) stack_pointer = reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#elif defined(__PPC__) + memcpy(&stack_pointer, &info->regs.gpr[1], sizeof(info->regs.gpr[1])); #else #error "This code hasn't been ported to your platform yet." #endif diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index 3a9a2e8..d37c7fe 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -59,7 +59,7 @@ namespace google_breakpad { #if defined(__i386) || defined(__ARM_EABI__) || \ (defined(__mips__) && _MIPS_SIM == _ABIO32) typedef Elf32_auxv_t elf_aux_entry; -#elif defined(__x86_64) || defined(__aarch64__) || \ +#elif defined(__x86_64) || defined(__aarch64__) || defined(__PPC64__) || \ (defined(__mips__) && _MIPS_SIM != _ABIO32) typedef Elf64_auxv_t elf_aux_entry; #endif diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc index 3ad48e5..eb250f0 100644 --- a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +++ b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc @@ -41,7 +41,7 @@ #include "common/scoped_ptr.h" #include "third_party/lss/linux_syscall_support.h" -#if defined(__ARM_EABI__) +#if defined(__ARM_EABI__) || defined(__PPC__) #define TID_PTR_REGISTER "r3" #elif defined(__aarch64__) #define TID_PTR_REGISTER "x3" diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc index e3ddb81..0374d6a 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -298,6 +298,8 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { #elif defined(__mips__) stack_pointer = reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#elif defined(__PPC__) + memcpy(&stack_pointer, &info->regs.gpr[1], sizeof(info->regs.gpr[1])); #else #error "This code hasn't been ported to your platform yet." #endif diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc index 2ef1c49..4d6f93d 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc @@ -454,6 +454,8 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { pid_t* process_tid_location = (pid_t*)(one_thread.regs.ecx); #elif defined(__x86_64) pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx); +#elif defined(__PPC__) + pid_t* process_tid_location = (pid_t*)(one_thread.regs.gpr[3]); #elif defined(__mips__) pid_t* process_tid_location = reinterpret_cast(one_thread.mcontext.gregs[1]); @@ -553,6 +555,8 @@ TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) { uintptr_t heap_addr = thread_info.regs.rcx; #elif defined(__mips__) uintptr_t heap_addr = thread_info.mcontext.gregs[1]; +#elif defined(__PPC__) + uintptr_t heap_addr = thread_info.regs.gpr[3]; #else #error This test has not been ported to this platform. #endif diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index d11ba6e..8087f09 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -136,7 +136,7 @@ class MinidumpWriter { : fd_(minidump_fd), path_(minidump_path), ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__PPC__) float_state_(context ? &context->float_state : NULL), #endif dumper_(dumper), @@ -888,7 +888,7 @@ class MinidumpWriter { dirent->location.rva = 0; } -#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) +#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || defined(__PPC__) bool WriteCPUInformation(MDRawSystemInfo* sys_info) { char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; static const char vendor_id_name[] = "vendor_id"; @@ -918,6 +918,8 @@ class MinidumpWriter { #endif #elif defined(__i386__) MD_CPU_ARCHITECTURE_X86; +#elif defined(__PPC__) + MD_CPU_ARCHITECTURE_PPC; #else MD_CPU_ARCHITECTURE_AMD64; #endif @@ -1325,7 +1327,11 @@ class MinidumpWriter { const struct ucontext* const ucontext_; // also from the signal handler #if !defined(__ARM_EABI__) && !defined(__mips__) - const google_breakpad::fpstate_t* const float_state_; // ditto + #if defined(__PPC__) + const struct _libc_fpstate* const float_state_=NULL; + #else + const google_breakpad::fpstate_t* const float_state_; // ditto + #endif #endif LinuxDumper* dumper_; MinidumpFileWriter minidump_writer_; diff --git a/src/client/linux/minidump_writer/minidump_writer.h b/src/client/linux/minidump_writer/minidump_writer.h index d1dc331..173cc69 100644 --- a/src/client/linux/minidump_writer/minidump_writer.h +++ b/src/client/linux/minidump_writer/minidump_writer.h @@ -47,7 +47,7 @@ class ExceptionHandler; #if defined(__aarch64__) typedef struct fpsimd_context fpstate_t; -#elif !defined(__ARM_EABI__) && !defined(__mips__) +#elif !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__PPC__) typedef struct _libc_fpstate fpstate_t; #endif diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest.cc b/src/client/linux/minidump_writer/minidump_writer_unittest.cc index 583ddda..3df03c9 100644 --- a/src/client/linux/minidump_writer/minidump_writer_unittest.cc +++ b/src/client/linux/minidump_writer/minidump_writer_unittest.cc @@ -707,6 +707,8 @@ TEST(MinidumpWriterTest, InvalidStackPointer) { context.context.uc_mcontext.arm_sp = invalid_stack_pointer; #elif defined(__aarch64__) context.context.uc_mcontext.sp = invalid_stack_pointer; +#elif defined(__PPC__) + context.context.uc_mcontext.regs->gpr[1] = invalid_stack_pointer; #elif defined(__mips__) context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] = invalid_stack_pointer; diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc index 528ee5f..636bb08 100644 --- a/src/processor/exploitability_unittest.cc +++ b/src/processor/exploitability_unittest.cc @@ -38,11 +38,14 @@ #include "google_breakpad/processor/minidump_processor.h" #include "google_breakpad/processor/process_state.h" #ifndef _WIN32 +#ifndef __PPC__ #include "processor/exploitability_linux.h" +#endif // __PPC__ #endif // _WIN32 #include "processor/simple_symbol_supplier.h" #ifndef _WIN32 +#ifndef __PPC__ namespace google_breakpad { class ExploitabilityLinuxTest : public ExploitabilityLinux { @@ -64,14 +67,17 @@ class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext { }; } // namespace google_breakpad +#endif // __PPC__ #endif // _WIN32 namespace { using google_breakpad::BasicSourceLineResolver; #ifndef _WIN32 +#ifndef __PPC__ using google_breakpad::ExploitabilityLinuxTest; using google_breakpad::ExploitabilityLinuxTestMinidumpContext; +#endif // __PPC__ #endif // _WIN32 using google_breakpad::MinidumpProcessor; using google_breakpad::ProcessState; @@ -172,6 +178,7 @@ TEST(ExploitabilityTest, TestLinuxEngine) { ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, ExploitabilityFor("linux_jmp_to_module_not_exe_region.dmp")); #ifndef _WIN32 +#ifndef __PPC__ ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, ExploitabilityFor("linux_write_to_nonwritable_module.dmp")); ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, @@ -182,10 +189,12 @@ TEST(ExploitabilityTest, TestLinuxEngine) { ExploitabilityFor("linux_write_to_outside_module_via_math.dmp")); ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, ExploitabilityFor("linux_write_to_under_4k.dmp")); +#endif // __PPC__ #endif // _WIN32 } #ifndef _WIN32 +#ifndef __PPC__ TEST(ExploitabilityLinuxUtilsTest, DisassembleBytesTest) { ASSERT_FALSE(ExploitabilityLinuxTest::DisassembleBytes("", NULL, 5, NULL)); uint8_t bytes[6] = {0xc7, 0x0, 0x5, 0x0, 0x0, 0x0}; @@ -301,6 +310,7 @@ TEST(ExploitabilityLinuxUtilsTest, CalculateAddressTest) { context, &write_address)); } +#endif // __PPC__ #endif // _WIN32 } // namespace diff --git a/src/third_party/curl/curlbuild.h b/src/third_party/curl/curlbuild.h index b0a53e6..e2553e0 100644 --- a/src/third_party/curl/curlbuild.h +++ b/src/third_party/curl/curlbuild.h @@ -154,7 +154,7 @@ #endif /* The size of `long', as computed by sizeof. */ -#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || \ +#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(__PPC64__) || \ defined(__aarch64__) || (defined(__mips__) && _MIPS_SIM == _ABI64) #define CURL_SIZEOF_LONG 8 #else diff --git a/src/tools/linux/md2core/minidump-2-core.cc b/src/tools/linux/md2core/minidump-2-core.cc index 6a9e28e..c4c3637 100644 --- a/src/tools/linux/md2core/minidump-2-core.cc +++ b/src/tools/linux/md2core/minidump-2-core.cc @@ -249,7 +249,11 @@ typedef struct prstatus { /* Information about thread; includes CPU reg*/ elf_timeval pr_stime; /* System time */ elf_timeval pr_cutime; /* Cumulative user time */ elf_timeval pr_cstime; /* Cumulative system time */ +#if defined(__PPC__) + pt_regs pr_reg; +#else user_regs_struct pr_reg; /* CPU registers */ +#endif uint32_t pr_fpvalid; /* True if math co-processor being used */ } prstatus; @@ -308,6 +312,8 @@ struct CrashedProcess { pid_t tid; #if defined(__mips__) mcontext_t mcontext; +#elif defined(__PPC__) + pt_regs regs; #else user_regs_struct regs; #endif @@ -522,6 +528,22 @@ ParseThreadRegisters(CrashedProcess::Thread* thread, thread->mcontext.fpc_eir = rawregs->float_save.fir; #endif } +#elif defined(__PPC64__) + static void + ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextPPC64* rawregs = range.GetData(0); + + for(int i = 0; i < MD_CONTEXT_PPC64_GPR_COUNT; i++) + thread->regs.gpr[i] = rawregs->gpr[i]; + + thread->regs.nip = rawregs->srr0; + thread->regs.msr = rawregs->srr1; + thread->regs.ctr = rawregs->ctr; + thread->regs.xer = rawregs->xer; + thread->regs.link = rawregs->lr; + thread->regs.ccr = rawregs->cr; +} #else #error "This code has not been ported to your platform yet" #endif @@ -610,6 +632,14 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, # else # error "This mips ABI is currently not supported (n32)" # endif +#elif defined(__PPC64__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_PPC) { + fprintf(stderr, + "This version of minidump-2-core only supports PowerPC (64bit)%s.\n", + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_PPC ? + ",\nbut the minidump file is from a 32bit machine" : ""); + _exit(1); + } #else #error "This code has not been ported to your platform yet" #endif @@ -915,6 +945,8 @@ WriteThread(const Options& options, const CrashedProcess::Thread& thread, pr.pr_pid = thread.tid; #if defined(__mips__) memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct)); +#elif defined(__PPC__) + memcpy(&pr.pr_reg, &thread.regs, sizeof(pt_regs)); #else memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct)); #endif