Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Partial implementation of DWARF expression evaluator
authorGabriel Corona <gabriel.corona@loria.fr>
Thu, 6 Mar 2014 14:06:56 +0000 (15:06 +0100)
committerGabriel Corona <gabriel.corona@loria.fr>
Thu, 6 Mar 2014 14:09:47 +0000 (15:09 +0100)
In order to resolve complexe location expressions of (C++ object)
inheritance relationships, it is necessary to implement a real DWARF
expression stack machine.

buildtools/Cmake/AddTests.cmake
buildtools/Cmake/DefinePackages.cmake
buildtools/Cmake/MakeExe.cmake
src/mc/mc_dwarf_expression.c [new file with mode: 0644]
src/mc/mc_private.h
testsuite/mc/CMakeLists.txt [new file with mode: 0644]
testsuite/mc/dwarf.c [new file with mode: 0644]
testsuite/mc/dwarf_expression.c [new file with mode: 0644]

index 9d5814c..658b0c7 100644 (file)
@@ -633,6 +633,11 @@ add_test(test-surf-usage                        ${CMAKE_BINARY_DIR}/testsuite/su
 add_test(test-surf-usage2                       ${CMAKE_BINARY_DIR}/testsuite/surf/surf_usage2 --cfg=path:${CMAKE_HOME_DIRECTORY}/testsuite/surf/ platform.xml)
 add_test(test-surf-trace                        ${CMAKE_BINARY_DIR}/testsuite/surf/trace_usage --cfg=path:${CMAKE_HOME_DIRECTORY}/testsuite/surf/)
 
+if(HAVE_MC)
+  add_test(mc-dwarf                             ${CMAKE_BINARY_DIR}/testsuite/mc/dwarf)
+  add_test(mc-dwarf-expression                  ${CMAKE_BINARY_DIR}/testsuite/mc/dwarf-expression)
+endif()
+
 add_test(testall                                ${CMAKE_BINARY_DIR}/src/testall)
 
 if(enable_auto_install)
index 622d35f..eacfccb 100644 (file)
@@ -543,6 +543,7 @@ set(MC_SRC
   src/mc/mc_dpor.c
   src/mc/mc_global.c
   src/mc/mc_dwarf.c
+  src/mc/mc_dwarf_expression.c
   src/mc/mc_liveness.c
   src/mc/mc_memory.c
   src/mc/mc_private.h
@@ -986,6 +987,7 @@ set(TOOLS_CMAKEFILES_TXT
 set(TESTSUITE_CMAKEFILES_TXT
   testsuite/surf/CMakeLists.txt
   testsuite/xbt/CMakeLists.txt
+  testsuite/mc/CMakeLists.txt
   )
 
 set(CMAKE_SOURCE_FILES
index c854fb5..b9a64be 100644 (file)
@@ -116,6 +116,7 @@ add_subdirectory(${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/f90/pt2pt)
 
 add_subdirectory(${CMAKE_HOME_DIRECTORY}/teshsuite/xbt)
 
+add_subdirectory(${CMAKE_HOME_DIRECTORY}/testsuite/mc)
 add_subdirectory(${CMAKE_HOME_DIRECTORY}/testsuite/surf)
 add_subdirectory(${CMAKE_HOME_DIRECTORY}/testsuite/xbt)
 
diff --git a/src/mc/mc_dwarf_expression.c b/src/mc/mc_dwarf_expression.c
new file mode 100644 (file)
index 0000000..a73ac2f
--- /dev/null
@@ -0,0 +1,238 @@
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+
+#include "mc_private.h"
+
+static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value) {
+  if(state->stack_size>=MC_EXPRESSION_STACK_SIZE)
+    return MC_EXPRESSION_E_STACK_OVERFLOW;
+
+  state->stack[state->stack_size++] = value;
+  return 0;
+}
+
+int mc_dwarf_execute_expression(
+  size_t n, const Dwarf_Op* ops, mc_expression_state_t state) {
+  for(int i=0; i!=n; ++i) {
+    int error = 0;
+    const Dwarf_Op* op = ops + i;
+    uint8_t atom = op->atom;
+
+    switch (atom) {
+
+    // Registers:
+
+    case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3:
+    case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7:
+    case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11:
+    case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15:
+    case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19:
+    case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
+    case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27:
+    case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31:{
+        int register_id = op->atom - DW_OP_breg0;
+        unw_word_t res;
+        if(!state->cursor)
+          return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
+        unw_get_reg(state->cursor, register_id, &res);
+        error = mc_dwarf_push_value(state, res + op->number);
+        break;
+      }
+
+    // Frame base:
+
+    case DW_OP_fbreg:
+      {
+        if(!state->frame_base)
+          return MC_EXPRESSION_E_MISSING_FRAME_BASE;
+        error = mc_dwarf_push_value(state, ((uintptr_t)state->frame_base) + op->number);
+        break;
+      }
+
+    // Constants:
+
+    case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3:
+    case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7:
+    case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11:
+    case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15:
+    case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19:
+    case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23:
+    case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27:
+    case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31:
+      error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
+      break;
+
+    case DW_OP_addr:
+    case DW_OP_const1u:
+    case DW_OP_const2u:
+    case DW_OP_const4u:
+    case DW_OP_const8u:
+    case DW_OP_const1s:
+    case DW_OP_const2s:
+    case DW_OP_const4s:
+    case DW_OP_const8s:
+    case DW_OP_constu:
+    case DW_OP_consts:
+      if(state->stack_size==MC_EXPRESSION_STACK_SIZE)
+        return MC_EXPRESSION_E_STACK_OVERFLOW;
+      error = mc_dwarf_push_value(state, op->number);
+      break;
+
+    // Stack manipulation:
+
+    // Push the value at the top of the stack:
+    case DW_OP_dup:
+      if(state->stack_size==0)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      else
+        error = mc_dwarf_push_value(state, state->stack[state->stack_size-1]);
+      break;
+
+    case DW_OP_drop:
+      if(state->stack_size==0)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      else
+        state->stack_size--;
+      break;
+
+    case DW_OP_swap:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        uintptr_t temp = state->stack[state->stack_size-2];
+        state->stack[state->stack_size-2] = state->stack[state->stack_size-1];
+        state->stack[state->stack_size-1] = temp;
+      }
+      break;
+
+    case DW_OP_over:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      error = mc_dwarf_push_value(state, state->stack[state->stack_size-2]);
+      break;
+
+    // Operations:
+
+    case DW_OP_plus:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        uintptr_t result = state->stack[state->stack_size-2] + state->stack[state->stack_size-1];
+        state->stack[state->stack_size-2] = result;
+        state->stack_size--;
+      }
+      break;
+
+    case DW_OP_mul:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        uintptr_t result = state->stack[state->stack_size-2] - state->stack[state->stack_size-1];
+        state->stack[state->stack_size-2] = result;
+        state->stack_size--;
+      }
+      break;
+
+    case DW_OP_plus_uconst:
+      if(state->stack_size==0)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      state->stack[state->stack_size-1] += op->number;
+      break;
+
+    case DW_OP_not:
+      if(state->stack_size==0)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      state->stack[state->stack_size-1] = ~state->stack[state->stack_size-1];
+      break;
+
+    case DW_OP_neg:
+      if(state->stack_size==0)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        intptr_t value = state->stack[state->stack_size-1];
+        if(value<0) value = -value;
+        state->stack[state->stack_size-1] = value;
+      }
+      break;
+
+    case DW_OP_minus:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        uintptr_t result = state->stack[state->stack_size-2] - state->stack[state->stack_size-1];
+        state->stack[state->stack_size-2] = result;
+        state->stack_size--;
+      }
+      break;
+
+    case DW_OP_and:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        uintptr_t result = state->stack[state->stack_size-2] & state->stack[state->stack_size-1];
+        state->stack[state->stack_size-2] = result;
+        state->stack_size--;
+      }
+      break;
+
+    case DW_OP_or:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        uintptr_t result = state->stack[state->stack_size-2] | state->stack[state->stack_size-1];
+        state->stack[state->stack_size-2] = result;
+        state->stack_size--;
+      }
+      break;
+
+    case DW_OP_xor:
+      if(state->stack_size<2)
+        return MC_EXPRESSION_E_STACK_UNDERFLOW;
+      {
+        uintptr_t result = state->stack[state->stack_size-2] ^ state->stack[state->stack_size-1];
+        state->stack[state->stack_size-2] = result;
+        state->stack_size--;
+      }
+      break;
+
+    case DW_OP_nop:
+      break;
+
+    // Dereference:
+    case DW_OP_deref_size:
+    case DW_OP_deref:
+      return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
+
+    // Not handled:
+    default:
+     return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
+    }
+
+    if(error) return error;
+  }
+  return 0;
+}
+
+// ***** Location
+
+/** \brief Resolve a location expression
+ *  \deprecated Use mc_dwarf_resolve_expression
+ */
+Dwarf_Off mc_dwarf_resolve_location(mc_expression_t expression, unw_cursor_t* c, void* frame_pointer_address) {
+  s_mc_expression_state_t state;
+  memset(&state, 0, sizeof(s_mc_expression_state_t));
+  state.frame_base = frame_pointer_address;
+  state.cursor = c;
+
+  if(mc_dwarf_execute_expression(expression->size, expression->ops, &state))
+    xbt_die("Error evaluating DWARF expression");
+  if(state.stack_size==0)
+    xbt_die("No value on the stack");
+  else
+    return (Dwarf_Off) state.stack[state.stack_size-1];
+}
+
index e901815..f8519a5 100644 (file)
@@ -370,6 +370,24 @@ extern mc_object_info_t mc_binary_info;
 void MC_find_object_address(memory_map_t maps, mc_object_info_t result);
 void MC_post_process_types(mc_object_info_t info);
 
+// ***** Expressions
+
+/** \brief a DWARF expression with optional validity contraints */
+typedef struct s_mc_expression {
+  size_t size;
+  Dwarf_Op* ops;
+  // Optional validity:
+  void* lowpc, *highpc;
+} s_mc_expression_t, *mc_expression_t;
+
+/** A location list (list of location expressions) */
+typedef struct s_mc_location_list {
+  size_t size;
+  mc_expression_t locations;
+} s_mc_location_list_t, *mc_location_list_t;
+
+// ***** Deprecated locations:
+
 typedef enum {
   e_dw_loclist,
   e_dw_register,
@@ -432,6 +450,8 @@ typedef struct s_dw_location_entry{
   dw_location_t location;
 }s_dw_location_entry_t, *dw_location_entry_t;
 
+// ***** Variables and functions
+
 typedef struct s_dw_variable{
   Dwarf_Off dwarf_offset; /* Global offset of the field. */
   int global;
@@ -477,6 +497,25 @@ void* MC_object_base_address(mc_object_info_t info);
 Dwarf_Off MC_dwarf_resolve_location(unw_cursor_t* c, dw_location_t location, void* frame_pointer_address);
 void* mc_find_frame_base(void* ip, dw_frame_t frame, unw_cursor_t* unw_cursor);
 
+#define MC_EXPRESSION_STACK_SIZE 64
+
+#define MC_EXPRESSION_OK 0
+#define MC_EXPRESSION_E_UNSUPPORTED_OPERATION 1
+#define MC_EXPRESSION_E_STACK_OVERFLOW 2
+#define MC_EXPRESSION_E_STACK_UNDERFLOW 3
+#define MC_EXPRESSION_E_MISSING_STACK_CONTEXT 4
+#define MC_EXPRESSION_E_MISSING_FRAME_BASE 5
+
+typedef struct s_mc_expression_state {
+  uintptr_t stack[MC_EXPRESSION_STACK_SIZE];
+  size_t stack_size;
+
+  unw_cursor_t* cursor;
+  void* frame_base;
+} s_mc_expression_state_t, *mc_expression_state_t;
+
+int mc_dwarf_execute_expression(size_t n, const Dwarf_Op* ops, mc_expression_state_t state);
+
 /********************************** Miscellaneous **********************************/
 
 typedef struct s_local_variable{
diff --git a/testsuite/mc/CMakeLists.txt b/testsuite/mc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3970c88
--- /dev/null
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.6)
+
+if(HAVE_MC)
+  set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}")
+  add_executable(dwarf dwarf.c)
+  target_link_libraries(dwarf simgrid)
+
+  add_executable(dwarf-expression dwarf_expression.c)
+  target_link_libraries(dwarf-expression simgrid)
+endif()
diff --git a/testsuite/mc/dwarf.c b/testsuite/mc/dwarf.c
new file mode 100644 (file)
index 0000000..eecba82
--- /dev/null
@@ -0,0 +1,89 @@
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <string.h>
+#include <assert.h>
+
+#include <xbt.h>
+#include <mc/mc.h>
+
+#include "../../src/include/mc/datatypes.h"
+#include "../../src/mc/mc_private.h"
+
+int test_some_array[4][5][6];
+struct some_struct { int first; int second[4][5]; } test_some_struct;
+
+static dw_type_t find_type_by_name(mc_object_info_t info, const char* name) {
+  xbt_dict_cursor_t cursor = NULL;
+  char *key;
+  dw_type_t type;
+  xbt_dict_foreach(info->types, cursor, key, type) {
+    if(!strcmp(name, type->name))
+      return type;
+  }
+
+  return NULL;
+}
+
+static dw_variable_t find_global_variable_by_name(mc_object_info_t info, const char* name) {
+  unsigned int cursor = 0;
+  dw_variable_t variable;
+  xbt_dynar_foreach(info->global_variables, cursor, variable){
+    if(!strcmp(name, variable->name))
+      return variable;
+  }
+
+  return NULL;
+}
+
+static dw_variable_t test_global_variable(mc_object_info_t info, const char* name, void* address, long byte_size) {
+  dw_variable_t variable = find_global_variable_by_name(info, name);
+  xbt_assert(variable, "Global variable %s was not found", name);
+  xbt_assert(!strcmp(variable->name, name), "Name mismatch for %s", name);
+  xbt_assert(variable->global, "Variable %s is not global", name);
+  xbt_assert(variable->address == address,
+      "Address mismatch for %s : %p expected but %p found", name, address, variable->address);
+
+  dw_type_t type = xbt_dict_get_or_null(mc_binary_info->types, variable->type_origin);
+  xbt_assert(type!=NULL, "Missing type for %s", name);
+  xbt_assert(type->byte_size = byte_size, "Byte size mismatch for %s", name);
+  return variable;
+}
+
+static dw_type_t find_type(mc_object_info_t info, const char* name, dw_type_t type) {
+  unsigned int cursor = 0;
+  dw_type_t member;
+  xbt_dynar_foreach(type->members, cursor, member){
+    if(!strcmp(name,member->name))
+      return member;
+  }
+  return NULL;
+}
+
+int some_local_variable = 0;
+
+int main(int argc, char** argv) {
+
+  // xbt_init(&argc, argv);
+  SIMIX_global_init(&argc, argv);
+  MC_memory_init();
+  MC_init();
+
+  dw_variable_t var;
+  dw_type_t type;
+
+  var = test_global_variable(mc_binary_info, "some_local_variable", &some_local_variable, sizeof(int));
+
+  var = test_global_variable(mc_binary_info, "test_some_array", &test_some_array, sizeof(test_some_array));
+  type = xbt_dict_get_or_null(mc_binary_info->types, var->type_origin);
+  xbt_assert(type->element_count == 6*5*4, "element_count mismatch in test_some_array : %i / %i", type->element_count, 6*5*4);
+
+  var = test_global_variable(mc_binary_info, "test_some_struct", &test_some_struct, sizeof(test_some_struct));
+  type = xbt_dict_get_or_null(mc_binary_info->types, var->type_origin);
+  assert(find_type(mc_binary_info, "first", type)->offset == 0);
+  assert(find_type(mc_binary_info, "second", type)->offset
+      == ((const char*)&test_some_struct.second) - (const char*)&test_some_struct);
+
+  _exit(0);
+}
diff --git a/testsuite/mc/dwarf_expression.c b/testsuite/mc/dwarf_expression.c
new file mode 100644 (file)
index 0000000..1ff04d5
--- /dev/null
@@ -0,0 +1,122 @@
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "../src/mc/mc_private.h"
+
+uintptr_t eval_binary_operation(mc_expression_state_t state, int op, uintptr_t a, uintptr_t b) {
+  state->stack_size = 0;
+
+  Dwarf_Op ops[15];
+  ops[0].atom = DW_OP_addr;
+  ops[0].number = a;
+  ops[1].atom = DW_OP_addr;
+  ops[1].number = b;
+  ops[2].atom = op;
+
+  assert(mc_dwarf_execute_expression(3, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size==1);
+  return state->stack[state->stack_size - 1];
+}
+
+void basic_test(mc_expression_state_t state) {
+  Dwarf_Op ops[60];
+
+  uintptr_t a = rand();
+  uintptr_t b = rand();
+
+  ops[0].atom = DW_OP_drop;
+  assert(mc_dwarf_execute_expression(1, ops, state) == MC_EXPRESSION_E_STACK_UNDERFLOW);
+
+  ops[0].atom = DW_OP_lit21;
+  assert(mc_dwarf_execute_expression(1, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size==1);
+  assert(state->stack[state->stack_size-1]==21);
+
+  ops[0].atom = DW_OP_addr;
+  ops[0].number = a;
+  assert(mc_dwarf_execute_expression(1, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size==2);
+  assert(state->stack[state->stack_size-1] == a);
+
+  ops[0].atom = DW_OP_drop;
+  ops[1].atom = DW_OP_drop;
+  assert(mc_dwarf_execute_expression(2, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size==0);
+
+  ops[0].atom = DW_OP_lit21;
+  ops[1].atom = DW_OP_plus_uconst;
+  ops[1].number = a;
+  assert(mc_dwarf_execute_expression(2, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size==1);
+  assert(state->stack[state->stack_size-1]== a + 21);
+
+  state->stack_size = 0;
+  ops[0].atom = DW_OP_addr;
+  ops[0].number = a;
+  ops[1].atom = DW_OP_dup;
+  ops[2].atom = DW_OP_plus;
+  assert(mc_dwarf_execute_expression(3, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size==1);
+  assert(state->stack[state->stack_size-1]== a + a);
+
+  state->stack_size = 0;
+  ops[0].atom = DW_OP_addr;
+  ops[0].number = a;
+  ops[1].atom = DW_OP_addr;
+  ops[1].number = b;
+  ops[2].atom = DW_OP_over;
+  assert(mc_dwarf_execute_expression(3, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size==3);
+  assert(state->stack[state->stack_size-1]== a);
+  assert(state->stack[state->stack_size-2]== b);
+  assert(state->stack[state->stack_size-3]== a);
+
+  state->stack_size = 0;
+  ops[0].atom = DW_OP_addr;
+  ops[0].number = a;
+  ops[1].atom = DW_OP_addr;
+  ops[1].number = b;
+  ops[2].atom = DW_OP_swap;
+  assert(mc_dwarf_execute_expression(3, ops, state) == MC_EXPRESSION_OK);
+  assert(state->stack_size=2);
+  assert(state->stack[state->stack_size-1]== a);
+  assert(state->stack[state->stack_size-2]== b);
+}
+
+int main(int argc, char** argv) {
+  s_mc_expression_state_t state;
+  memset(&state, 0, sizeof(s_mc_expression_state_t));
+
+  basic_test(&state);
+
+  for(int i=0; i!=100; ++i) {
+    uintptr_t a = rand();
+    uintptr_t b = rand();
+    assert(eval_binary_operation(&state, DW_OP_plus, a, b) == (a + b));
+  }
+
+  for(int i=0; i!=100; ++i) {
+    uintptr_t a = rand();
+    uintptr_t b = rand();
+    assert(eval_binary_operation(&state, DW_OP_or, a, b) == (a | b));
+  }
+
+  for(int i=0; i!=100; ++i) {
+    uintptr_t a = rand();
+    uintptr_t b = rand();
+    assert(eval_binary_operation(&state, DW_OP_and, a, b) == (a & b));
+  }
+
+  for(int i=0; i!=100; ++i) {
+    uintptr_t a = rand();
+    uintptr_t b = rand();
+    assert(eval_binary_operation(&state, DW_OP_xor, a, b) == (a ^ b));
+  }
+
+  return 0;
+}