1 /* Copyright (c) 2014. 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. */
11 #include <elfutils/libdw.h>
13 #include "mc_object_info.h"
14 #include "mc_snapshot.h"
15 #include "mc_private.h"
17 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
19 if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
20 return MC_EXPRESSION_E_STACK_OVERFLOW;
22 state->stack[state->stack_size++] = value;
26 static int mc_dwarf_register_to_libunwind(int dwarf_register)
28 #if defined(UNW_TARGET_X86_64)
29 // It seems for this arch, DWARF and libunwind agree in the numbering:
30 return dwarf_register;
31 #elif defined(UNW_TARGET_X86)
32 // Could't find the authoritative source of information for this.
33 // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
34 switch (dwarf_register) {
54 return UNW_X86_EFLAGS;
84 xbt_die("Bad/unknown register number.");
87 #error This architecture is not supported yet.
91 int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
92 mc_expression_state_t state)
94 for (int i = 0; i != n; ++i) {
96 const Dwarf_Op *op = ops + i;
97 uint8_t atom = op->atom;
136 mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
139 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
140 unw_get_reg(state->cursor, register_id, &res);
141 error = mc_dwarf_push_value(state, res + op->number);
145 // Push the CFA (Canonical Frame Addresse):
146 case DW_OP_call_frame_cfa:
148 // UNW_X86_64_CFA does not return the CFA DWARF expects
149 // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
150 // unwind it once in order to find the parent SP:
153 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
156 unw_cursor_t cursor = *(state->cursor);
160 unw_get_reg(&cursor, UNW_TDEP_SP, &res);
161 error = mc_dwarf_push_value(state, res);
169 if (!state->frame_base)
170 return MC_EXPRESSION_E_MISSING_FRAME_BASE;
172 mc_dwarf_push_value(state,
173 ((uintptr_t) state->frame_base) + op->number);
212 error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
216 if (!state->object_info)
217 return MC_EXPRESSION_E_NO_BASE_ADDRESS;
218 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
219 return MC_EXPRESSION_E_STACK_OVERFLOW;
220 error = mc_dwarf_push_value(state,
221 (Dwarf_Off) (uintptr_t)
222 MC_object_base_address(state->object_info) +
236 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
237 return MC_EXPRESSION_E_STACK_OVERFLOW;
238 error = mc_dwarf_push_value(state, op->number);
241 // Stack manipulation:
243 // Push the value at the top of the stack:
245 if (state->stack_size == 0)
246 return MC_EXPRESSION_E_STACK_UNDERFLOW;
248 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
252 if (state->stack_size == 0)
253 return MC_EXPRESSION_E_STACK_UNDERFLOW;
259 if (state->stack_size < 2)
260 return MC_EXPRESSION_E_STACK_UNDERFLOW;
262 uintptr_t temp = state->stack[state->stack_size - 2];
263 state->stack[state->stack_size - 2] =
264 state->stack[state->stack_size - 1];
265 state->stack[state->stack_size - 1] = temp;
270 if (state->stack_size < 2)
271 return MC_EXPRESSION_E_STACK_UNDERFLOW;
272 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
278 if (state->stack_size < 2)
279 return MC_EXPRESSION_E_STACK_UNDERFLOW;
282 state->stack[state->stack_size - 2] +
283 state->stack[state->stack_size - 1];
284 state->stack[state->stack_size - 2] = result;
290 if (state->stack_size < 2)
291 return MC_EXPRESSION_E_STACK_UNDERFLOW;
294 state->stack[state->stack_size - 2] -
295 state->stack[state->stack_size - 1];
296 state->stack[state->stack_size - 2] = result;
301 case DW_OP_plus_uconst:
302 if (state->stack_size == 0)
303 return MC_EXPRESSION_E_STACK_UNDERFLOW;
304 state->stack[state->stack_size - 1] += op->number;
308 if (state->stack_size == 0)
309 return MC_EXPRESSION_E_STACK_UNDERFLOW;
310 state->stack[state->stack_size - 1] =
311 ~state->stack[state->stack_size - 1];
315 if (state->stack_size == 0)
316 return MC_EXPRESSION_E_STACK_UNDERFLOW;
318 intptr_t value = state->stack[state->stack_size - 1];
321 state->stack[state->stack_size - 1] = value;
326 if (state->stack_size < 2)
327 return MC_EXPRESSION_E_STACK_UNDERFLOW;
330 state->stack[state->stack_size - 2] -
331 state->stack[state->stack_size - 1];
332 state->stack[state->stack_size - 2] = result;
338 if (state->stack_size < 2)
339 return MC_EXPRESSION_E_STACK_UNDERFLOW;
342 state->stack[state->stack_size -
343 2] & state->stack[state->stack_size - 1];
344 state->stack[state->stack_size - 2] = result;
350 if (state->stack_size < 2)
351 return MC_EXPRESSION_E_STACK_UNDERFLOW;
354 state->stack[state->stack_size -
355 2] | state->stack[state->stack_size - 1];
356 state->stack[state->stack_size - 2] = result;
362 if (state->stack_size < 2)
363 return MC_EXPRESSION_E_STACK_UNDERFLOW;
366 state->stack[state->stack_size -
367 2] ^ state->stack[state->stack_size - 1];
368 state->stack[state->stack_size - 2] = result;
377 case DW_OP_deref_size:
378 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
381 if (state->stack_size == 0)
382 return MC_EXPRESSION_E_STACK_UNDERFLOW;
385 uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
387 uintptr_t* res = (uintptr_t*) mc_snapshot_read((void*) address, state->snapshot, state->process_index, &temp, sizeof(uintptr_t));
388 state->stack[state->stack_size - 1] = *res;
394 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
405 /** \brief Resolve a location expression
406 * \deprecated Use mc_dwarf_resolve_expression
408 void mc_dwarf_resolve_location(mc_location_t location,
409 mc_expression_t expression,
410 mc_object_info_t object_info,
412 void *frame_pointer_address,
413 mc_snapshot_t snapshot, int process_index)
415 s_mc_expression_state_t state;
416 memset(&state, 0, sizeof(s_mc_expression_state_t));
417 state.frame_base = frame_pointer_address;
419 state.snapshot = snapshot;
420 state.object_info = object_info;
421 state.process_index = process_index;
423 if (expression->size >= 1
424 && expression->ops[0].atom >=DW_OP_reg0 && expression->ops[0].atom <= DW_OP_reg31) {
425 int dwarf_register = expression->ops[0].atom - DW_OP_reg0;
426 xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i",
428 location->memory_location = NULL;
429 location->cursor = c;
430 location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
434 if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
435 xbt_die("Error evaluating DWARF expression");
436 if (state.stack_size == 0)
437 xbt_die("No value on the stack");
439 location->memory_location = (void*) state.stack[state.stack_size - 1];
440 location->cursor = NULL;
441 location->register_id = 0;
445 static mc_expression_t mc_find_expression(mc_location_list_t locations, unw_word_t ip) {
446 for (size_t i = 0; i != locations->size; ++i) {
447 mc_expression_t expression = locations->locations + i;
448 if ((expression->lowpc == NULL && expression->highpc == NULL)
449 || (ip && ip >= (unw_word_t) expression->lowpc
450 && ip < (unw_word_t) expression->highpc)) {
457 void mc_dwarf_resolve_locations(mc_location_t location,
458 mc_location_list_t locations,
459 mc_object_info_t object_info,
461 void *frame_pointer_address,
462 mc_snapshot_t snapshot, int process_index)
467 if (unw_get_reg(c, UNW_REG_IP, &ip))
468 xbt_die("Could not resolve IP");
471 mc_expression_t expression = mc_find_expression(locations, ip);
473 mc_dwarf_resolve_location(location,
474 expression, object_info, c,
475 frame_pointer_address, snapshot, process_index);
477 xbt_die("Could not resolve location");
481 /** \brief Find the frame base of a given frame
486 void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
487 unw_cursor_t * unw_cursor)
489 s_mc_location_t location;
490 mc_dwarf_resolve_locations(&location,
491 &frame->frame_base, object_info,
492 unw_cursor, NULL, NULL, -1);
493 switch(mc_get_location_type(&location)) {
494 case MC_LOCATION_TYPE_ADDRESS:
495 return location.memory_location;
497 case MC_LOCATION_TYPE_REGISTER: {
498 // This is a special case.
499 // The register if not the location of the frame base
500 // (a frame base cannot be located in a register)
501 // Instead, DWARF defines this to mean that the register
502 // contains the address of the frame base.
504 unw_get_reg(location.cursor, location.register_id, &word);
509 xbt_die("Cannot handle non-address frame base");
510 return NULL; // Unreachable
514 void mc_dwarf_expression_clear(mc_expression_t expression)
516 free(expression->ops);
517 expression->ops = NULL;
518 expression->size = 0;
519 expression->lowpc = NULL;
520 expression->highpc = NULL;
523 void mc_dwarf_location_list_clear(mc_location_list_t list)
525 for (size_t i = 0; i != list->size; ++i) {
526 mc_dwarf_expression_clear(list->locations + i);
528 free(list->locations);
529 list->locations = NULL;
533 void mc_dwarf_expression_init(mc_expression_t expression, size_t len,
536 expression->lowpc = NULL;
537 expression->highpc = NULL;
538 expression->size = len;
539 expression->ops = xbt_malloc(len * sizeof(Dwarf_Op));
540 memcpy(expression->ops, ops, len * sizeof(Dwarf_Op));
543 void mc_dwarf_location_list_init_from_expression(mc_location_list_t target,
544 size_t len, Dwarf_Op * ops)
547 target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
548 mc_dwarf_expression_init(target->locations, len, ops);
551 void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
552 Dwarf_Die * die, Dwarf_Attribute * attr)
554 if (list->locations) {
555 mc_dwarf_location_list_clear(list);
559 ptrdiff_t offset = 0;
560 Dwarf_Addr base, start, end;
566 offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
569 else if (offset == -1)
570 xbt_die("Error while loading location list");
575 (mc_expression_t) realloc(list->locations,
576 list->size * sizeof(s_mc_expression_t));
577 mc_expression_t expression = list->locations + i;
578 expression->ops = NULL;
579 mc_dwarf_expression_init(expression, len, ops);
583 flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
584 // If start == 0, this is not a location list:
585 expression->lowpc = start == 0 ? NULL : (char *) base + start;
586 expression->highpc = start == 0 ? NULL : (char *) base + end;