Call arbitrary functions from the monitor
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 23 Mar 2010 07:39:37 +0000 (00:39 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:40 +0000 (17:35 -0700)
This is sweet.  And like Chuck Norris, it shows no mercy.  You have been
warned.

kern/arch/i686/kdebug.c
kern/include/kdebug.h
kern/include/monitor.h
kern/include/stab.h
kern/src/monitor.c

index d59b3e6..3ebf3c4 100644 (file)
@@ -253,3 +253,45 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
        
        return 0;
 }
+
+/* Returns a function pointer for a function name matching the given string. */
+void *debug_get_fn_addr(char *fn_name)
+{
+       const struct stab *SNT stab_end = __STAB_END__;
+       const struct stab *BND(__this,stab_end) stabs = __STAB_BEGIN__;
+       const char *SNT stabstr_end = __STABSTR_END__;
+       const char *NT BND(__this,stabstr_end) stabstr = __STABSTR_BEGIN__;
+
+       static int first_fn_idx = 0;
+       int i = first_fn_idx;
+       int len;
+       const char *stab_fn_name = 0;
+       void *retval = 0;
+
+       // String table validity checks (from above)
+       {
+               int stabstrsz = stabstr_end - stabstr;
+               if (stabstr_end <= stabstr || stabstr[stabstrsz-1] != 0)
+                       return 0;
+       }
+
+       for (/* i set */; &stabs[i] < stab_end; i++) {
+               if (stabs[i].n_type != N_FUN)
+                       continue;
+               first_fn_idx = first_fn_idx ? first_fn_idx : i;
+               /* broken stab, just keep going */
+               if (!(stabs[i].n_strx < stabstr_end - stabstr))
+                       continue;
+               stab_fn_name = stabstr + stabs[i].n_strx;
+               len = strfind(stab_fn_name, ':') - stab_fn_name;
+               if (!len)
+                       continue;
+               /* we have a match. */
+               if (!strncmp(stab_fn_name, fn_name, len)) {
+                       printd("FN name: %s, Addr: %p\n", stab_fn_name, stabs[i].n_value);
+                       retval = (void*)stabs[i].n_value;
+                       break;
+               }
+       }
+       return retval;
+}
index 4127814..2e49fa6 100644 (file)
@@ -16,5 +16,6 @@ typedef struct Eipdebuginfo {
 } eipdebuginfo_t;
 
 int debuginfo_eip(uintptr_t eip, eipdebuginfo_t *NONNULL info);
+void *debug_get_fn_addr(char *fn_name);
 
 #endif
index 734fc15..9f767b8 100644 (file)
@@ -25,5 +25,6 @@ int mon_kfs_cat(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_manager(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_procinfo(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_exit(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
+int mon_kfunc(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 
 #endif // !ROS_KERN_MONITOR_H
index eed75ba..18b275d 100644 (file)
@@ -40,7 +40,7 @@
 #define        N_LENG          0xfe    // length of preceding entry
 
 // Entries in the STABS table are formatted as follows.
-typedef struct Stab {
+typedef struct stab {
        uint32_t n_strx;        // index into string table of name
        uint8_t n_type;         // type of symbol
        uint8_t n_other;        // misc info (usually empty)
index f1a41ee..25e3063 100644 (file)
@@ -22,6 +22,7 @@
 #include <manager.h>
 #include <schedule.h>
 #include <resource.h>
+#include <kdebug.h>
 
 #include <ros/memlayout.h>
 
@@ -50,6 +51,7 @@ static command_t (RO commands)[] = {
        { "manager", "Run the manager", mon_manager},
        { "procinfo", "Show information about processes", mon_procinfo},
        { "exit", "Leave the monitor", mon_exit},
+       { "kfunc", "Run a kernel function directly (!!!)", mon_kfunc},
 };
 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
 
@@ -354,6 +356,71 @@ int mon_exit(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
        return -1;
 }
 
+int mon_kfunc(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
+{
+       #ifndef __i386__
+       printk("Only supported on x86 for now.  =(\n");
+       return -1;
+       #endif
+
+       void (*func)(void *arg, ...);
+
+       if (argc < 2) {
+               printk("Usage: kfunc FUNCTION [arg1] [arg2] [etc]\n");
+               printk("Arguments must be in hex.  Can take 6 args.\n");
+               return 1;
+       }
+       func = debug_get_fn_addr(argv[1]);
+       if (!func) {
+               printk("Function not found.\n");
+               return 1;
+       }
+       /* Not elegant, but whatever.  maybe there's a better syntax, or we can do
+        * it with asm magic. */
+       switch (argc) {
+               case 2: /* have to fake one arg */
+                       func((void*)0);
+                       break;
+               case 3: /* the real first arg */
+                       func((void*)strtol(argv[2], 0, 16));
+                       break;
+               case 4:
+                       func((void*)strtol(argv[2], 0, 16),
+                                   strtol(argv[3], 0, 16));
+                       break;
+               case 5:
+                       func((void*)strtol(argv[2], 0, 16),
+                                   strtol(argv[3], 0, 16),
+                                   strtol(argv[4], 0, 16));
+                       break;
+               case 6:
+                       func((void*)strtol(argv[2], 0, 16),
+                                   strtol(argv[3], 0, 16),
+                                   strtol(argv[4], 0, 16),
+                                   strtol(argv[5], 0, 16));
+                       break;
+               case 7:
+                       func((void*)strtol(argv[2], 0, 16),
+                                   strtol(argv[3], 0, 16),
+                                   strtol(argv[4], 0, 16),
+                                   strtol(argv[5], 0, 16),
+                                   strtol(argv[6], 0, 16));
+                       break;
+               case 8:
+                       func((void*)strtol(argv[2], 0, 16),
+                                   strtol(argv[3], 0, 16),
+                                   strtol(argv[4], 0, 16),
+                                   strtol(argv[5], 0, 16),
+                                   strtol(argv[6], 0, 16),
+                                   strtol(argv[7], 0, 16));
+                       break;
+               default:
+                       printk("Bad number of arguments.\n");
+                       return -1;
+       }
+       return 0;
+}
+
 /***** Kernel monitor command interpreter *****/
 
 #define WHITESPACE "\t\r\n "