-/* Copyright (c) 2015. The SimGrid Team.
+/* Copyright (c) 2015-2017. The SimGrid Team.
* All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
// We need this for the register indices:
// #define _GNU_SOURCE
-#include <string.h>
+#include <cstring>
// On x86_64, libunwind unw_context_t has the same layout as ucontext_t:
+#include <sys/types.h>
#include <sys/ucontext.h>
+#ifdef __FreeBSD__
+typedef register_t greg_t;
+#endif
#include <libunwind.h>
-#include "mc_object_info.h"
-#include "mc_process.h"
-#include "mc_unw.h"
+#include "src/mc/Frame.hpp"
+#include "src/mc/mc_unw.hpp"
+#include "src/mc/remote/RemoteClient.hpp"
+
+using simgrid::mc::remote;
-extern "C" {
+namespace simgrid {
+namespace mc {
// ***** Implementation
*
* Delegates to the local/ptrace implementation.
*/
-static int find_proc_info(unw_addr_space_t as,
+int UnwindContext::find_proc_info(unw_addr_space_t as,
unw_word_t ip, unw_proc_info_t *pip,
- int need_unwind_info, void* arg)
+ int need_unwind_info, void* arg) noexcept
{
- mc_unw_context_t context = (mc_unw_context_t) arg;
- return unw_get_accessors(context->process->unw_underlying_addr_space)->find_proc_info(
- context->process->unw_underlying_addr_space, ip, pip,
- need_unwind_info, context->process->unw_underlying_context
+ simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
+ return unw_get_accessors(context->process_->unw_underlying_addr_space)->find_proc_info(
+ context->process_->unw_underlying_addr_space, ip, pip,
+ need_unwind_info, context->process_->unw_underlying_context
);
}
*
* Delegates to the local/ptrace implementation.
*/
-static void put_unwind_info(unw_addr_space_t as,
- unw_proc_info_t *pip, void* arg)
+void UnwindContext::put_unwind_info(unw_addr_space_t as,
+ unw_proc_info_t *pip, void* arg) noexcept
{
- mc_unw_context_t context = (mc_unw_context_t) arg;
- return unw_get_accessors(context->process->unw_underlying_addr_space)->put_unwind_info(
- context->process->unw_underlying_addr_space, pip,
- context->process->unw_underlying_context
+ simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
+ return unw_get_accessors(context->process_->unw_underlying_addr_space)->put_unwind_info(
+ context->process_->unw_underlying_addr_space, pip,
+ context->process_->unw_underlying_context
);
}
*
* Not implemented.
*/
-static int get_dyn_info_list_addr(unw_addr_space_t as,
- unw_word_t *dilap, void* arg)
+int UnwindContext::get_dyn_info_list_addr(unw_addr_space_t as,
+ unw_word_t *dilap, void* arg) noexcept
{
- mc_unw_context_t context = (mc_unw_context_t) arg;
- return unw_get_accessors(context->process->unw_underlying_addr_space)->get_dyn_info_list_addr(
- context->process->unw_underlying_addr_space,
+ simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
+ return unw_get_accessors(context->process_->unw_underlying_addr_space)->get_dyn_info_list_addr(
+ context->process_->unw_underlying_addr_space,
dilap,
- context->process->unw_underlying_context
+ context->process_->unw_underlying_context
);
}
/** Read from the target address space memory (libunwind method)
*
- * Delegates to the `mc_process_t`.
+ * Delegates to the `simgrid::mc::Process*`.
*/
-static int access_mem(unw_addr_space_t as,
+int UnwindContext::access_mem(unw_addr_space_t as,
unw_word_t addr, unw_word_t *valp,
- int write, void* arg)
+ int write, void* arg) noexcept
{
- mc_unw_context_t context = (mc_unw_context_t) arg;
+ simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
if (write)
return - UNW_EREADONLYREG;
- MC_address_space_read(context->address_space,
- MC_ADDRESS_SPACE_READ_FLAGS_NONE, valp, (void*) addr, sizeof(unw_word_t), MC_PROCESS_INDEX_ANY);
- // We don't handle failure gracefully.
+ context->addressSpace_->read_bytes(valp, sizeof(unw_word_t), remote(addr));
return 0;
}
-static void* get_reg(unw_context_t* context, unw_regnum_t regnum)
+void* UnwindContext::get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept
{
#ifdef __x86_64
mcontext_t* mcontext = &context->uc_mcontext;
switch (regnum) {
+# ifdef __linux__
case UNW_X86_64_RAX: return &mcontext->gregs[REG_RAX];
case UNW_X86_64_RDX: return &mcontext->gregs[REG_RDX];
case UNW_X86_64_RCX: return &mcontext->gregs[REG_RCX];
case UNW_X86_64_R14: return &mcontext->gregs[REG_R14];
case UNW_X86_64_R15: return &mcontext->gregs[REG_R15];
case UNW_X86_64_RIP: return &mcontext->gregs[REG_RIP];
- default: return NULL;
+# elif defined __FreeBSD__
+ case UNW_X86_64_RAX: return &mcontext->mc_rax;
+ case UNW_X86_64_RDX: return &mcontext->mc_rdx;
+ case UNW_X86_64_RCX: return &mcontext->mc_rcx;
+ case UNW_X86_64_RBX: return &mcontext->mc_rbx;
+ case UNW_X86_64_RSI: return &mcontext->mc_rsi;
+ case UNW_X86_64_RDI: return &mcontext->mc_rdi;
+ case UNW_X86_64_RBP: return &mcontext->mc_rbp;
+ case UNW_X86_64_RSP: return &mcontext->mc_rsp;
+ case UNW_X86_64_R8: return &mcontext->mc_r8;
+ case UNW_X86_64_R9: return &mcontext->mc_r9;
+ case UNW_X86_64_R10: return &mcontext->mc_r10;
+ case UNW_X86_64_R11: return &mcontext->mc_r11;
+ case UNW_X86_64_R12: return &mcontext->mc_r12;
+ case UNW_X86_64_R13: return &mcontext->mc_r13;
+ case UNW_X86_64_R14: return &mcontext->mc_r14;
+ case UNW_X86_64_R15: return &mcontext->mc_r15;
+ case UNW_X86_64_RIP: return &mcontext->mc_rip;
+# else
+# error "Unable to get register from ucontext, please add your case"
+# endif
+ default: return nullptr;
}
#else
- return NULL;
+ return nullptr;
#endif
}
/** Read a standard register (libunwind method)
*/
-static int access_reg(unw_addr_space_t as,
+int UnwindContext::access_reg(unw_addr_space_t as,
unw_regnum_t regnum, unw_word_t *valp,
- int write, void* arg)
+ int write, void* arg) noexcept
{
- mc_unw_context_t as_context = (mc_unw_context_t) arg;
- unw_context_t* context = &as_context->context;
+ simgrid::mc::UnwindContext* as_context = (simgrid::mc::UnwindContext*) arg;
+ unw_context_t* context = &as_context->unwindContext_;
if (write)
return -UNW_EREADONLYREG;
greg_t* preg = (greg_t*) get_reg(context, regnum);
- if (!preg)
+ if (not preg)
return -UNW_EBADREG;
*valp = *preg;
return 0;
* `getcontext()` is not relevant for the caller. It is not really necessary
* to save and handle them.
*/
-static int access_fpreg(unw_addr_space_t as,
+int UnwindContext::access_fpreg(unw_addr_space_t as,
unw_regnum_t regnum, unw_fpreg_t *fpvalp,
- int write, void* arg)
+ int write, void* arg) noexcept
{
return -UNW_EBADREG;
}
*
* We don't use this.
*/
-static int resume(unw_addr_space_t as,
- unw_cursor_t *cp, void* arg)
+int UnwindContext::resume(unw_addr_space_t as,
+ unw_cursor_t *cp, void* arg) noexcept
{
return -UNW_EUNSPEC;
}
/** Find informations about a function (libunwind method)
*/
-static int get_proc_name(unw_addr_space_t as,
+int UnwindContext::get_proc_name(unw_addr_space_t as,
unw_word_t addr, char *bufp,
size_t buf_len, unw_word_t *offp,
- void* arg)
+ void* arg) noexcept
{
- mc_unw_context_t context = (mc_unw_context_t) arg;
- dw_frame_t frame = MC_process_find_function(context->process, (void*) addr);
- if (!frame)
+ simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
+ simgrid::mc::Frame* frame = context->process_->find_function(remote(addr));
+ if (not frame)
return - UNW_ENOINFO;
- *offp = (unw_word_t) frame->low_pc - addr;
+ *offp = (unw_word_t) frame->range.begin() - addr;
- strncpy(bufp, frame->name, buf_len);
+ strncpy(bufp, frame->name.c_str(), buf_len);
if (bufp[buf_len - 1]) {
bufp[buf_len - 1] = 0;
return -UNW_ENOMEM;
// ***** Init
-unw_accessors_t mc_unw_accessors =
- {
- &find_proc_info,
- &put_unwind_info,
- &get_dyn_info_list_addr,
- &access_mem,
- &access_reg,
- &access_fpreg,
- &resume,
- &get_proc_name
- };
-
-// ***** Context management
-
-int mc_unw_init_context(
- mc_unw_context_t context, mc_process_t process, unw_context_t* c)
+/** Virtual table for our `libunwind` implementation
+ *
+ * Stack unwinding on a `simgrid::mc::Process*` (for memory, unwinding information)
+ * and `ucontext_t` (for processor registers).
+ *
+ * It works with the `simgrid::mc::UnwindContext` context.
+ */
+unw_accessors_t UnwindContext::accessors = {
+ &find_proc_info,
+ &put_unwind_info,
+ &get_dyn_info_list_addr,
+ &access_mem,
+ &access_reg,
+ &access_fpreg,
+ &resume,
+ &get_proc_name
+};
+
+unw_addr_space_t UnwindContext::createUnwindAddressSpace()
+{
+ return unw_create_addr_space(&UnwindContext::accessors, BYTE_ORDER);
+}
+
+void UnwindContext::clear()
+{
+ addressSpace_ = nullptr;
+ process_ = nullptr;
+}
+
+void UnwindContext::initialize(simgrid::mc::RemoteClient* process, unw_context_t* c)
{
- context->address_space = (mc_address_space_t) process;
- context->process = process;
+ clear();
+
+ this->addressSpace_ = process;
+ this->process_ = process;
// Take a copy of the context for our own purpose:
- context->context = *c;
-#if defined(PROCESSOR_x86_64) || defined(PROCESSOR_i686)
+ this->unwindContext_ = *c;
+#if SIMGRID_PROCESSOR_x86_64 || SIMGRID_PROCESSOR_i686
+# ifdef __linux__
// On x86_64, ucontext_t contains a pointer to itself for FP registers.
// We don't really need support for FR registers as they are caller saved
// and probably never use those fields as libunwind-x86_64 does not read
// FP registers from the unw_context_t
- // but we fix the pointer in order to avoid dangling pointers:
- context->context.uc_mcontext.fpregs = &(context->context.__fpregs_mem);
+ // Let's ignore this and see what happens:
+ this->unwindContext_.uc_mcontext.fpregs = nullptr;
+# endif
#else
// Do we need to do any fixup like this?
- #error Target CPU type is not handled.
+# error Target CPU type is not handled.
#endif
-
- return 0;
}
-int mc_unw_destroy_context(mc_unw_context_t context)
+unw_cursor_t UnwindContext::cursor()
{
- context->address_space = NULL;
- context->process = NULL;
- return 0;
+ unw_cursor_t cursor;
+ if (process_ == nullptr
+ || addressSpace_ == nullptr
+ || unw_init_remote(&cursor, process_->unw_addr_space, this) != 0)
+ xbt_die("UnwindContext not initialized");
+ return cursor;
}
-// ***** Cursor management
-
-int mc_unw_init_cursor(unw_cursor_t *cursor, mc_unw_context_t context)
-{
- if (!context->process || !context->address_space)
- return -UNW_EUNSPEC;
- mc_address_space_t as = context->address_space;
-
- // Use local unwinding for current process:
- if (MC_is_process(as) && MC_process_is_self((mc_process_t) as))
- return unw_init_local(cursor, &context->context);
-
- return unw_init_remote(cursor, context->process->unw_addr_space, context);
}
-
}