1 /* Copyright (c) 2015-2017. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
8 * Libunwind support for mc_address_space objects.
11 // We need this for the register indices:
12 // #define _GNU_SOURCE
16 // On x86_64, libunwind unw_context_t has the same layout as ucontext_t:
17 #include <sys/types.h>
18 #include <sys/ucontext.h>
20 typedef register_t greg_t;
23 #include <libunwind.h>
25 #include "src/mc/Frame.hpp"
26 #include "src/mc/mc_unw.h"
27 #include "src/mc/remote/RemoteClient.hpp"
29 using simgrid::mc::remote;
34 // ***** Implementation
36 /** Get frame unwind information (libunwind method)
38 * Delegates to the local/ptrace implementation.
40 int UnwindContext::find_proc_info(unw_addr_space_t as,
41 unw_word_t ip, unw_proc_info_t *pip,
42 int need_unwind_info, void* arg) noexcept
44 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
45 return unw_get_accessors(context->process_->unw_underlying_addr_space)->find_proc_info(
46 context->process_->unw_underlying_addr_space, ip, pip,
47 need_unwind_info, context->process_->unw_underlying_context
51 /** Release frame unwind information (libunwind method)
53 * Delegates to the local/ptrace implementation.
55 void UnwindContext::put_unwind_info(unw_addr_space_t as,
56 unw_proc_info_t *pip, void* arg) noexcept
58 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
59 return unw_get_accessors(context->process_->unw_underlying_addr_space)->put_unwind_info(
60 context->process_->unw_underlying_addr_space, pip,
61 context->process_->unw_underlying_context
65 /** (libunwind method)
69 int UnwindContext::get_dyn_info_list_addr(unw_addr_space_t as,
70 unw_word_t *dilap, void* arg) noexcept
72 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
73 return unw_get_accessors(context->process_->unw_underlying_addr_space)->get_dyn_info_list_addr(
74 context->process_->unw_underlying_addr_space,
76 context->process_->unw_underlying_context
80 /** Read from the target address space memory (libunwind method)
82 * Delegates to the `simgrid::mc::Process*`.
84 int UnwindContext::access_mem(unw_addr_space_t as,
85 unw_word_t addr, unw_word_t *valp,
86 int write, void* arg) noexcept
88 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
90 return - UNW_EREADONLYREG;
91 context->addressSpace_->read_bytes(valp, sizeof(unw_word_t), remote(addr));
95 void* UnwindContext::get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept
98 mcontext_t* mcontext = &context->uc_mcontext;
101 case UNW_X86_64_RAX: return &mcontext->gregs[REG_RAX];
102 case UNW_X86_64_RDX: return &mcontext->gregs[REG_RDX];
103 case UNW_X86_64_RCX: return &mcontext->gregs[REG_RCX];
104 case UNW_X86_64_RBX: return &mcontext->gregs[REG_RBX];
105 case UNW_X86_64_RSI: return &mcontext->gregs[REG_RSI];
106 case UNW_X86_64_RDI: return &mcontext->gregs[REG_RDI];
107 case UNW_X86_64_RBP: return &mcontext->gregs[REG_RBP];
108 case UNW_X86_64_RSP: return &mcontext->gregs[REG_RSP];
109 case UNW_X86_64_R8: return &mcontext->gregs[REG_R8];
110 case UNW_X86_64_R9: return &mcontext->gregs[REG_R9];
111 case UNW_X86_64_R10: return &mcontext->gregs[REG_R10];
112 case UNW_X86_64_R11: return &mcontext->gregs[REG_R11];
113 case UNW_X86_64_R12: return &mcontext->gregs[REG_R12];
114 case UNW_X86_64_R13: return &mcontext->gregs[REG_R13];
115 case UNW_X86_64_R14: return &mcontext->gregs[REG_R14];
116 case UNW_X86_64_R15: return &mcontext->gregs[REG_R15];
117 case UNW_X86_64_RIP: return &mcontext->gregs[REG_RIP];
118 # elif defined __FreeBSD__
119 case UNW_X86_64_RAX: return &mcontext->mc_rax;
120 case UNW_X86_64_RDX: return &mcontext->mc_rdx;
121 case UNW_X86_64_RCX: return &mcontext->mc_rcx;
122 case UNW_X86_64_RBX: return &mcontext->mc_rbx;
123 case UNW_X86_64_RSI: return &mcontext->mc_rsi;
124 case UNW_X86_64_RDI: return &mcontext->mc_rdi;
125 case UNW_X86_64_RBP: return &mcontext->mc_rbp;
126 case UNW_X86_64_RSP: return &mcontext->mc_rsp;
127 case UNW_X86_64_R8: return &mcontext->mc_r8;
128 case UNW_X86_64_R9: return &mcontext->mc_r9;
129 case UNW_X86_64_R10: return &mcontext->mc_r10;
130 case UNW_X86_64_R11: return &mcontext->mc_r11;
131 case UNW_X86_64_R12: return &mcontext->mc_r12;
132 case UNW_X86_64_R13: return &mcontext->mc_r13;
133 case UNW_X86_64_R14: return &mcontext->mc_r14;
134 case UNW_X86_64_R15: return &mcontext->mc_r15;
135 case UNW_X86_64_RIP: return &mcontext->mc_rip;
137 # error "Unable to get register from ucontext, please add your case"
139 default: return nullptr;
146 /** Read a standard register (libunwind method)
148 int UnwindContext::access_reg(unw_addr_space_t as,
149 unw_regnum_t regnum, unw_word_t *valp,
150 int write, void* arg) noexcept
152 simgrid::mc::UnwindContext* as_context = (simgrid::mc::UnwindContext*) arg;
153 unw_context_t* context = &as_context->unwindContext_;
155 return -UNW_EREADONLYREG;
156 greg_t* preg = (greg_t*) get_reg(context, regnum);
163 /** Read a floating-point register (libunwind method)
165 * FP registers are caller-saved. The values saved by functions such as
166 * `getcontext()` is not relevant for the caller. It is not really necessary
167 * to save and handle them.
169 int UnwindContext::access_fpreg(unw_addr_space_t as,
170 unw_regnum_t regnum, unw_fpreg_t *fpvalp,
171 int write, void* arg) noexcept
176 /** Resume the execution of the context (libunwind method)
180 int UnwindContext::resume(unw_addr_space_t as,
181 unw_cursor_t *cp, void* arg) noexcept
186 /** Find informations about a function (libunwind method)
188 int UnwindContext::get_proc_name(unw_addr_space_t as,
189 unw_word_t addr, char *bufp,
190 size_t buf_len, unw_word_t *offp,
193 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*) arg;
194 simgrid::mc::Frame* frame = context->process_->find_function(remote(addr));
196 return - UNW_ENOINFO;
197 *offp = (unw_word_t) frame->range.begin() - addr;
199 strncpy(bufp, frame->name.c_str(), buf_len);
200 if (bufp[buf_len - 1]) {
201 bufp[buf_len - 1] = 0;
210 /** Virtual table for our `libunwind` implementation
212 * Stack unwinding on a `simgrid::mc::Process*` (for memory, unwinding information)
213 * and `ucontext_t` (for processor registers).
215 * It works with the `simgrid::mc::UnwindContext` context.
217 unw_accessors_t UnwindContext::accessors = {
220 &get_dyn_info_list_addr,
228 unw_addr_space_t UnwindContext::createUnwindAddressSpace()
230 return unw_create_addr_space(&UnwindContext::accessors, BYTE_ORDER);
233 void UnwindContext::clear()
235 addressSpace_ = nullptr;
239 void UnwindContext::initialize(simgrid::mc::RemoteClient* process, unw_context_t* c)
243 this->addressSpace_ = process;
244 this->process_ = process;
246 // Take a copy of the context for our own purpose:
247 this->unwindContext_ = *c;
248 #if SIMGRID_PROCESSOR_x86_64 || SIMGRID_PROCESSOR_i686
250 // On x86_64, ucontext_t contains a pointer to itself for FP registers.
251 // We don't really need support for FR registers as they are caller saved
252 // and probably never use those fields as libunwind-x86_64 does not read
253 // FP registers from the unw_context_t
254 // but we fix the pointer in order to avoid dangling pointers:
255 // context->context_.uc_mcontext.fpregs = &(context->context.__fpregs_mem);
257 // Let's ignore this and see what happens:
258 this->unwindContext_.uc_mcontext.fpregs = nullptr;
261 // Do we need to do any fixup like this?
262 # error Target CPU type is not handled.
266 unw_cursor_t UnwindContext::cursor()
269 if (process_ == nullptr
270 || addressSpace_ == nullptr
271 || unw_init_remote(&cursor, process_->unw_addr_space, this) != 0)
272 xbt_die("UnwindContext not initialized");