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"
15 #include "mc_location.h"
16 #include "mc/AddressSpace.hpp"
17 #include "mc/Frame.hpp"
18 #include "mc/ObjectInformation.hpp"
20 using simgrid::mc::remote;
24 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
26 if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
27 return MC_EXPRESSION_E_STACK_OVERFLOW;
29 state->stack[state->stack_size++] = value;
33 /** Convert a DWARF register into a libunwind register
35 * DWARF and libunwind does not use the same convention for numbering the
36 * registers on some architectures. The function makes the necessary
39 static int mc_dwarf_register_to_libunwind(int dwarf_register)
41 #if defined(UNW_TARGET_X86_64)
42 // It seems for this arch, DWARF and libunwind agree in the numbering:
43 return dwarf_register;
44 #elif defined(UNW_TARGET_X86)
45 // Could't find the authoritative source of information for this.
46 // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
47 switch (dwarf_register) {
67 return UNW_X86_EFLAGS;
97 xbt_die("Bad/unknown register number.");
100 #error This architecture is not supported yet for DWARF expression evaluation.
104 int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
105 mc_expression_state_t state)
107 for (size_t i = 0; i != n; ++i) {
109 const Dwarf_Op *op = ops + i;
110 uint8_t atom = op->atom;
149 mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
152 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
153 unw_get_reg(state->cursor, register_id, &res);
154 error = mc_dwarf_push_value(state, res + op->number);
158 // Push the CFA (Canonical Frame Addresse):
159 case DW_OP_call_frame_cfa:
161 // UNW_X86_64_CFA does not return the CFA DWARF expects
162 // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
163 // unwind it once in order to find the parent SP:
166 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
169 unw_cursor_t cursor = *(state->cursor);
173 unw_get_reg(&cursor, UNW_TDEP_SP, &res);
174 error = mc_dwarf_push_value(state, res);
182 if (!state->frame_base)
183 return MC_EXPRESSION_E_MISSING_FRAME_BASE;
184 uintptr_t fb = ((uintptr_t) state->frame_base) + op->number;
185 error = mc_dwarf_push_value(state, fb);
192 // Short constant literals:
193 // DW_OP_lit15 pushed the 15 on the stack.
226 error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
229 // Address from the base address of this ELF object.
230 // Push the address on the stack (base_address + argument).
232 if (!state->object_info)
233 return MC_EXPRESSION_E_NO_BASE_ADDRESS;
234 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
235 return MC_EXPRESSION_E_STACK_OVERFLOW;
236 Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
237 state->object_info->base_address() + op->number;
238 error = mc_dwarf_push_value(state, addr);
242 // General constants:
243 // Push the constant argument on the stack.
254 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
255 return MC_EXPRESSION_E_STACK_OVERFLOW;
256 error = mc_dwarf_push_value(state, op->number);
259 // ***** Stack manipulation:
261 // Push another copy/duplicate the value at the top of the stack:
263 if (state->stack_size == 0)
264 return MC_EXPRESSION_E_STACK_UNDERFLOW;
266 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
269 // Pop/drop the top of the stack:
271 if (state->stack_size == 0)
272 return MC_EXPRESSION_E_STACK_UNDERFLOW;
277 // Swap the two top-most value of the stack:
279 if (state->stack_size < 2)
280 return MC_EXPRESSION_E_STACK_UNDERFLOW;
282 uintptr_t temp = state->stack[state->stack_size - 2];
283 state->stack[state->stack_size - 2] =
284 state->stack[state->stack_size - 1];
285 state->stack[state->stack_size - 1] = temp;
289 // Duplicate the value under the top of the stack:
291 if (state->stack_size < 2)
292 return MC_EXPRESSION_E_STACK_UNDERFLOW;
293 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
297 // Those usually take the top of the stack and the next value as argument
298 // and replace the top of the stack with the computed value
299 // (stack.top() += stack.before_top()).
302 if (state->stack_size < 2)
303 return MC_EXPRESSION_E_STACK_UNDERFLOW;
306 state->stack[state->stack_size - 2] +
307 state->stack[state->stack_size - 1];
308 state->stack[state->stack_size - 2] = result;
314 if (state->stack_size < 2)
315 return MC_EXPRESSION_E_STACK_UNDERFLOW;
318 state->stack[state->stack_size - 2] -
319 state->stack[state->stack_size - 1];
320 state->stack[state->stack_size - 2] = result;
325 case DW_OP_plus_uconst:
326 if (state->stack_size == 0)
327 return MC_EXPRESSION_E_STACK_UNDERFLOW;
328 state->stack[state->stack_size - 1] += op->number;
332 if (state->stack_size == 0)
333 return MC_EXPRESSION_E_STACK_UNDERFLOW;
334 state->stack[state->stack_size - 1] =
335 ~state->stack[state->stack_size - 1];
339 if (state->stack_size == 0)
340 return MC_EXPRESSION_E_STACK_UNDERFLOW;
342 intptr_t value = state->stack[state->stack_size - 1];
345 state->stack[state->stack_size - 1] = value;
350 if (state->stack_size < 2)
351 return MC_EXPRESSION_E_STACK_UNDERFLOW;
354 state->stack[state->stack_size - 2] -
355 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;
374 if (state->stack_size < 2)
375 return MC_EXPRESSION_E_STACK_UNDERFLOW;
378 state->stack[state->stack_size -
379 2] | state->stack[state->stack_size - 1];
380 state->stack[state->stack_size - 2] = result;
386 if (state->stack_size < 2)
387 return MC_EXPRESSION_E_STACK_UNDERFLOW;
390 state->stack[state->stack_size -
391 2] ^ state->stack[state->stack_size - 1];
392 state->stack[state->stack_size - 2] = result;
400 // ***** Deference (memory fetch)
402 case DW_OP_deref_size:
403 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
406 if (state->stack_size == 0)
407 return MC_EXPRESSION_E_STACK_UNDERFLOW;
410 uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
411 if (!state->address_space)
412 xbt_die("Missing address space");
413 state->address_space->read_bytes(
414 &state->stack[state->stack_size - 1], sizeof(uintptr_t),
415 remote(address), state->process_index);
421 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
432 /** \brief Resolve a location expression
433 * \deprecated Use mc_dwarf_resolve_expression
435 void mc_dwarf_resolve_location(mc_location_t location,
436 simgrid::mc::DwarfExpression* expression,
437 simgrid::mc::ObjectInformation* object_info,
439 void *frame_pointer_address,
440 simgrid::mc::AddressSpace* address_space, int process_index)
442 s_mc_expression_state_t state;
443 memset(&state, 0, sizeof(s_mc_expression_state_t));
444 state.frame_base = frame_pointer_address;
446 state.address_space = address_space;
447 state.object_info = object_info;
448 state.process_index = process_index;
450 if (expression->size() >= 1
451 && (*expression)[0].atom >=DW_OP_reg0
452 && (*expression)[0].atom <= DW_OP_reg31) {
453 int dwarf_register = (*expression)[0].atom - DW_OP_reg0;
455 "Missing frame context for register operation DW_OP_reg%i",
457 location->memory_location = NULL;
458 location->cursor = c;
459 location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
463 if (mc_dwarf_execute_expression(
464 expression->size(), expression->data(), &state))
465 xbt_die("Error evaluating DWARF expression");
466 if (state.stack_size == 0)
467 xbt_die("No value on the stack");
469 location->memory_location = (void*) state.stack[state.stack_size - 1];
470 location->cursor = NULL;
471 location->register_id = 0;
475 // TODO, move this in a method of LocationList
476 static simgrid::mc::DwarfExpression* mc_find_expression(
477 simgrid::mc::LocationList* locations, unw_word_t ip)
479 for (simgrid::mc::LocationListEntry& entry : *locations)
480 if (entry.valid_for_ip(ip))
481 return &entry.expression;
485 void mc_dwarf_resolve_locations(mc_location_t location,
486 simgrid::mc::LocationList* locations,
487 simgrid::mc::ObjectInformation* object_info,
489 void *frame_pointer_address,
490 simgrid::mc::AddressSpace* address_space,
496 if (unw_get_reg(c, UNW_REG_IP, &ip))
497 xbt_die("Could not resolve IP");
500 simgrid::mc::DwarfExpression* expression = mc_find_expression(locations, ip);
502 mc_dwarf_resolve_location(location,
503 expression, object_info, c,
504 frame_pointer_address, address_space, process_index);
506 xbt_die("Could not resolve location");
510 /** \brief Find the frame base of a given frame
515 void *mc_find_frame_base(simgrid::mc::Frame* frame, simgrid::mc::ObjectInformation* object_info,
516 unw_cursor_t * unw_cursor)
518 s_mc_location_t location;
519 mc_dwarf_resolve_locations(&location,
520 &frame->frame_base, object_info,
521 unw_cursor, NULL, NULL, -1);
522 switch(mc_get_location_type(&location)) {
523 case MC_LOCATION_TYPE_ADDRESS:
524 return location.memory_location;
526 case MC_LOCATION_TYPE_REGISTER: {
527 // This is a special case.
528 // The register if not the location of the frame base
529 // (a frame base cannot be located in a register)
530 // Instead, DWARF defines this to mean that the register
531 // contains the address of the frame base.
533 unw_get_reg(location.cursor, location.register_id, &word);
538 xbt_die("Cannot handle non-address frame base");
539 return NULL; // Unreachable
543 void mc_dwarf_location_list_init(
544 simgrid::mc::LocationList* list, simgrid::mc::ObjectInformation* info,
545 Dwarf_Die * die, Dwarf_Attribute * attr)
549 ptrdiff_t offset = 0;
550 Dwarf_Addr base, start, end;
556 offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
559 else if (offset == -1)
560 xbt_die("Error while loading location list");
562 simgrid::mc::LocationListEntry entry;
563 entry.expression = simgrid::mc::DwarfExpression(ops, ops + len);
565 void *base = info->base_address();
566 // If start == 0, this is not a location list:
567 entry.lowpc = start == 0 ? NULL : (char *) base + start;
568 entry.highpc = start == 0 ? NULL : (char *) base + end;
570 list->push_back(std::move(entry));