]> sourceware.org Git - systemtap.git/commitdiff
PR14573 (partial): Pass some registers into stapdyn
authorJosh Stone <jistone@redhat.com>
Fri, 5 Oct 2012 02:04:14 +0000 (19:04 -0700)
committerJosh Stone <jistone@redhat.com>
Fri, 5 Oct 2012 02:04:14 +0000 (19:04 -0700)
There doesn't seem to be a way to create and pass the pt_regs structure
from the Dyninst API, but we can still get most registers.  This patch
adds a new enter_dyninst_uprobe_regs() to receive registers and fill
them into a pt_regs from there.

XXX Dyninst is currently limited in how many individual function
arguments it can pass, so for now I'm cutting it down to the first 8.

* runtime/dyninst/stapdyn.h: Declare enter_dyninst_uprobe_regs.
* runtime/dyninst/uprobes.c: Implement it, filling all dwarf registers
  into a local struct pt_regs.
* runtime/dyninst/regs.c: Include regs.h to get SET_REG_IP.
* stapdyn/stapdyn.cxx (get_dwarf_registers): Create BPatch_snippets for
  as many of the DWARF registers as possible (bug-limited to 8).
  (instrument_uprobes): Look for the new entry function and use it.

runtime/dyninst/loc2c-runtime.h
runtime/dyninst/regs.c
runtime/dyninst/stapdyn.h
runtime/dyninst/uprobes.c
stapdyn/stapdyn.cxx

index bf1704f3a5ab1ed99b482c11a95b95b0b419af02..47983e8cedb386975aacea99093f9ca492df039e 100644 (file)
 #define u_store_register(regno, value) \
   pt_regs_store_register(c->uregs, regno, value)
 
+#if defined(__i386__)
+// The kernel's way of getting esp doesn't work as an lvalue
+#undef pt_dwarf_register_4
+#define pt_dwarf_register_4(regs)      regs->esp
+#endif
+
 
 #define uread(ptr) ({ \
        typeof(*(ptr)) _v = 0; \
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..935ea16c434cd81a4cafbe668500867ab736edd3 100644 (file)
@@ -0,0 +1 @@
+#include "regs.h"
index 5beb0a55212aab6db6b6fbe97960df95ee5f399d..3cbc7c6f4912f333f724b5a2e18c637cbe890f22 100644 (file)
@@ -40,6 +40,11 @@ extern uint64_t stp_dyninst_probe_semaphore(uint64_t index);
 
 extern int enter_dyninst_uprobe(uint64_t index, struct pt_regs *regs);
 
+/* This is somewhat of a hack until we can figure out how to build a pt_regs
+ * struct directly with stapdyn.  The varargs are all unsigned long, giving
+ * first the original PC, then DWARF-ordered registers.  */
+extern int enter_dyninst_uprobe_regs(uint64_t index, unsigned long nregs, ...);
+
 
 /* STAP 2.x : */
 
index bf54e5740ed57bc417810d5530705b6b654f1412..975ddc87c86bed4ede0993f4c1cd7e26e8004bb9 100644 (file)
@@ -60,6 +60,49 @@ uint64_t stp_dyninst_probe_semaphore(uint64_t index)
        return stapdu_probes[index].semaphore;
 }
 
+int enter_dyninst_uprobe_regs(uint64_t index, unsigned long nregs, ...)
+{
+       struct pt_regs regs = {0};
+
+       va_list varegs;
+       va_start(varegs, nregs);
+
+       if (nregs > 0)
+               SET_REG_IP((&regs), va_arg(varegs, unsigned long));
+
+       /* NB: pt_regs_store_register() expects literal register numbers to
+        * paste as CPP tokens, so unfortunately this has to be unrolled.  */
+#define SET_REG(n) if (n < nregs - 1) \
+                       pt_regs_store_register((&regs), n, \
+                                       va_arg(varegs, unsigned long))
+#if defined(__i386__) || defined(__x86_64__)
+       SET_REG(0);
+       SET_REG(1);
+       SET_REG(2);
+       SET_REG(3);
+       SET_REG(4);
+       SET_REG(5);
+       SET_REG(6);
+       SET_REG(7);
+#endif
+#if defined(__x86_64__)
+       SET_REG(8);
+       SET_REG(9);
+       SET_REG(10);
+       SET_REG(11);
+       SET_REG(12);
+       SET_REG(13);
+       SET_REG(14);
+       SET_REG(15);
+#endif
+#undef SET_REG
+
+       va_end(varegs);
+
+
+       return enter_dyninst_uprobe(index, &regs);
+}
+
 
 #endif /* _UPROBES_DYNINST_C_ */
 
index 6d613de3444b202e52036e09e8613c20805faae3..6459aff1937a2c475a80e649e6d26280ba483638 100644 (file)
@@ -125,6 +125,50 @@ call_inferior_function(BPatch_process *app, const string& name)
     }
 }
 
+static void
+get_dwarf_registers(BPatch_process *app,
+                    vector<BPatch_snippet*>& registers)
+{
+#if defined(__i386__)
+  static const char* const names[] = {
+      "eax", "ecx", "edx", "ebx",
+      "esp", "ebp", "esi", "edi",
+      NULL };
+#elif defined(__x86_64__)
+  static const char* const names[] = {
+      "rax", "rdx", "rcx", "rbx",
+      "rsi", "rdi", "rbp", "rsp",
+      "r8",  "r9",  "r10", "r11",
+      "r12", "r13", "r14", "r15",
+      NULL };
+#else
+  static const char* const names[] = { NULL };
+#endif
+
+  registers.push_back(new BPatch_originalAddressExpr());
+
+  BPatch_Vector<BPatch_register> bpregs;
+  app->getRegisters(bpregs);
+
+  // O(n^2) loop, but neither is very large
+  for (const char* const* name = names; *name; ++name)
+    {
+      // XXX Dyninst is currently limited in how many individual function
+      // arguments it can pass, so we'll have to cut this short...
+      if (registers.size() > 8) break;
+
+      size_t i;
+      for (i = 0; i < bpregs.size(); ++i)
+        if (bpregs[i].name() == *name)
+          {
+            registers.push_back(new BPatch_registerExpr(bpregs[i]));
+            break;
+          }
+      if (i >= bpregs.size())
+        registers.push_back(new BPatch_constExpr((unsigned long)0));
+    }
+}
+
 static void
 instrument_uprobes(BPatch_process *app,
                    const vector<stapdyn_uprobe_target>& targets)
@@ -147,10 +191,25 @@ instrument_uprobes(BPatch_process *app,
         file_objects[resolved_path] = objects[i];
     }
 
+  BPatch_function* enter_function = NULL;
   vector<BPatch_function *> functions;
-  image->findFunction("enter_dyninst_uprobe", functions);
-  if (functions.empty()) return;
-  BPatch_function& enter_function = *functions[0];
+  vector<BPatch_snippet *> enter_args;
+
+  image->findFunction("enter_dyninst_uprobe_regs", functions);
+  if (!functions.empty())
+    {
+      get_dwarf_registers(app, enter_args);
+      if (!enter_args.empty())
+        enter_function = functions[0];
+    }
+
+  if (!enter_function)
+    {
+      image->findFunction("enter_dyninst_uprobe", functions);
+      if (functions.empty())
+        return;
+      enter_function = functions[0];
+    }
 
   app->beginInsertionSet();
   for (size_t i = 0; i < targets.size(); ++i)
@@ -196,8 +255,14 @@ instrument_uprobes(BPatch_process *app,
 
           vector<BPatch_snippet *> args;
           args.push_back(new BPatch_constExpr((int64_t)probe.index));
-          args.push_back(new BPatch_constExpr((void*)NULL)); // pt_regs
-          BPatch_funcCallExpr call(enter_function, args);
+          if (enter_args.empty())
+            args.push_back(new BPatch_constExpr((void*)NULL)); // pt_regs
+          else
+            {
+              args.push_back(new BPatch_constExpr((unsigned long)enter_args.size()));
+              args.insert(args.end(), enter_args.begin(), enter_args.end());
+            }
+          BPatch_funcCallExpr call(*enter_function, args);
           app->insertSnippet(call, points);
 
           // XXX write the semaphore too!
This page took 0.032837 seconds and 5 git commands to generate.