1 /* Copyright (c) 2015-2019. 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.hpp"
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*/, unw_word_t ip, unw_proc_info_t* pip, int need_unwind_info,
43 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
44 return unw_get_accessors(context->process_->unw_underlying_addr_space)
45 ->find_proc_info(context->process_->unw_underlying_addr_space, ip, pip, need_unwind_info,
46 context->process_->unw_underlying_context);
49 /** Release frame unwind information (libunwind method)
51 * Delegates to the local/ptrace implementation.
53 void UnwindContext::put_unwind_info(unw_addr_space_t /*as*/, unw_proc_info_t* pip, void* arg) noexcept
55 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
56 return unw_get_accessors(context->process_->unw_underlying_addr_space)
57 ->put_unwind_info(context->process_->unw_underlying_addr_space, pip, context->process_->unw_underlying_context);
60 /** (libunwind method)
64 int UnwindContext::get_dyn_info_list_addr(unw_addr_space_t /*as*/, unw_word_t* dilap, void* arg) noexcept
66 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
67 return unw_get_accessors(context->process_->unw_underlying_addr_space)
68 ->get_dyn_info_list_addr(context->process_->unw_underlying_addr_space, dilap,
69 context->process_->unw_underlying_context);
72 /** Read from the target address space memory (libunwind method)
74 * Delegates to the `simgrid::mc::Process*`.
76 int UnwindContext::access_mem(unw_addr_space_t /*as*/, unw_word_t addr, unw_word_t* valp, int write, void* arg) noexcept
78 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
80 return -UNW_EREADONLYREG;
81 context->addressSpace_->read_bytes(valp, sizeof(unw_word_t), remote(addr));
85 void* UnwindContext::get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept
88 mcontext_t* mcontext = &context->uc_mcontext;
92 return &mcontext->gregs[REG_RAX];
94 return &mcontext->gregs[REG_RDX];
96 return &mcontext->gregs[REG_RCX];
98 return &mcontext->gregs[REG_RBX];
100 return &mcontext->gregs[REG_RSI];
102 return &mcontext->gregs[REG_RDI];
104 return &mcontext->gregs[REG_RBP];
106 return &mcontext->gregs[REG_RSP];
108 return &mcontext->gregs[REG_R8];
110 return &mcontext->gregs[REG_R9];
112 return &mcontext->gregs[REG_R10];
114 return &mcontext->gregs[REG_R11];
116 return &mcontext->gregs[REG_R12];
118 return &mcontext->gregs[REG_R13];
120 return &mcontext->gregs[REG_R14];
122 return &mcontext->gregs[REG_R15];
124 return &mcontext->gregs[REG_RIP];
125 #elif defined __FreeBSD__
127 return &mcontext->mc_rax;
129 return &mcontext->mc_rdx;
131 return &mcontext->mc_rcx;
133 return &mcontext->mc_rbx;
135 return &mcontext->mc_rsi;
137 return &mcontext->mc_rdi;
139 return &mcontext->mc_rbp;
141 return &mcontext->mc_rsp;
143 return &mcontext->mc_r8;
145 return &mcontext->mc_r9;
147 return &mcontext->mc_r10;
149 return &mcontext->mc_r11;
151 return &mcontext->mc_r12;
153 return &mcontext->mc_r13;
155 return &mcontext->mc_r14;
157 return &mcontext->mc_r15;
159 return &mcontext->mc_rip;
161 #error "Unable to get register from ucontext, please add your case"
171 /** Read a standard register (libunwind method)
173 int UnwindContext::access_reg(unw_addr_space_t /*as*/, unw_regnum_t regnum, unw_word_t* valp, int write,
176 simgrid::mc::UnwindContext* as_context = (simgrid::mc::UnwindContext*)arg;
177 unw_context_t* context = &as_context->unwindContext_;
179 return -UNW_EREADONLYREG;
180 greg_t* preg = (greg_t*)get_reg(context, regnum);
187 /** Read a floating-point register (libunwind method)
189 * FP registers are caller-saved. The values saved by functions such as
190 * `getcontext()` is not relevant for the caller. It is not really necessary
191 * to save and handle them.
193 int UnwindContext::access_fpreg(unw_addr_space_t /*as*/, unw_regnum_t /*regnum*/, unw_fpreg_t* /*fpvalp*/,
194 int /*write*/, void* /*arg*/) noexcept
199 /** Resume the execution of the context (libunwind method)
203 int UnwindContext::resume(unw_addr_space_t /*as*/, unw_cursor_t* /*cp*/, void* /*arg*/) noexcept
208 /** Find informations about a function (libunwind method)
210 int UnwindContext::get_proc_name(unw_addr_space_t /*as*/, unw_word_t addr, char* bufp, size_t buf_len, unw_word_t* offp,
213 simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
214 simgrid::mc::Frame* frame = context->process_->find_function(remote(addr));
217 *offp = (unw_word_t)frame->range.begin() - addr;
219 strncpy(bufp, frame->name.c_str(), buf_len);
220 if (bufp[buf_len - 1]) {
221 bufp[buf_len - 1] = 0;
230 /** Virtual table for our `libunwind` implementation
232 * Stack unwinding on a `simgrid::mc::Process*` (for memory, unwinding information)
233 * and `ucontext_t` (for processor registers).
235 * It works with the `simgrid::mc::UnwindContext` context.
237 unw_accessors_t UnwindContext::accessors = {&find_proc_info, &put_unwind_info, &get_dyn_info_list_addr,
238 &access_mem, &access_reg, &access_fpreg,
239 &resume, &get_proc_name};
241 unw_addr_space_t UnwindContext::createUnwindAddressSpace()
243 return unw_create_addr_space(&UnwindContext::accessors, BYTE_ORDER);
246 void UnwindContext::initialize(simgrid::mc::RemoteClient* process, unw_context_t* c)
248 this->addressSpace_ = process;
249 this->process_ = process;
251 // Take a copy of the context for our own purpose:
252 this->unwindContext_ = *c;
253 #if SIMGRID_PROCESSOR_x86_64 || SIMGRID_PROCESSOR_i686
255 // On x86_64, ucontext_t contains a pointer to itself for FP registers.
256 // We don't really need support for FR registers as they are caller saved
257 // and probably never use those fields as libunwind-x86_64 does not read
258 // FP registers from the unw_context_t
259 // Let's ignore this and see what happens:
260 this->unwindContext_.uc_mcontext.fpregs = nullptr;
263 // Do we need to do any fixup like this?
264 #error Target CPU type is not handled.
268 unw_cursor_t UnwindContext::cursor()
271 if (process_ == nullptr || addressSpace_ == nullptr || unw_init_remote(&cursor, process_->unw_addr_space, this) != 0)
272 xbt_die("UnwindContext not initialized");
277 } // namespace simgrid