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:
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 "mc_object_info.h"
22 #include "mc_process.h"
25 // ***** Implementation
27 /** Get frame unwind information (libunwind method)
29 * Delegates to the local/ptrace implementation.
31 static int find_proc_info(unw_addr_space_t as,
32 unw_word_t ip, unw_proc_info_t *pip,
33 int need_unwind_info, void* arg)
35 mc_unw_context_t context = (mc_unw_context_t) arg;
36 return unw_get_accessors(context->process->unw_underlying_addr_space)->find_proc_info(
37 context->process->unw_underlying_addr_space, ip, pip,
38 need_unwind_info, context->process->unw_underlying_context
42 /** Release frame unwind information (libunwind method)
44 * Delegates to the local/ptrace implementation.
46 static void put_unwind_info(unw_addr_space_t as,
47 unw_proc_info_t *pip, void* arg)
49 mc_unw_context_t context = (mc_unw_context_t) arg;
50 return unw_get_accessors(context->process->unw_underlying_addr_space)->put_unwind_info(
51 context->process->unw_underlying_addr_space, pip,
52 context->process->unw_underlying_context
56 /** (libunwind method)
60 static int get_dyn_info_list_addr(unw_addr_space_t as,
61 unw_word_t *dilap, void* arg)
63 mc_unw_context_t context = (mc_unw_context_t) arg;
64 return unw_get_accessors(context->process->unw_underlying_addr_space)->get_dyn_info_list_addr(
65 context->process->unw_underlying_addr_space,
67 context->process->unw_underlying_context
71 /** Read from the target address space memory (libunwind method)
73 * Delegates to the `mc_process_t`.
75 static int access_mem(unw_addr_space_t as,
76 unw_word_t addr, unw_word_t *valp,
79 mc_unw_context_t context = (mc_unw_context_t) arg;
81 return -UNW_EREADONLYREG;
82 MC_address_space_read(context->address_space,
83 0, valp, (void*) addr, sizeof(unw_word_t), MC_PROCESS_INDEX_ANY);
84 // We don't handle failure gracefully.
88 static void* get_reg(unw_context_t* context, unw_regnum_t regnum)
91 mcontext_t* mcontext = &context->uc_mcontext;
93 case UNW_X86_64_RAX: return &mcontext->gregs[REG_RAX];
94 case UNW_X86_64_RDX: return &mcontext->gregs[REG_RDX];
95 case UNW_X86_64_RCX: return &mcontext->gregs[REG_RCX];
96 case UNW_X86_64_RBX: return &mcontext->gregs[REG_RBX];
97 case UNW_X86_64_RSI: return &mcontext->gregs[REG_RSI];
98 case UNW_X86_64_RDI: return &mcontext->gregs[REG_RDI];
99 case UNW_X86_64_RBP: return &mcontext->gregs[REG_RBP];
100 case UNW_X86_64_RSP: return &mcontext->gregs[REG_RSP];
101 case UNW_X86_64_R8: return &mcontext->gregs[REG_R8];
102 case UNW_X86_64_R9: return &mcontext->gregs[REG_R9];
103 case UNW_X86_64_R10: return &mcontext->gregs[REG_R10];
104 case UNW_X86_64_R11: return &mcontext->gregs[REG_R11];
105 case UNW_X86_64_R12: return &mcontext->gregs[REG_R12];
106 case UNW_X86_64_R13: return &mcontext->gregs[REG_R13];
107 case UNW_X86_64_R14: return &mcontext->gregs[REG_R14];
108 case UNW_X86_64_R15: return &mcontext->gregs[REG_R15];
109 case UNW_X86_64_RIP: return &mcontext->gregs[REG_RIP];
110 default: return NULL;
117 /** Read a standard register (libunwind method)
119 static int access_reg(unw_addr_space_t as,
120 unw_regnum_t regnum, unw_word_t *valp,
121 int write, void* arg)
123 mc_unw_context_t as_context = (mc_unw_context_t) arg;
124 unw_context_t* context = &as_context->context;
126 return -UNW_EREADONLYREG;
127 greg_t* preg = get_reg(context, regnum);
134 /** Read a floating-point register (libunwind method)
136 * FP registers are caller-saved. The values saved by functions such as
137 * `getcontext()` is not relevant for the caller. It is not really necessary
138 * to save and handle them.
140 static int access_fpreg(unw_addr_space_t as,
141 unw_regnum_t regnum, unw_fpreg_t *fpvalp,
142 int write, void* arg)
147 /** Resume the execution of the context (libunwind method)
151 static int resume(unw_addr_space_t as,
152 unw_cursor_t *cp, void* arg)
157 /** Find informations about a function (libunwind method)
159 static int get_proc_name(unw_addr_space_t as,
160 unw_word_t addr, char *bufp,
161 size_t buf_len, unw_word_t *offp,
164 mc_unw_context_t context = (mc_unw_context_t) arg;
165 dw_frame_t frame = MC_process_find_function(context->process, (void*) addr);
167 return - UNW_ENOINFO;
168 *offp = (unw_word_t) frame->low_pc - addr;
170 strncpy(bufp, frame->name, buf_len);
171 if (bufp[buf_len - 1]) {
172 bufp[buf_len - 1] = 0;
181 unw_accessors_t mc_unw_accessors =
183 .find_proc_info = &find_proc_info,
184 .put_unwind_info = &put_unwind_info,
185 .get_dyn_info_list_addr = &get_dyn_info_list_addr,
186 .access_mem = &access_mem,
187 .access_reg = &access_reg,
188 .access_fpreg = &access_fpreg,
190 .get_proc_name = &get_proc_name
193 // ***** Context management
195 int mc_unw_init_context(
196 mc_unw_context_t context, mc_process_t process, unw_context_t* c)
198 context->address_space = (mc_address_space_t) process;
199 context->process = process;
201 // Take a copy of the context for our own purpose:
202 context->context = *c;
203 #if defined(PROCESSOR_x86_64) || defined(PROCESSOR_i686)
204 // On x86_64, ucontext_t contains a pointer to itself for FP registers.
205 // We don't really need support for FR registers as they are caller saved
206 // and probably never use those fields as libunwind-x86_64 does not read
207 // FP registers from the unw_context_t
208 // but we fix the pointer in order to avoid dangling pointers:
209 context->context.uc_mcontext.fpregs = &(context->context.__fpregs_mem);
211 // Do we need to do any fixup like this?
212 #error Target CPU type is not handled.
218 int mc_unw_destroy_context(mc_unw_context_t context)
220 context->address_space = NULL;
221 context->process = NULL;
225 // ***** Cursor management
227 int mc_unw_init_cursor(unw_cursor_t *cursor, mc_unw_context_t context)
229 if (!context->process || !context->address_space)
231 mc_address_space_t as = context->address_space;
233 // Use local unwinding for current process:
234 if (MC_is_process(as) && MC_process_is_self((mc_process_t) as))
235 return unw_init_local(cursor, &context->context);
237 return unw_init_remote(cursor, context->process->unw_addr_space, context);