Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Remove spurious "using" declarations.
[simgrid.git] / src / mc / inspect / mc_unw.cpp
1 /* Copyright (c) 2015-2022. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 /** \file
7  *  Libunwind support for mc_address_space objects.
8  */
9
10 // We need this for the register indices:
11 // #define _GNU_SOURCE
12
13 #include "src/mc/inspect/mc_unw.hpp"
14 #include "src/mc/inspect/Frame.hpp"
15 #include "src/mc/remote/RemoteProcess.hpp"
16
17 #include <cstring>
18
19 // On x86_64, libunwind unw_context_t has the same layout as ucontext_t:
20 #include <sys/types.h>
21 #include <sys/ucontext.h>
22 #ifdef __FreeBSD__
23 typedef register_t greg_t;
24 #endif
25
26 #include <libunwind.h>
27
28 namespace simgrid {
29 namespace mc {
30
31 // ***** Implementation
32
33 /** Get frame unwind information (libunwind method)
34  *
35  *  Delegates to the local/ptrace implementation.
36  */
37 int UnwindContext::find_proc_info(unw_addr_space_t /*as*/, unw_word_t ip, unw_proc_info_t* pip, int need_unwind_info,
38                                   void* arg) noexcept
39 {
40   const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
41   return unw_get_accessors(context->process_->unw_underlying_addr_space)
42       ->find_proc_info(context->process_->unw_underlying_addr_space, ip, pip, need_unwind_info,
43                        context->process_->unw_underlying_context);
44 }
45
46 /** Release frame unwind information (libunwind method)
47  *
48  *  Delegates to the local/ptrace implementation.
49  */
50 void UnwindContext::put_unwind_info(unw_addr_space_t /*as*/, unw_proc_info_t* pip, void* arg) noexcept
51 {
52   const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
53   return unw_get_accessors(context->process_->unw_underlying_addr_space)
54       ->put_unwind_info(context->process_->unw_underlying_addr_space, pip, context->process_->unw_underlying_context);
55 }
56
57 /** (libunwind method)
58  *
59  *  Not implemented.
60  */
61 int UnwindContext::get_dyn_info_list_addr(unw_addr_space_t /*as*/, unw_word_t* dilap, void* arg) noexcept
62 {
63   const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
64   return unw_get_accessors(context->process_->unw_underlying_addr_space)
65       ->get_dyn_info_list_addr(context->process_->unw_underlying_addr_space, dilap,
66                                context->process_->unw_underlying_context);
67 }
68
69 /** Read from the target address space memory (libunwind method)
70  *
71  *  Delegates to the `simgrid::mc::Process*`.
72  */
73 int UnwindContext::access_mem(unw_addr_space_t /*as*/, unw_word_t addr, unw_word_t* valp, int write, void* arg) noexcept
74 {
75   const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
76   if (write)
77     return -UNW_EREADONLYREG;
78   context->address_space_->read_bytes(valp, sizeof(unw_word_t), remote(addr));
79   return 0;
80 }
81
82 void* UnwindContext::get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept
83 {
84 #ifdef __x86_64
85   mcontext_t* mcontext = &context->uc_mcontext;
86   switch (regnum) {
87 #ifdef __linux__
88     case UNW_X86_64_RAX:
89       return &mcontext->gregs[REG_RAX];
90     case UNW_X86_64_RDX:
91       return &mcontext->gregs[REG_RDX];
92     case UNW_X86_64_RCX:
93       return &mcontext->gregs[REG_RCX];
94     case UNW_X86_64_RBX:
95       return &mcontext->gregs[REG_RBX];
96     case UNW_X86_64_RSI:
97       return &mcontext->gregs[REG_RSI];
98     case UNW_X86_64_RDI:
99       return &mcontext->gregs[REG_RDI];
100     case UNW_X86_64_RBP:
101       return &mcontext->gregs[REG_RBP];
102     case UNW_X86_64_RSP:
103       return &mcontext->gregs[REG_RSP];
104     case UNW_X86_64_R8:
105       return &mcontext->gregs[REG_R8];
106     case UNW_X86_64_R9:
107       return &mcontext->gregs[REG_R9];
108     case UNW_X86_64_R10:
109       return &mcontext->gregs[REG_R10];
110     case UNW_X86_64_R11:
111       return &mcontext->gregs[REG_R11];
112     case UNW_X86_64_R12:
113       return &mcontext->gregs[REG_R12];
114     case UNW_X86_64_R13:
115       return &mcontext->gregs[REG_R13];
116     case UNW_X86_64_R14:
117       return &mcontext->gregs[REG_R14];
118     case UNW_X86_64_R15:
119       return &mcontext->gregs[REG_R15];
120     case UNW_X86_64_RIP:
121       return &mcontext->gregs[REG_RIP];
122 #elif defined __FreeBSD__
123     case UNW_X86_64_RAX:
124       return &mcontext->mc_rax;
125     case UNW_X86_64_RDX:
126       return &mcontext->mc_rdx;
127     case UNW_X86_64_RCX:
128       return &mcontext->mc_rcx;
129     case UNW_X86_64_RBX:
130       return &mcontext->mc_rbx;
131     case UNW_X86_64_RSI:
132       return &mcontext->mc_rsi;
133     case UNW_X86_64_RDI:
134       return &mcontext->mc_rdi;
135     case UNW_X86_64_RBP:
136       return &mcontext->mc_rbp;
137     case UNW_X86_64_RSP:
138       return &mcontext->mc_rsp;
139     case UNW_X86_64_R8:
140       return &mcontext->mc_r8;
141     case UNW_X86_64_R9:
142       return &mcontext->mc_r9;
143     case UNW_X86_64_R10:
144       return &mcontext->mc_r10;
145     case UNW_X86_64_R11:
146       return &mcontext->mc_r11;
147     case UNW_X86_64_R12:
148       return &mcontext->mc_r12;
149     case UNW_X86_64_R13:
150       return &mcontext->mc_r13;
151     case UNW_X86_64_R14:
152       return &mcontext->mc_r14;
153     case UNW_X86_64_R15:
154       return &mcontext->mc_r15;
155     case UNW_X86_64_RIP:
156       return &mcontext->mc_rip;
157 #else
158 #error "Unable to get register from ucontext, please add your case"
159 #endif
160     default:
161       return nullptr;
162   }
163 #else
164   return nullptr;
165 #endif
166 }
167
168 /** Read a standard register (libunwind method)
169  */
170 int UnwindContext::access_reg(unw_addr_space_t /*as*/, unw_regnum_t regnum, unw_word_t* valp, int write,
171                               void* arg) noexcept
172 {
173   auto* as_context       = static_cast<simgrid::mc::UnwindContext*>(arg);
174   unw_context_t* context = &as_context->unwind_context_;
175   if (write)
176     return -UNW_EREADONLYREG;
177   const greg_t* preg = (greg_t*)get_reg(context, regnum);
178   if (not preg)
179     return -UNW_EBADREG;
180   *valp = *preg;
181   return 0;
182 }
183
184 /** Find information about a function (libunwind method)
185  */
186 int UnwindContext::get_proc_name(unw_addr_space_t /*as*/, unw_word_t addr, char* bufp, size_t buf_len, unw_word_t* offp,
187                                  void* arg) noexcept
188 {
189   const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
190   const simgrid::mc::Frame* frame           = context->process_->find_function(remote(addr));
191   if (not frame)
192     return -UNW_ENOINFO;
193   *offp = (unw_word_t)frame->range.begin() - addr;
194
195   strncpy(bufp, frame->name.c_str(), buf_len);
196   if (bufp[buf_len - 1]) {
197     bufp[buf_len - 1] = 0;
198     return -UNW_ENOMEM;
199   }
200
201   return 0;
202 }
203
204 // ***** Init
205
206 unw_addr_space_t UnwindContext::createUnwindAddressSpace()
207 {
208   /** Virtual table for our `libunwind` implementation
209    *
210    *  Stack unwinding on a `simgrid::mc::Process*` (for memory, unwinding information)
211    *  and `ucontext_t` (for processor registers).
212    *
213    * It works with the `simgrid::mc::UnwindContext` context.
214    *
215    * Use nullptr as access_fpreg and resume, as we don't need them.
216    */
217   unw_accessors_t accessors = {&find_proc_info, &put_unwind_info, &get_dyn_info_list_addr, &access_mem, &access_reg,
218                                nullptr,         nullptr,          &get_proc_name};
219   return unw_create_addr_space(&accessors, BYTE_ORDER);
220 }
221
222 void UnwindContext::initialize(simgrid::mc::RemoteProcess* process, unw_context_t* c)
223 {
224   this->address_space_ = process;
225   this->process_      = process;
226
227   // Take a copy of the context for our own purpose:
228   this->unwind_context_ = *c;
229 #if SIMGRID_PROCESSOR_x86_64 || SIMGRID_PROCESSOR_i686 || defined(__aarch64__)
230 #ifdef __linux__
231   // On x86_64, ucontext_t contains a pointer to itself for FP registers.
232   // We don't really need support for FR registers as they are caller saved
233   // and probably never use those fields as libunwind-x86_64 does not read
234   // FP registers from the unw_context_t
235   // Let's ignore this and see what happens:
236   this->unwind_context_.uc_mcontext.fpregs = nullptr;
237 #endif
238 #else
239   // Do we need to do any fixup like this?
240 #error Target CPU type is not handled.
241 #endif
242 }
243
244 unw_cursor_t UnwindContext::cursor()
245 {
246   unw_cursor_t cursor;
247   xbt_assert(process_ != nullptr && address_space_ != nullptr &&
248                  unw_init_remote(&cursor, process_->unw_addr_space, this) == 0,
249              "UnwindContext not initialized");
250   return cursor;
251 }
252
253 } // namespace mc
254 } // namespace simgrid