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_private.h"
18 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
20 if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
21 return MC_EXPRESSION_E_STACK_OVERFLOW;
23 state->stack[state->stack_size++] = value;
27 /** Convert a DWARF register into a libunwind register
29 * DWARF and libunwind does not use the same convention for numbering the
30 * registers on some architectures. The function makes the necessary
33 static int mc_dwarf_register_to_libunwind(int dwarf_register)
35 #if defined(UNW_TARGET_X86_64)
36 // It seems for this arch, DWARF and libunwind agree in the numbering:
37 return dwarf_register;
38 #elif defined(UNW_TARGET_X86)
39 // Could't find the authoritative source of information for this.
40 // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
41 switch (dwarf_register) {
61 return UNW_X86_EFLAGS;
91 xbt_die("Bad/unknown register number.");
94 #error This architecture is not supported yet for DWARF expression evaluation.
98 int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
99 mc_expression_state_t state)
101 for (size_t i = 0; i != n; ++i) {
103 const Dwarf_Op *op = ops + i;
104 uint8_t atom = op->atom;
143 mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
146 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
147 unw_get_reg(state->cursor, register_id, &res);
148 error = mc_dwarf_push_value(state, res + op->number);
152 // Push the CFA (Canonical Frame Addresse):
153 case DW_OP_call_frame_cfa:
155 // UNW_X86_64_CFA does not return the CFA DWARF expects
156 // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
157 // unwind it once in order to find the parent SP:
160 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
163 unw_cursor_t cursor = *(state->cursor);
167 unw_get_reg(&cursor, UNW_TDEP_SP, &res);
168 error = mc_dwarf_push_value(state, res);
176 if (!state->frame_base)
177 return MC_EXPRESSION_E_MISSING_FRAME_BASE;
178 uintptr_t fb = ((uintptr_t) state->frame_base) + op->number;
179 error = mc_dwarf_push_value(state, fb);
186 // Short constant literals:
187 // DW_OP_lit15 pushed the 15 on the stack.
220 error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
223 // Address from the base address of this ELF object.
224 // Push the address on the stack (base_address + argument).
226 if (!state->object_info)
227 return MC_EXPRESSION_E_NO_BASE_ADDRESS;
228 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
229 return MC_EXPRESSION_E_STACK_OVERFLOW;
230 Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
231 MC_object_base_address(state->object_info) + op->number;
232 error = mc_dwarf_push_value(state, addr);
236 // General constants:
237 // Push the constant argument on the stack.
248 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
249 return MC_EXPRESSION_E_STACK_OVERFLOW;
250 error = mc_dwarf_push_value(state, op->number);
253 // ***** Stack manipulation:
255 // Push another copy/duplicate the value at the top of the stack:
257 if (state->stack_size == 0)
258 return MC_EXPRESSION_E_STACK_UNDERFLOW;
260 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
263 // Pop/drop the top of the stack:
265 if (state->stack_size == 0)
266 return MC_EXPRESSION_E_STACK_UNDERFLOW;
271 // Swap the two top-most value of the stack:
273 if (state->stack_size < 2)
274 return MC_EXPRESSION_E_STACK_UNDERFLOW;
276 uintptr_t temp = state->stack[state->stack_size - 2];
277 state->stack[state->stack_size - 2] =
278 state->stack[state->stack_size - 1];
279 state->stack[state->stack_size - 1] = temp;
283 // Duplicate the value under the top of the stack:
285 if (state->stack_size < 2)
286 return MC_EXPRESSION_E_STACK_UNDERFLOW;
287 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
291 // Those usually take the top of the stack and the next value as argument
292 // and replace the top of the stack with the computed value
293 // (stack.top() += stack.before_top()).
296 if (state->stack_size < 2)
297 return MC_EXPRESSION_E_STACK_UNDERFLOW;
300 state->stack[state->stack_size - 2] +
301 state->stack[state->stack_size - 1];
302 state->stack[state->stack_size - 2] = result;
308 if (state->stack_size < 2)
309 return MC_EXPRESSION_E_STACK_UNDERFLOW;
312 state->stack[state->stack_size - 2] -
313 state->stack[state->stack_size - 1];
314 state->stack[state->stack_size - 2] = result;
319 case DW_OP_plus_uconst:
320 if (state->stack_size == 0)
321 return MC_EXPRESSION_E_STACK_UNDERFLOW;
322 state->stack[state->stack_size - 1] += op->number;
326 if (state->stack_size == 0)
327 return MC_EXPRESSION_E_STACK_UNDERFLOW;
328 state->stack[state->stack_size - 1] =
329 ~state->stack[state->stack_size - 1];
333 if (state->stack_size == 0)
334 return MC_EXPRESSION_E_STACK_UNDERFLOW;
336 intptr_t value = state->stack[state->stack_size - 1];
339 state->stack[state->stack_size - 1] = value;
344 if (state->stack_size < 2)
345 return MC_EXPRESSION_E_STACK_UNDERFLOW;
348 state->stack[state->stack_size - 2] -
349 state->stack[state->stack_size - 1];
350 state->stack[state->stack_size - 2] = result;
356 if (state->stack_size < 2)
357 return MC_EXPRESSION_E_STACK_UNDERFLOW;
360 state->stack[state->stack_size -
361 2] & state->stack[state->stack_size - 1];
362 state->stack[state->stack_size - 2] = result;
368 if (state->stack_size < 2)
369 return MC_EXPRESSION_E_STACK_UNDERFLOW;
372 state->stack[state->stack_size -
373 2] | state->stack[state->stack_size - 1];
374 state->stack[state->stack_size - 2] = result;
380 if (state->stack_size < 2)
381 return MC_EXPRESSION_E_STACK_UNDERFLOW;
384 state->stack[state->stack_size -
385 2] ^ state->stack[state->stack_size - 1];
386 state->stack[state->stack_size - 2] = result;
394 // ***** Deference (memory fetch)
396 case DW_OP_deref_size:
397 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
400 if (state->stack_size == 0)
401 return MC_EXPRESSION_E_STACK_UNDERFLOW;
404 uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
405 if (!state->address_space)
406 xbt_die("Missing address space");
407 MC_address_space_read(
408 state->address_space, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
409 &state->stack[state->stack_size - 1], (const void*) address,
410 sizeof(uintptr_t), state->process_index);
416 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
427 /** \brief Resolve a location expression
428 * \deprecated Use mc_dwarf_resolve_expression
430 void mc_dwarf_resolve_location(mc_location_t location,
431 mc_expression_t expression,
432 mc_object_info_t object_info,
434 void *frame_pointer_address,
435 mc_address_space_t address_space, int process_index)
437 s_mc_expression_state_t state;
438 memset(&state, 0, sizeof(s_mc_expression_state_t));
439 state.frame_base = frame_pointer_address;
441 state.address_space = address_space;
442 state.object_info = object_info;
443 state.process_index = process_index;
445 if (expression->size >= 1
446 && expression->ops[0].atom >=DW_OP_reg0 && expression->ops[0].atom <= DW_OP_reg31) {
447 int dwarf_register = expression->ops[0].atom - DW_OP_reg0;
448 xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i",
450 location->memory_location = NULL;
451 location->cursor = c;
452 location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
456 if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
457 xbt_die("Error evaluating DWARF expression");
458 if (state.stack_size == 0)
459 xbt_die("No value on the stack");
461 location->memory_location = (void*) state.stack[state.stack_size - 1];
462 location->cursor = NULL;
463 location->register_id = 0;
467 static mc_expression_t mc_find_expression(mc_location_list_t locations, unw_word_t ip) {
468 for (size_t i = 0; i != locations->size; ++i) {
469 mc_expression_t expression = locations->locations + i;
470 if ((expression->lowpc == NULL && expression->highpc == NULL)
471 || (ip && ip >= (unw_word_t) expression->lowpc
472 && ip < (unw_word_t) expression->highpc)) {
479 void mc_dwarf_resolve_locations(mc_location_t location,
480 mc_location_list_t locations,
481 mc_object_info_t object_info,
483 void *frame_pointer_address,
484 mc_address_space_t address_space, int process_index)
489 if (unw_get_reg(c, UNW_REG_IP, &ip))
490 xbt_die("Could not resolve IP");
493 mc_expression_t expression = mc_find_expression(locations, ip);
495 mc_dwarf_resolve_location(location,
496 expression, object_info, c,
497 frame_pointer_address, address_space, process_index);
499 xbt_die("Could not resolve location");
503 /** \brief Find the frame base of a given frame
508 void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
509 unw_cursor_t * unw_cursor)
511 s_mc_location_t location;
512 mc_dwarf_resolve_locations(&location,
513 &frame->frame_base, object_info,
514 unw_cursor, NULL, NULL, -1);
515 switch(mc_get_location_type(&location)) {
516 case MC_LOCATION_TYPE_ADDRESS:
517 return location.memory_location;
519 case MC_LOCATION_TYPE_REGISTER: {
520 // This is a special case.
521 // The register if not the location of the frame base
522 // (a frame base cannot be located in a register)
523 // Instead, DWARF defines this to mean that the register
524 // contains the address of the frame base.
526 unw_get_reg(location.cursor, location.register_id, &word);
531 xbt_die("Cannot handle non-address frame base");
532 return NULL; // Unreachable
536 void mc_dwarf_expression_clear(mc_expression_t expression)
538 free(expression->ops);
539 expression->ops = NULL;
540 expression->size = 0;
541 expression->lowpc = NULL;
542 expression->highpc = NULL;
545 void mc_dwarf_location_list_clear(mc_location_list_t list)
547 for (size_t i = 0; i != list->size; ++i) {
548 mc_dwarf_expression_clear(list->locations + i);
550 free(list->locations);
551 list->locations = NULL;
555 void mc_dwarf_expression_init(mc_expression_t expression, size_t len,
558 expression->lowpc = NULL;
559 expression->highpc = NULL;
560 expression->size = len;
561 expression->ops = (Dwarf_Op*) xbt_malloc(len * sizeof(Dwarf_Op));
562 memcpy(expression->ops, ops, len * sizeof(Dwarf_Op));
565 void mc_dwarf_location_list_init_from_expression(mc_location_list_t target,
566 size_t len, Dwarf_Op * ops)
569 target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
570 mc_dwarf_expression_init(target->locations, len, ops);
573 void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
574 Dwarf_Die * die, Dwarf_Attribute * attr)
576 if (list->locations) {
577 mc_dwarf_location_list_clear(list);
581 ptrdiff_t offset = 0;
582 Dwarf_Addr base, start, end;
588 offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
591 else if (offset == -1)
592 xbt_die("Error while loading location list");
597 (mc_expression_t) realloc(list->locations,
598 list->size * sizeof(s_mc_expression_t));
599 mc_expression_t expression = list->locations + i;
600 expression->ops = NULL;
601 mc_dwarf_expression_init(expression, len, ops);
605 flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
606 // If start == 0, this is not a location list:
607 expression->lowpc = start == 0 ? NULL : (char *) base + start;
608 expression->highpc = start == 0 ? NULL : (char *) base + end;