1 /* Copyright (c) 2015. 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/ucontext.h>
19 #include <libunwind.h>
21 #include "src/mc/Process.hpp"
22 #include "src/mc/mc_unw.h"
23 #include "src/mc/Frame.hpp"
25 using simgrid::mc::remote;
29 // ***** Implementation
31 /** Get frame unwind information (libunwind method)
33 * Delegates to the local/ptrace implementation.
35 static int find_proc_info(unw_addr_space_t as,
36 unw_word_t ip, unw_proc_info_t *pip,
37 int need_unwind_info, void* arg)
39 mc_unw_context_t context = (mc_unw_context_t) arg;
40 return unw_get_accessors(context->process->unw_underlying_addr_space)->find_proc_info(
41 context->process->unw_underlying_addr_space, ip, pip,
42 need_unwind_info, context->process->unw_underlying_context
46 /** Release frame unwind information (libunwind method)
48 * Delegates to the local/ptrace implementation.
50 static void put_unwind_info(unw_addr_space_t as,
51 unw_proc_info_t *pip, void* arg)
53 mc_unw_context_t context = (mc_unw_context_t) arg;
54 return unw_get_accessors(context->process->unw_underlying_addr_space)->put_unwind_info(
55 context->process->unw_underlying_addr_space, pip,
56 context->process->unw_underlying_context
60 /** (libunwind method)
64 static int get_dyn_info_list_addr(unw_addr_space_t as,
65 unw_word_t *dilap, void* arg)
67 mc_unw_context_t context = (mc_unw_context_t) arg;
68 return unw_get_accessors(context->process->unw_underlying_addr_space)->get_dyn_info_list_addr(
69 context->process->unw_underlying_addr_space,
71 context->process->unw_underlying_context
75 /** Read from the target address space memory (libunwind method)
77 * Delegates to the `simgrid::mc::Process*`.
79 static int access_mem(unw_addr_space_t as,
80 unw_word_t addr, unw_word_t *valp,
83 mc_unw_context_t context = (mc_unw_context_t) arg;
85 return - UNW_EREADONLYREG;
86 context->address_space->read_bytes(valp, sizeof(unw_word_t), remote(addr));
90 static void* get_reg(unw_context_t* context, unw_regnum_t regnum)
93 mcontext_t* mcontext = &context->uc_mcontext;
95 case UNW_X86_64_RAX: return &mcontext->gregs[REG_RAX];
96 case UNW_X86_64_RDX: return &mcontext->gregs[REG_RDX];
97 case UNW_X86_64_RCX: return &mcontext->gregs[REG_RCX];
98 case UNW_X86_64_RBX: return &mcontext->gregs[REG_RBX];
99 case UNW_X86_64_RSI: return &mcontext->gregs[REG_RSI];
100 case UNW_X86_64_RDI: return &mcontext->gregs[REG_RDI];
101 case UNW_X86_64_RBP: return &mcontext->gregs[REG_RBP];
102 case UNW_X86_64_RSP: return &mcontext->gregs[REG_RSP];
103 case UNW_X86_64_R8: return &mcontext->gregs[REG_R8];
104 case UNW_X86_64_R9: return &mcontext->gregs[REG_R9];
105 case UNW_X86_64_R10: return &mcontext->gregs[REG_R10];
106 case UNW_X86_64_R11: return &mcontext->gregs[REG_R11];
107 case UNW_X86_64_R12: return &mcontext->gregs[REG_R12];
108 case UNW_X86_64_R13: return &mcontext->gregs[REG_R13];
109 case UNW_X86_64_R14: return &mcontext->gregs[REG_R14];
110 case UNW_X86_64_R15: return &mcontext->gregs[REG_R15];
111 case UNW_X86_64_RIP: return &mcontext->gregs[REG_RIP];
112 default: return nullptr;
119 /** Read a standard register (libunwind method)
121 static int access_reg(unw_addr_space_t as,
122 unw_regnum_t regnum, unw_word_t *valp,
123 int write, void* arg)
125 mc_unw_context_t as_context = (mc_unw_context_t) arg;
126 unw_context_t* context = &as_context->context;
128 return -UNW_EREADONLYREG;
129 greg_t* preg = (greg_t*) get_reg(context, regnum);
136 /** Read a floating-point register (libunwind method)
138 * FP registers are caller-saved. The values saved by functions such as
139 * `getcontext()` is not relevant for the caller. It is not really necessary
140 * to save and handle them.
142 static int access_fpreg(unw_addr_space_t as,
143 unw_regnum_t regnum, unw_fpreg_t *fpvalp,
144 int write, void* arg)
149 /** Resume the execution of the context (libunwind method)
153 static int resume(unw_addr_space_t as,
154 unw_cursor_t *cp, void* arg)
159 /** Find informations about a function (libunwind method)
161 static int get_proc_name(unw_addr_space_t as,
162 unw_word_t addr, char *bufp,
163 size_t buf_len, unw_word_t *offp,
166 mc_unw_context_t context = (mc_unw_context_t) arg;
167 simgrid::mc::Frame* frame = context->process->find_function(remote(addr));
169 return - UNW_ENOINFO;
170 *offp = (unw_word_t) frame->range.begin() - addr;
172 strncpy(bufp, frame->name.c_str(), buf_len);
173 if (bufp[buf_len - 1]) {
174 bufp[buf_len - 1] = 0;
183 unw_accessors_t mc_unw_accessors =
187 &get_dyn_info_list_addr,
195 // ***** Context management
197 int mc_unw_init_context(
198 mc_unw_context_t context, simgrid::mc::Process* process, unw_context_t* c)
200 context->address_space = process;
201 context->process = process;
203 // Take a copy of the context for our own purpose:
204 context->context = *c;
205 #if defined(PROCESSOR_x86_64) || defined(PROCESSOR_i686)
206 // On x86_64, ucontext_t contains a pointer to itself for FP registers.
207 // We don't really need support for FR registers as they are caller saved
208 // and probably never use those fields as libunwind-x86_64 does not read
209 // FP registers from the unw_context_t
210 // but we fix the pointer in order to avoid dangling pointers:
211 context->context.uc_mcontext.fpregs = &(context->context.__fpregs_mem);
213 // Do we need to do any fixup like this?
214 #error Target CPU type is not handled.
220 // ***** Cursor management
222 int mc_unw_init_cursor(unw_cursor_t *cursor, mc_unw_context_t context)
224 if (!context->process || !context->address_space)
226 return unw_init_remote(cursor, context->process->unw_addr_space, context);