1 /* Copyright (c) 2014-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. */
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"
19 #include "mc/DwarfExpression.hpp"
21 using simgrid::mc::remote;
26 evaluation_error::~evaluation_error() {}
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(__x86_64__)
42 // It seems for this arch, DWARF and libunwind agree in the numbering:
43 return dwarf_register;
44 #elif defined(__i386__)
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.
110 const Dwarf_Op* ops, std::size_t n,
111 const ExpressionContext& context, ExpressionStack& stack)
113 for (size_t i = 0; i != n; ++i) {
114 const Dwarf_Op *op = ops + i;
115 std::uint8_t atom = op->atom;
154 mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
157 throw evaluation_error("Missin stack context");
158 unw_get_reg(context.cursor, register_id, &res);
159 stack.push(res + op->number);
163 // Push the CFA (Canonical Frame Addresse):
164 case DW_OP_call_frame_cfa:
166 // UNW_X86_64_CFA does not return the CFA DWARF expects
167 // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
168 // unwind it once in order to find the parent SP:
171 throw evaluation_error("Missint cursor");
174 unw_cursor_t cursor = *(context.cursor);
178 unw_get_reg(&cursor, UNW_REG_SP, &res);
186 stack.push((std::uintptr_t) context.frame_base + op->number);
191 // Short constant literals:
192 // DW_OP_lit15 pushed the 15 on the stack.
225 stack.push(atom - DW_OP_lit0);
228 // Address from the base address of this ELF object.
229 // Push the address on the stack (base_address + argument).
231 if (!context.object_info)
232 throw evaluation_error("No base address");
233 Dwarf_Off addr = (Dwarf_Off) (std::uintptr_t)
234 context.object_info->base_address() + op->number;
239 // General constants:
240 // Push the constant argument on the stack.
251 stack.push(op->number);
254 // ***** Stack manipulation:
256 // Push another copy/duplicate the value at the top of the stack:
261 // Pop/drop the top of the stack:
266 // Swap the two top-most value of the stack:
268 std::swap(stack.top(), stack.top(1));
271 // Duplicate the value under the top of the stack:
273 stack.push(stack.top(1));
277 // Those usually take the top of the stack and the next value as argument
278 // and replace the top of the stack with the computed value
279 // (stack.top() += stack.before_top()).
282 stack.push(stack.pop() + stack.pop());
286 stack.push(stack.pop() * stack.pop());
289 case DW_OP_plus_uconst:
290 stack.top() += op->number;
294 stack.top() = ~stack.top();
298 stack.top() = - (intptr_t) stack.top();
302 stack.push(stack.pop() - stack.pop());
306 stack.push(stack.pop() & stack.pop());
310 stack.push(stack.pop() | stack.pop());
314 stack.push(stack.pop() ^ stack.pop());
320 // ***** Deference (memory fetch)
322 case DW_OP_deref_size:
323 throw evaluation_error("Unsupported operation");
327 if (!context.address_space)
328 throw evaluation_error("Missing address space");
329 context.address_space->read_bytes(
330 &stack.top(), sizeof(uintptr_t), remote(stack.top()),
331 context.process_index);
336 throw evaluation_error("Unsupported operation");
344 /** \brief Resolve a location expression
345 * \deprecated Use mc_dwarf_resolve_expression
347 void resolve_location(mc_location_t location,
348 simgrid::dwarf::DwarfExpression const& expression,
349 simgrid::mc::ObjectInformation* object_info,
351 void *frame_pointer_address,
352 simgrid::mc::AddressSpace* address_space, int process_index)
354 simgrid::dwarf::ExpressionContext context;
355 context.frame_base = frame_pointer_address;
357 context.address_space = address_space;
358 context.object_info = object_info;
359 context.process_index = process_index;
361 if (!expression.empty()
362 && expression[0].atom >= DW_OP_reg0
363 && expression[0].atom <= DW_OP_reg31) {
364 int dwarf_register = expression[0].atom - DW_OP_reg0;
366 "Missing frame context for register operation DW_OP_reg%i",
368 location->memory_location = NULL;
369 location->cursor = c;
370 location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
374 simgrid::dwarf::ExpressionStack stack;
375 simgrid::dwarf::execute(expression, context, stack);
377 location->memory_location = (void*) stack.top();
378 location->cursor = NULL;
379 location->register_id = 0;
385 // TODO, move this in a method of LocationList
386 static simgrid::dwarf::DwarfExpression* mc_find_expression(
387 simgrid::mc::LocationList* locations, unw_word_t ip)
389 for (simgrid::mc::LocationListEntry& entry : *locations)
390 if (entry.valid_for_ip(ip))
391 return &entry.expression;
397 void mc_dwarf_resolve_locations(mc_location_t location,
398 simgrid::mc::LocationList* locations,
399 simgrid::mc::ObjectInformation* object_info,
401 void *frame_pointer_address,
402 simgrid::mc::AddressSpace* address_space,
408 if (unw_get_reg(c, UNW_REG_IP, &ip))
409 xbt_die("Could not resolve IP");
412 simgrid::dwarf::DwarfExpression* expression =
413 mc_find_expression(locations, ip);
415 simgrid::dwarf::resolve_location(location,
416 *expression, object_info, c,
417 frame_pointer_address, address_space, process_index);
419 xbt_die("Could not resolve location");
423 /** \brief Find the frame base of a given frame
428 void *mc_find_frame_base(simgrid::mc::Frame* frame, simgrid::mc::ObjectInformation* object_info,
429 unw_cursor_t * unw_cursor)
431 s_mc_location_t location;
432 mc_dwarf_resolve_locations(&location,
433 &frame->frame_base, object_info,
434 unw_cursor, NULL, NULL, -1);
435 switch(mc_get_location_type(&location)) {
436 case MC_LOCATION_TYPE_ADDRESS:
437 return location.memory_location;
439 case MC_LOCATION_TYPE_REGISTER: {
440 // This is a special case.
441 // The register if not the location of the frame base
442 // (a frame base cannot be located in a register)
443 // Instead, DWARF defines this to mean that the register
444 // contains the address of the frame base.
446 unw_get_reg(location.cursor, location.register_id, &word);
451 xbt_die("Cannot handle non-address frame base");
452 return NULL; // Unreachable
456 void mc_dwarf_location_list_init(
457 simgrid::mc::LocationList* list, simgrid::mc::ObjectInformation* info,
458 Dwarf_Die * die, Dwarf_Attribute * attr)
462 std::ptrdiff_t offset = 0;
463 Dwarf_Addr base, start, end;
469 offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
472 else if (offset == -1)
473 xbt_die("Error while loading location list");
475 simgrid::mc::LocationListEntry entry;
476 entry.expression = simgrid::dwarf::DwarfExpression(ops, ops + len);
478 void *base = info->base_address();
479 // If start == 0, this is not a location list:
480 entry.lowpc = start == 0 ? NULL : (char *) base + start;
481 entry.highpc = start == 0 ? NULL : (char *) base + end;
483 list->push_back(std::move(entry));