]> git.saurik.com Git - apple/system_cmds.git/commitdiff
system_cmds-196.tar.gz mac-os-x-101 mac-os-x-1011 mac-os-x-1012 mac-os-x-1013 mac-os-x-1014 mac-os-x-1015 v196
authorApple <opensource@apple.com>
Mon, 13 Aug 2001 18:14:33 +0000 (18:14 +0000)
committerApple <opensource@apple.com>
Mon, 13 Aug 2001 18:14:33 +0000 (18:14 +0000)
27 files changed:
dynamic_pager.tproj/dynamic_pager.c
fs_usage.tproj/fs_usage.1
fs_usage.tproj/fs_usage.c
init.tproj/init.c
kextd.tproj/KEXTD.c
kextd.tproj/KEXTD.h
kextd.tproj/KEXTD_main.c
kextd.tproj/Makefile
kextd.tproj/PB.project
kextload.tproj/Makefile
kextload.tproj/PB.project
kextunload.tproj/Makefile
kextunload.tproj/PB.project
kmodload.tproj/Makefile
kmodload.tproj/PB.project
kmodload.tproj/kld_patch.c [new file with mode: 0644]
kmodload.tproj/kld_patch.h [new file with mode: 0644]
kmodload.tproj/kmodload.c
latency.tproj/latency.c
login.tproj/login.c
nvram.tproj/Makefile
nvram.tproj/PB.project
sc_usage.tproj/sc_usage.c
sc_usage.tproj/trace.codes
top.tproj/Makefile
top.tproj/PB.project
top.tproj/top.c

index 51ce54c1ad498f4fd4ca3bf449f4e12ff1044d22..30375b273757b9daf4aee2a8f14e0624c33b1d9c 100644 (file)
@@ -75,12 +75,22 @@ server_alert_loop(
                      max_size + MAX_TRAILER_SIZE,
                      TRUE)) != KERN_SUCCESS)
       return kr;
+    if ((kr = vm_protect(mach_task_self(),
+                     (vm_address_t)bufRequest,
+                     max_size + MAX_TRAILER_SIZE,
+                    FALSE, VM_PROT_ALL)) != KERN_SUCCESS)
+      return kr;
     mlock(bufRequest, max_size + MAX_TRAILER_SIZE);
     if ((kr = vm_allocate(mach_task_self(),
                      (vm_address_t *)&bufReply,
                      max_size + MAX_TRAILER_SIZE,
                      TRUE)) != KERN_SUCCESS)
       return kr;
+    if ((kr = vm_protect(mach_task_self(),
+                     (vm_address_t)bufReply,
+                     max_size + MAX_TRAILER_SIZE,
+                    FALSE, VM_PROT_ALL)) != KERN_SUCCESS)
+      return kr;
     mlock(bufReply, max_size + MAX_TRAILER_SIZE);
     while(TRUE) {
        mr = mach_msg_overwrite_trap(&bufRequest->Head, MACH_RCV_MSG|options,
@@ -274,7 +284,6 @@ paging_setup(flags, size, priority, low, high)
        off_t           filesize = size;
        char            subfile[512];
        FILE            *file_ptr;
-        kern_return_t   error;
 
        file_count = 0;
        sprintf(subfile, "%s%d", fileroot, file_count);
@@ -285,6 +294,8 @@ paging_setup(flags, size, priority, low, high)
         
        macx_swapon(subfile, flags, size, priority);
        if(hi_water) {
+               mach_msg_type_name_t    poly;
+
                daemon(0,0);
 
                if (mach_port_allocate(mach_task_self(), 
@@ -293,6 +304,9 @@ paging_setup(flags, size, priority, low, high)
                        fprintf(stderr,"allocation of trigger port failed\n");
                        exit(1);
                }
+               /* create a send right on our local port */
+               mach_port_extract_right(mach_task_self(), trigger_port,
+                       MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly);
                macx_triggers(high, low, HI_WAT_ALERT, trigger_port);
                if(low) {
                        macx_triggers(high, 
index 2d3af748082fe7a935fa39f1d4de299d1667b432..67a1fba90f9b4af40a8452bda8b6dcd9e43d51c7 100644 (file)
@@ -14,9 +14,11 @@ in real-time.
 .Nm fs_usage
 presents an ongoing display of system call usage
 information pertaining to filesystem activity.  By default
-this includes all system processes.  The information, however,
-may  be limited to include or exclude a specified list 
-of processes.
+this includes all system processes except the running
+fs_usage process,
+Terminal, telnetd, sshd, rlogind, tcsh, csh and sh.
+These defaluts can be overridden such that output is limited to
+include or exclude a list of processes specified by the user.
 .Pp
 The output presented by
 .Nm fs_usage
index 1027e59ccfc18f4e5416ddf8dc5276f5d20a8cd0..465d0dcfc74c842eaa9b33d2330241d3aba96303 100644 (file)
@@ -60,6 +60,16 @@ cc -I. -DKERNEL_PRIVATE -O -o fs_usage fs_usage.c
 
 extern int errno;
 
+/* 
+   MAXCOLS controls when extra data kicks in.
+   MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
+   If NUMPARMS changes to match the kernel, it will automatically
+   get reflected in the -w mode output.
+*/
+#define NUMPARMS 23
+#define PATHLENGTH (NUMPARMS*sizeof(long))
+#define MAXCOLS 131
+#define MAX_WIDE_MODE_COLS (PATHLENGTH + 80)
 
 struct th_info {
         int  in_filemgr;
@@ -69,11 +79,11 @@ struct th_info {
         int  arg2;
         int  arg3;
         int  arg4;
-        int  vfslookup;
         int  child_thread;
         int  waited;
         double stime;
-        char pathname[32];
+        long *pathptr;
+        char pathname[PATHLENGTH + 1];   /* add room for null terminator */
 };
 
 #define MAX_THREADS 512
@@ -234,6 +244,7 @@ int    pids[MAX_PIDS];
 
 int    num_of_pids = 0;
 int    exclude_pids = 0;
+int    exclude_default_pids = 1;
 
 struct kinfo_proc *kp_buffer = 0;
 int kp_nentries = 0;
@@ -299,17 +310,22 @@ void leave()                      /* exit under normal conditions -- INT handler */
 
 void sigwinch()
 {
-       initscr();
+  if (!wideflag)
+    initscr();
 }
 
 int
 exit_usage(myname) {
 
         fprintf(stderr, "Usage: %s [-e] [-w] [pid | cmd [pid | cmd]....]\n", myname);
-       fprintf(stderr, "  -e    exclude the pids specified from the sample\n");
+       fprintf(stderr, "  -e    exclude the specified list of pids from the sample\n");
+       fprintf(stderr, "        and exclude fs_usage by default\n");
        fprintf(stderr, "  -w    force wider, detailed, output\n");
        fprintf(stderr, "  pid   selects process(s) to sample\n");
        fprintf(stderr, "  cmd   selects process(s) matching command string to sample\n");
+       fprintf(stderr, "\n%s will handle a maximum list of %d pids.\n\n", myname, MAX_PIDS);
+       fprintf(stderr, "By default (no options) the following processes are excluded from the output:\n");
+       fprintf(stderr, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");
 
        exit(1);
 }
@@ -350,9 +366,12 @@ main(argc, argv)
                switch(ch) {
                 case 'e':
                    exclude_pids = 1;
+                   exclude_default_pids = 0;
                    break;
                 case 'w':
                    wideflag = 1;
+                   if (COLS < MAX_WIDE_MODE_COLS)
+                     COLS = MAX_WIDE_MODE_COLS;
                    break;
               default:
                 exit_usage(myname);             
@@ -362,6 +381,10 @@ main(argc, argv)
         argc -= optind;
         argv += optind;
 
+       /* If we process any list of pids/cmds, then turn off the defaults */
+       if (argc > 0)
+         exclude_default_pids = 0;
+
        while (argc > 0 && num_of_pids < (MAX_PIDS - 1)) {
          select_pid_mode++;
          argtopid(argv[0]);
@@ -369,8 +392,26 @@ main(argc, argv)
          argv++;
        }
 
+       /* Exclude a set of default pids */
+       if (exclude_default_pids)
+         {
+           argtopid("Terminal");
+           argtopid("telnetd");
+           argtopid("sshd");
+           argtopid("rlogind");
+           argtopid("tcsh");
+           argtopid("csh");
+           argtopid("sh");
+           exclude_pids = 1;
+         }
+
        if (exclude_pids)
+         {
+           if (num_of_pids < (MAX_PIDS - 1))
                pids[num_of_pids++] = getpid();
+           else
+             exit_usage(myname);
+         }
 
 #if 0
        for (i = 0; i < num_of_pids; i++)
@@ -638,6 +679,7 @@ sample_sc()
 {
        kd_buf *kd;
        int i, count;
+       size_t needed;
        void read_command_map();
        void create_map_entry();
 
@@ -665,7 +707,7 @@ sample_sc()
 
                for (i = 0; i < cur_max; i++) {
                        th_state[i].thread = 0;
-                       th_state[i].vfslookup = 0;
+                       th_state[i].pathptr = (long *)0;
                        th_state[i].pathname[0] = 0;
                }
                cur_max = 0;
@@ -740,23 +782,31 @@ sample_sc()
                    if ((ti = find_thread(thread, 0)) == (struct th_info *)0)
                            continue;
 
-                   if (ti->vfslookup == 0) {
-                           ti->vfslookup = 1;
-                           memset(&ti->pathname[0], 0, 32);
+                   if (!ti->pathptr) {
                            sargptr = (long *)&ti->pathname[0];
-                               
+                           memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
                            *sargptr++ = kd[i].arg2;
                            *sargptr++ = kd[i].arg3;
                            *sargptr++ = kd[i].arg4;
+                           ti->pathptr = sargptr;
+
+                   } else {
+                           sargptr = ti->pathptr;
+
+                           /* 
+                              We don't want to overrun our pathname buffer if the
+                              kernel sends us more VFS_LOOKUP entries than we can
+                              handle.
+                           */
+
+                           if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
+                             continue;
 
-                   } else if (ti->vfslookup == 1) {
-                           ti->vfslookup = 2;
-         
-                           sargptr = (long *)&ti->pathname[12];
                            *sargptr++ = kd[i].arg1;
                            *sargptr++ = kd[i].arg2;
                            *sargptr++ = kd[i].arg3;
                            *sargptr++ = kd[i].arg4;
+                           ti->pathptr = sargptr;
                    }
                    continue;
                }
@@ -1401,8 +1451,13 @@ enter_syscall(int thread, int type, kd_buf *kd, char *name, double now)
        int    usecs;
        long long l_usecs;
        long curr_time;
-          kd_threadmap *map;
-          kd_threadmap *find_thread_map();
+       kd_threadmap *map;
+       kd_threadmap *find_thread_map();
+       int clen = 0;
+       int tsclen = 0;
+       int nmclen = 0;
+       int argsclen = 0;
+       char buf[MAXCOLS];
 
        switch (type) {
 
@@ -1546,43 +1601,62 @@ enter_syscall(int thread, int type, kd_buf *kd, char *name, double now)
                           bias_secs = curr_time - secs;
                   }
                   curr_time = bias_secs + secs;
-                  printf("%-8.8s", &(ctime(&curr_time)[11]));
+                  sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
+                  tsclen = strlen(buf);
 
-                  if (COLS > 110 || wideflag) {
+                  if (COLS > MAXCOLS || wideflag) {
                           usecs = l_usecs - (long long)((long long)secs * 1000000);
-                          printf(".%03ld", (long)usecs / 1000);
+                          sprintf(&buf[tsclen], ".%03ld", (long)usecs / 1000);
+                          tsclen = strlen(buf);
                   }
-                  map = find_thread_map(thread);
-                  if (map) {
-                      char buf[128];
-                      int  clen;
-
-                      sprintf(buf, "  %s", name);
-                      clen = strlen(buf);
-
-                      if (clen > 25)
-                          clen = 25;
-                      memset(&buf[clen], ' ', 26 - clen);
 
-                      sprintf(&buf[25], "(%d, 0x%x, 0x%x, 0x%x)", (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
-                      clen = strlen(&buf[25]) + 25;
-                      memset(&buf[clen], ' ', 128 - clen);
-
-                      if (COLS > 110 || wideflag)
-                          sprintf(&buf[81], "%s\n", map->command); 
-                      else
-                          sprintf(&buf[60], "%.12s\n", map->command); 
+                  /* Print timestamp column */
+                  printf(buf);
 
+                  map = find_thread_map(thread);
+                  if (map) {
+                      sprintf(buf, "  %-25.25s ", name);
+                      nmclen = strlen(buf);
                       printf(buf);
 
+                      sprintf(buf, "(%d, 0x%x, 0x%x, 0x%x)", (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
+                      argsclen = strlen(buf);
+                      
+                      /*
+                        Calculate white space out to command
+                      */
+                      if (COLS > MAXCOLS || wideflag)
+                        {
+                          clen = COLS - (tsclen + nmclen + argsclen + 20);
+                        }
+                      else
+                        clen = COLS - (tsclen + nmclen + argsclen + 12);
+
+                      if(clen > 0)
+                        {
+                          printf(buf);   /* print the kdargs */
+                          memset(buf, ' ', clen);
+                          buf[clen] = '\0';
+                          printf(buf);
+                        }
+                      else if ((argsclen + clen) > 0)
+                        {
+                          /* no room so wipe out the kdargs */
+                          memset(buf, ' ', (argsclen + clen));
+                          buf[argsclen + clen] = '\0';
+                          printf(buf);
+                        }
+
+                      if (COLS > MAXCOLS || wideflag)
+                          printf("%-20.20s\n", map->command); 
+                      else
+                          printf("%-12.12s\n", map->command); 
                   } else
                           printf("  %-24.24s (%5d, %#x, 0x%x, 0x%x)\n",         name, (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
-      
           } else {
                           ti->in_filemgr = 0;
           }
           ti->thread = thread;
-          ti->vfslookup = 0;
           ti->waited = 0;
           ti->type   = type;
           ti->stime  = now;
@@ -1590,6 +1664,7 @@ enter_syscall(int thread, int type, kd_buf *kd, char *name, double now)
           ti->arg2   = kd->arg2;
           ti->arg3   = kd->arg3;
           ti->arg4   = kd->arg4;
+          ti->pathptr = (long *)0;
           ti->pathname[0] = 0;
 
           break;
@@ -1597,6 +1672,7 @@ enter_syscall(int thread, int type, kd_buf *kd, char *name, double now)
        default:
           break;
        }
+       fflush (0);
 }
 
 
@@ -1612,6 +1688,9 @@ exit_syscall(char *sc_name, int thread, int type, int error, int retval,
        long curr_time;
        kd_threadmap *map;
        kd_threadmap *find_thread_map();
+       int len = 0;
+       int clen = 0;
+       char buf[MAXCOLS];
       
        if ((ti = find_thread(thread, type)) == (struct th_info *)0)
               return;
@@ -1624,52 +1703,93 @@ exit_syscall(char *sc_name, int thread, int type, int error, int retval,
               bias_secs = curr_time - secs;
        }
        curr_time = bias_secs + secs;
-       printf("%-8.8s", &(ctime(&curr_time)[11]));
+       sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
+       clen = strlen(buf);
 
-
-       if (COLS > 110 || wideflag) {
+       if (COLS > MAXCOLS || wideflag) {
               nopadding = 0;
               usecs = l_usecs - (long long)((long long)secs * 1000000);
-              printf(".%03ld", (long)usecs / 1000);
-
+              sprintf(&buf[clen], ".%03ld", (long)usecs / 1000);
+              clen = strlen(buf);
               if ((type >> 24) != FILEMGR_CLASS) {
                   if (find_thread(thread, -1)) {
-                      printf("   ");
+                      sprintf(&buf[clen], "   ");
+                      clen = strlen(buf);
                       nopadding = 1;
                   }
               }
        } else
               nopadding = 1;
 
-       if (((type >> 24) == FILEMGR_CLASS) && (COLS > 110 || wideflag)) 
-              printf("  %-18.18s", sc_name);
+       if (((type >> 24) == FILEMGR_CLASS) && (COLS > MAXCOLS || wideflag))
+              sprintf(&buf[clen], "  %-18.18s", sc_name);
        else
-              printf("  %-15.15s", sc_name);
+              sprintf(&buf[clen], "  %-15.15s", sc_name);
 
-       if (COLS > 110 || wideflag) {
+       clen = strlen(buf);
+
+       if (COLS > MAXCOLS || wideflag) {
               if (has_fd == 2 && error == 0)
-                      printf(" F=%-3d", retval);
+                      sprintf(&buf[clen], " F=%-3d", retval);
               else if (has_fd == 1)
-                      printf(" F=%-3d", ti->arg1);
+                      sprintf(&buf[clen], " F=%-3d", ti->arg1);
               else if (has_ret != 2)
-                      printf("      ");
+                      sprintf(&buf[clen], "      ");
+
+              clen = strlen(buf);
 
               if (error)
-                      printf("[%3d]       ", error);
+                      sprintf(&buf[clen], "[%3d]       ", error);
               else if (has_ret == 3)
-                      printf("O=0x%8.8x", ti->arg3);
+                      sprintf(&buf[clen], "O=0x%8.8x", ti->arg3);
               else if (has_ret == 5)
-                      printf("O=0x%8.8x", retval);
+                      sprintf(&buf[clen], "O=0x%8.8x", retval);
               else if (has_ret == 2) 
-                      printf(" A=0x%8.8x     ", retval);
+                      sprintf(&buf[clen], " A=0x%8.8x     ", retval);
               else if (has_ret == 1)
-                      printf("  B=0x%-6x", retval);
+                      sprintf(&buf[clen], "  B=0x%-6x", retval);
               else if (has_ret == 4)
-                      printf("R=0x%-8x", retval);
+                      sprintf(&buf[clen], "R=0x%-8x", retval);
               else
-                      printf("            ");
+                      sprintf(&buf[clen], "            ");
+              clen = strlen(buf);
        }
-       printf(" %-28.28s ",  ti->pathname);
+       printf(buf);
+
+       /*
+        Calculate space available to print pathname
+       */
+       if (COLS > MAXCOLS || wideflag)
+        clen =  COLS - (clen + 13 + 20);
+       else
+        clen =  COLS - (clen + 13 + 12);
+
+       if ((type >> 24) != FILEMGR_CLASS && !nopadding)
+        clen -= 3;
+
+       sprintf(&buf[0], " %s ", ti->pathname);
+       len = strlen(buf);
+       
+       if (clen > len)
+        {
+          /* 
+             Add null padding if column length
+             is wider than the pathname length.
+          */
+          memset(&buf[len], ' ', clen - len);
+          buf[clen] = '\0';
+          printf(buf);
+        }
+       else if (clen == len)
+        {
+          printf(buf);
+        }
+       else if ((clen > 0) && (clen < len))
+        {
+          /* This prints the tail end of the pathname */
+          buf[len-clen] = ' ';
+          printf(&buf[len - clen]);
+        }
 
        usecs = (unsigned long)(((double)now - ti->stime) / divisor);
        secs = usecs / 1000000;
@@ -1685,16 +1805,17 @@ exit_syscall(char *sc_name, int thread, int type, int error, int retval,
               printf("  ");
 
        if (map) {
-              if (COLS > 110 || wideflag)
-                      printf(" %s", map->command);
+              if (COLS > MAXCOLS || wideflag)
+                      printf(" %-20.20s", map->command);
               else
-                      printf(" %.12s", map->command);
+                      printf(" %-12.12s", map->command);
        }
        printf("\n");
 
        if (ti == &th_state[cur_max - 1])
                 cur_max--;
        ti->thread = 0;
+       fflush (0);
 }
 
 int
@@ -1819,8 +1940,13 @@ void create_map_entry(int thread, char *command)
 
     map->valid = 1;
     map->thread = thread;
-    (void)strncpy (map->command, command, sizeof(map->command));
-    map->command[sizeof(map->command)-1] = '\0';
+    /*
+      The trace entry that returns the command name will hold
+      at most, MAXCOMLEN chars, and in that case, is not
+      guaranteed to be null terminated.
+    */
+    (void)strncpy (map->command, command, MAXCOMLEN);
+    map->command[MAXCOMLEN] = '\0';
 }
 
 
index a44eb7ade523eeb3c7797159817872e00e1d040c..1dd3015391e9ce17034c24f69399b7add334e258 100644 (file)
@@ -542,7 +542,6 @@ setctty(name, flags)
        int fd;
 
        (void) revoke(name);
-       sleep (2);                      /* leave DTR low */
        if ((fd = open(name, flags | O_RDWR)) == -1) {
                stall("can't open %s: %m", name);
                _exit(1);
index b00a2324c4a73d45d73d7eac1416df485dfc9f5a..2030b48f403c29e3fc41a23dbb9926b4e629d06b 100644 (file)
@@ -838,7 +838,7 @@ static KEXTReturn _KEXTDModuleErrorCB(KEXTManagerRef manager, KEXTModuleRef modu
 #if TIMERSOURCE
 static void _KEXTDTimerCallout(CFRunLoopTimerRef timer, void * info)
 {
-    KEXTDScanPaths((KEXTDRef)info);
+    KEXTDScanPaths((KEXTDRef)info, false);
 }
 #endif
 
@@ -853,7 +853,7 @@ static void _KEXTDSIGHUPCallout(void * info)
 
     // Check for new or removed bundles and do the appropriate
     // things.
-    KEXTDScanPaths((KEXTDRef)info);
+    KEXTDScanPaths((KEXTDRef)info, false);
 
     // Make sure we try to load the unloaded personalities
     // It's probably overkill to do this here.
@@ -870,7 +870,7 @@ static void _KEXTDPerform(void * info)
 
     k = (KEXTD *)info;
 
-//    KEXTDScanPaths((KEXTDRef)k);
+//    KEXTDScanPaths((KEXTDRef)k, false);
 
     PTLockTakeLock(k->_queue_lock);
     while ( !queue_empty(&k->_requestQ) ) {
@@ -886,13 +886,7 @@ static void _KEXTDPerform(void * info)
         name = reqstruct->kmodname;
         free(reqstruct);
 
-       if( type == kIOCatalogMatchIdle) {
-
-           mach_timespec_t timeout = { 10, 0 };
-           IOKitWaitQuiet( k->_catPort, &timeout );
-           KEXTdaemonSignal();
-
-        } else if ( name ) {
+        if ( name ) {
 
             if ( k->_beVerbose ) {
                 char modname[256];
@@ -1038,7 +1032,7 @@ void KEXTDReset(KEXTDRef kextd)
     if ( k->_manager )
         KEXTManagerReset(k->_manager);
     
-    KEXTDScanPaths(kextd);
+    KEXTDScanPaths(kextd, false);
 }
 
 static KEXTReturn _KEXTDSendDataToCatalog(KEXTDRef kextd, int flag, CFTypeRef obj)
@@ -1123,10 +1117,10 @@ static KEXTReturn _KEXTDSendPersonalities(KEXTDRef kextd, KEXTBootlevel bootleve
 
     if ( CFArrayGetCount(toload) > 0 ) {
         error = KEXTManagerLoadPersonalities(((KEXTD *)kextd)->_manager, toload);
-    } else {
-       KEXTdaemonSignal();
     }
 
+    KEXTdaemonSignal();
+
     CFRelease(toload);
 
     return error;
@@ -1355,7 +1349,6 @@ KEXTReturn KEXTDKernelRequest(KEXTDRef kextd, CFStringRef name)
 static void * _KEXTDKmodWait(void * info)
 {
     mach_port_t kmodPort;
-    kern_return_t kr;
     KEXTD * kextd;
     KEXTReturn error;
     request_t * reqstruct;
@@ -1464,7 +1457,7 @@ KEXTdaemonSignal(void)
        return;
     signalled = TRUE;
     if (gDebug) {
-        printf("kextd: idle\n");
+        printf("kextd: signal\n");
        return;
     }
 
@@ -1486,11 +1479,17 @@ static void
 KEXTdaemonWait(void)
 {
     kern_return_t      kr;
+    mach_port_t                masterPort;
     mach_timespec_t    waitTime = { 40, 0 };
 
     kr = semaphore_timedwait( gDaemonSema, waitTime );
     if( kr != KERN_SUCCESS )
         syslog(LOG_ERR, "semaphore_timedwait(%lx)\n", kr);
+
+    IOMasterPort( MACH_PORT_NULL, &masterPort );
+    IOKitWaitQuiet( masterPort, &waitTime );
+    if( kr != KERN_SUCCESS )
+        syslog(LOG_ERR, "IOKitWaitQuiet(%lx)\n", kr);
 }
 
 static int
@@ -1547,9 +1546,9 @@ KEXTdaemon(nochdir, noclose)
 
 
 #if TIMERSOURCE
-KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel)
+KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel, Boolean cdMKextBoot)
 #else
-KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, KEXTBootlevel bootlevel)
+KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, KEXTBootlevel bootlevel, Boolean cdMKextBoot)
 #endif
 {
     pthread_attr_t kmod_thread_attr;
@@ -1585,7 +1584,7 @@ KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, B
     };
 
     gDebug = debug;
-    if (!debug) {
+    if (!debug && !cdMKextBoot) {
         errno = 0;
         KEXTdaemon(0, 0);
         if ( errno ) {
@@ -1616,6 +1615,11 @@ KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, B
 
     _kextd = kextd;
 
+    if( cdMKextBoot) {
+        KEXTDScanPaths(kextd, true);
+        return kKEXTReturnSuccess;
+    }
+
     // FIXME: Need a way to make this synchronous!
     error = KERN2KEXTReturn(IOCatalogueSendData(k->_catPort, kIOCatalogRemoveKernelLinker, 0, 0));
     if (error != kKEXTReturnSuccess) {
@@ -1672,7 +1676,7 @@ KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, B
     syslog(LOG_INFO, "started.");
 
     IOCatalogueReset(k->_catPort, kIOCatalogResetDefault);
-    KEXTDScanPaths(kextd);
+    KEXTDScanPaths(kextd, false);
 
 #if TIMERSOURCE
     if ( poll ) {
@@ -1705,7 +1709,7 @@ KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, B
     return kKEXTReturnSuccess;
 }
 
-void KEXTDScanPaths(KEXTDRef kextd)
+void KEXTDScanPaths(KEXTDRef kextd, Boolean cdMKextBoot)
 {
     KEXTReturn error;
     KEXTD * k;
@@ -1732,9 +1736,11 @@ void KEXTDScanPaths(KEXTDRef kextd)
                     syslog(LOG_INFO, "scanning: %s.", str);
                 }
             }
-            error = KEXTManagerScanPath(k->_manager, url);
-            if ( error != kKEXTReturnSuccess ) {
-                syslog(LOG_ERR, "error (%d) scanning path.\n", error);
+            if( !cdMKextBoot) {
+                error = KEXTManagerScanPath(k->_manager, url);
+                if ( error != kKEXTReturnSuccess ) {
+                    syslog(LOG_ERR, "error (%d) scanning path.\n", error);
+                }
             }
 #if LOOKAPPLENDRV
            do {
index cdd6088d73f262a6fefa8264f6f41399690f55db..9cd505540454f448057062ef6f8f5702e114831e 100644 (file)
@@ -47,11 +47,11 @@ void                KEXTDFree(KEXTDRef kextd);
 void            KEXTDHangup(KEXTDRef kextd);
 void           KEXTDReset(KEXTDRef kextd);
 #if TIMERSOURCE
-KEXTReturn     KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel);
+KEXTReturn     KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel, Boolean cdMKextBoot);
 #else
-KEXTReturn     KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, KEXTBootlevel bootlevel);
+KEXTReturn     KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, KEXTBootlevel bootlevel, Boolean cdMKextBoot);
 #endif
-void           KEXTDScanPaths(KEXTDRef kextd);
+void           KEXTDScanPaths(KEXTDRef kextd, Boolean cdMKextBoot);
 void           KEXTDAddScanPath(KEXTDRef kextd, CFURLRef path);
 void           KEXTDRegisterHelperCallbacks(KEXTDRef kextd, KEXTDHelperCallbacks * callbacks);
 KEXTReturn      KEXTDKernelRequest(KEXTDRef kextd, CFStringRef moduleName);
index 0537f47e20198540861055b5f80d7e16c2596e3f..778b1870d7e2689e86102391a3784ec57192c742 100644 (file)
@@ -9,7 +9,7 @@ static const char * arg0 = NULL;
 
 static void usage(void)
 {
-    printf("usage: %s [-v] [-d] [-x] [-b bootlevel]\n", arg0);
+    printf("usage: %s [-v] [-d] [-x] [-j] [-b bootlevel] [-f dirpath]\n", arg0);
     exit(1);
 }
 
@@ -18,14 +18,15 @@ int main (int argc, const char *argv[])
     KEXTDRef kextd;
     KEXTReturn error;
     KEXTBootlevel bootlevel;
+    CFStringRef str;
     CFURLRef url;
-    CFArrayRef array;
+    CFMutableArrayRef array;
     CFIndex period;
     Boolean safeBoot;
     Boolean beVerbose;
     Boolean enableTimer;
     Boolean debug;
-    const void * vals[1];
+    Boolean cdMKextBoot;
     int c;
 
     arg0 = argv[0];
@@ -34,14 +35,27 @@ int main (int argc, const char *argv[])
     safeBoot = false;
     beVerbose = false;
     enableTimer = false;
+    cdMKextBoot = false;
     bootlevel = kKEXTBootlevelNormal;
 
-    while ( (c = getopt(argc, (char **)argv, "xvdb:")) != -1 ) {
+    url = CFURLCreateWithFileSystemPath(NULL, CFSTR(DEFAULT_SEARCH_PATH), kCFURLPOSIXPathStyle, true);
+    if ( !url ) {
+        printf("Error opening: %s.\n", DEFAULT_SEARCH_PATH);
+        exit(1);
+    }
+    array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue(array, url);
+    CFRelease(url);
+
+    while ( (c = getopt(argc, (char **)argv, "xvdjb:f:")) != -1 ) {
         switch ( c ) {
 
             case 'x':
                 safeBoot = true;
                 break;
+            case 'v':
+                beVerbose = true;
+                break;
             case 'd':
                 debug = true;
                 break;
@@ -68,6 +82,27 @@ int main (int argc, const char *argv[])
                 }
                 break;
 
+            case 'j':
+                cdMKextBoot = true;
+                break;
+                
+            case 'f':
+                if ( !optarg ) {
+                    usage();
+                }
+                str = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingNonLossyASCII);
+                if ( str )
+                    url = CFURLCreateWithFileSystemPath(NULL, str, kCFURLPOSIXPathStyle, true);
+                else
+                    url = NULL;
+                if ( !url ) {
+                    printf("Error opening: %s.\n", optarg);
+                } else {
+                    CFArrayAppendValue(array, url);
+                    CFRelease(url);
+                }
+                break;
+
             default:
                 usage();
         }
@@ -79,16 +114,6 @@ int main (int argc, const char *argv[])
         usage();
     }
 
-
-
-    url = CFURLCreateWithFileSystemPath(NULL, CFSTR(DEFAULT_SEARCH_PATH), kCFURLPOSIXPathStyle, true);
-    if ( !url ) {
-        printf("Error opening: %s.\n", DEFAULT_SEARCH_PATH);
-        exit(1);
-    }
-    vals[0] = url;
-    array = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks);
-    CFRelease(url);
     kextd = KEXTDCreate(array, &error);
     CFRelease(array);
     if ( !kextd ) {
@@ -98,9 +123,9 @@ int main (int argc, const char *argv[])
     
     KEXTDRegisterHelperCallbacks(kextd, NULL);
 #if TIMERSOURCE
-    error = KEXTDStartMain(kextd, beVerbose, safeBoot, debug, enableTimer, period, bootlevel);
+    error = KEXTDStartMain(kextd, beVerbose, safeBoot, debug, enableTimer, period, bootlevel, cdMKextBoot);
 #else
-    error = KEXTDStartMain(kextd, beVerbose, safeBoot, debug, bootlevel);
+    error = KEXTDStartMain(kextd, beVerbose, safeBoot, debug, bootlevel, cdMKextBoot);
 #endif
     if ( error != kKEXTReturnSuccess ) {
         KEXTDFree(kextd);
index 56510b3df5f5a83b7157ac0930e4a409a0a1964d..a43517e0a562d547ca5e97573b7f9e2fcc38f15a 100644 (file)
@@ -31,8 +31,8 @@ PROF_LIBS = $(LIBS)
 
 
 NEXTSTEP_PB_CFLAGS = -fpascal-strings -Wno-four-char-constants
-NEXTSTEP_PB_LDFLAGS = -undefined warning
-FRAMEWORKS = -framework IOKit
+
+FRAMEWORKS = -framework CoreFoundation -framework IOKit
 
 
 NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
index 6a19916ae9ba32a660dacb0300a55ef751e84e45..dd503bf35776ff25e54c9564e67255b5c0d69456 100644 (file)
@@ -1,7 +1,7 @@
 {
     DYNAMIC_CODE_GEN = YES; 
     FILESTABLE = {
-        FRAMEWORKS = (IOKit.framework); 
+        FRAMEWORKS = (CoreFoundation.framework, IOKit.framework); 
         FRAMEWORKSEARCH = (); 
         H_FILES = (GetSymbolFromPEF.h, KEXTD.h, PTLock.h); 
         OTHER_LINKED = (KEXTD.c, KEXTD_main.c, PEFSupport.c, PTLock.c); 
@@ -14,7 +14,6 @@
     NEXTSTEP_COMPILEROPTIONS = "-fpascal-strings -Wno-four-char-constants"; 
     NEXTSTEP_INSTALLDIR = /usr/libexec; 
     NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
-    NEXTSTEP_LINKEROPTIONS = "-undefined warning"; 
     NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
     PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
     PDO_UNIX_INSTALLDIR = /bin; 
index 0e72c0720173c0939cc4eee0e86bb7b7f49c26a7..d09afc4b830111373bd977fc02102cd436160212 100644 (file)
@@ -28,7 +28,7 @@ DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-FRAMEWORKS = -framework IOKit
+FRAMEWORKS = -framework CoreFoundation -framework IOKit
 
 
 NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
index bf00197edb13d5c295979056d1e19bf9f932a649..d23d6b31093fe1d34863c3a9f719ecea98cd5165 100644 (file)
@@ -1,7 +1,7 @@
 {
     DYNAMIC_CODE_GEN = YES; 
     FILESTABLE = {
-        FRAMEWORKS = (IOKit.framework); 
+        FRAMEWORKS = (CoreFoundation.framework, IOKit.framework); 
         OTHER_LINKED = (kextload_main.c); 
         OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kextload.8); 
         SUBPROJECTS = (); 
index ab6a55be1f5e1ca622aaf7f9ef664feadeccb10b..2df339822ac04b3e1300cb58834982423d12706c 100644 (file)
@@ -28,7 +28,7 @@ DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-FRAMEWORKS = -framework IOKit
+FRAMEWORKS = -framework CoreFoundation -framework IOKit
 
 
 NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
index 7089f1b69cc08d06f07bad239a3b6c59173754cc..3b295113f2bf1ea13566b1119b6c97d32571fc41 100644 (file)
@@ -1,7 +1,7 @@
 {
     DYNAMIC_CODE_GEN = YES; 
     FILESTABLE = {
-        FRAMEWORKS = (IOKit.framework); 
+        FRAMEWORKS = (CoreFoundation.framework, IOKit.framework); 
         OTHER_LINKED = (kextunload_main.c); 
         OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kextunload.8); 
     }; 
index 3704c8fe6407a7d28b820c49e3548bca7d8d2ea9..508f918b3185f9668f41b0bd2c7cc389c9d51fec 100644 (file)
@@ -12,7 +12,9 @@ NAME = kmodload
 PROJECTVERSION = 2.8
 PROJECT_TYPE = Tool
 
-CFILES = kmodload.c
+HFILES = kld_patch.h
+
+CFILES = kld_patch.c kmodload.c
 
 OTHERSRCS = Makefile.preamble Makefile Makefile.postamble kmodload.8\
             kmodsyms.8
@@ -29,8 +31,6 @@ DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-HEADER_PATHS =\
-               -I$(NEXT_ROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
 
 
 NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
index b8fba6b872467428d737535fb33921387e261374..474d5fea1eef3d1020438c223e9b36cc7dd1e1d1 100644 (file)
@@ -2,9 +2,10 @@
     DYNAMIC_CODE_GEN = YES; 
     FILESTABLE = {
         FRAMEWORKS = (); 
-        HEADERSEARCH = ("$(NEXT_ROOT)/System/Library/Frameworks/System.framework/PrivateHeaders"); 
+        HEADERSEARCH = (); 
+        H_FILES = (kld_patch.h); 
         OTHER_LIBS = (kld); 
-        OTHER_LINKED = (kmodload.c); 
+        OTHER_LINKED = (kld_patch.c, kmodload.c); 
         OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kmodload.8, kmodsyms.8); 
     }; 
     LANGUAGE = English; 
diff --git a/kmodload.tproj/kld_patch.c b/kmodload.tproj/kld_patch.c
new file mode 100644 (file)
index 0000000..646bf14
--- /dev/null
@@ -0,0 +1,2124 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License').  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * History:
+ *  2001-05-30         gvdl    Initial implementation of the vtable patcher.
+ */
+// 45678901234567890123456789012345678901234567890123456789012345678901234567890
+
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+
+#if KERNEL
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <sys/systm.h>
+
+#include <libkern/OSTypes.h>
+
+#include <libsa/stdlib.h>
+#include <libsa/mach/mach.h>
+
+#include "mach_loader.h"
+
+#include <vm/vm_kern.h>
+
+enum { false = 0, true = 1 };
+
+#define vm_page_size page_size
+
+extern load_return_t fatfile_getarch(
+    void            * vp,       // normally a (struct vnode *)
+    vm_offset_t       data_ptr,
+    struct fat_arch * archret);
+
+#else /* !KERNEL */
+#include <unistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/errno.h> 
+#include <sys/fcntl.h>
+#include <sys/stat.h>   
+#include <sys/mman.h>   
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <mach-o/arch.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#endif /* KERNEL */
+
+#include "kld_patch.h"
+
+#if 0
+static __inline__ void DIE(void) { IODelay(2000000000); }
+
+#define LOG_DELAY()    IODelay(200000)
+#define DEBUG_LOG(x)   do { IOLog x; LOG_DELAY(); } while(0)
+#else
+
+#define DIE()
+#define LOG_DELAY()
+#define DEBUG_LOG(x)
+
+#endif
+
+// OSObject symbol prefixes and suffixes
+#define kVTablePrefix          "___vt"
+#define kReservedPrefix                "__RESERVED"
+#define kSuperClassSuffix      ".superClass"
+#define kGMetaSuffix           ".gMetaClass"
+#define kLinkEditSegName       SEG_LINKEDIT
+
+// GCC 2.95 drops 2 leading constants in the vtable
+#define kVTablePreambleLen 2
+
+// Last address that I'm willing to try find vm in
+#define kTopAddr  ((unsigned char *) (1024 * 1024 * 1024))
+
+// Size in bytes that Data Ref object's get increased in size
+// Must be a power of 2
+#define kDataCapacityIncrement 128
+
+// My usual set of helper macros.  I personally find these macros
+// easier to read in the code rather than an explicit error condition
+// check.  If I don't make it easy then I may get lazy ond not check
+// everything.  I'm sorry if you find this code harder to read.
+
+// break_if will evaluate the expression and if it is true
+// then it will print the msg, which is enclosed in parens
+// and then break.  Usually used in loops are do { } while (0)
+#define break_if(expr, msg)                                    \
+    if (expr) {                                                        \
+       errprintf msg;                                          \
+        break;                                                 \
+    }
+
+// return_if will evaluate expr and if true it will log the
+// msg, which is enclosed in parens, and then it will return
+// with the return code of ret.
+#define return_if(expr, ret, msg) do {                         \
+    if (expr) {                                                        \
+       errprintf msg;                                          \
+        return ret;                                            \
+    }                                                          \
+} while (0)
+
+#ifndef MIN
+#define        MIN(a,b) (((a)<(b))?(a):(b))
+#endif /* MIN */
+#ifndef MAX
+#define        MAX(a,b) (((a)>(b))?(a):(b))
+#endif /* MAX */
+
+typedef struct Data {
+    unsigned long fLength, fCapacity;
+    unsigned char *fData;
+} Data, *DataRef;
+
+struct sectionRecord {
+    const struct section *fSection;
+    DataRef fRelocCache;
+};
+
+enum patchState {
+    kSymbolIdentical,
+    kSymbolLocal,
+    kSymbolPadUpdate,
+    kSymbolSuperUpdate,
+    kSymbolMismatch
+};
+
+struct patchRecord {
+    struct nlist *fSymbol;
+    enum patchState fType;
+};
+
+struct relocRecord {
+    void *fValue;
+    const struct nlist *fSymbol;
+    struct relocation_info *fRInfo;
+    void *reserved;
+};
+
+struct metaClassRecord {
+    char *fSuperName;
+    struct fileRecord *fFile;
+    const struct nlist *fVTableSym;
+    struct patchRecord *fPatchedVTable;
+    char fClassName[1];
+};
+
+struct fileRecord {
+    size_t fMapSize, fMachOSize;
+    const char *fPath;
+    unsigned char *fMap, *fMachO, *fPadEnd;
+    DataRef fClassList;
+    DataRef fSectData;
+    DataRef fNewSymbols, fNewStrings;
+    struct symtab_command *fSymtab;
+    struct sectionRecord *fSections;
+    char *fStringBase;
+    struct nlist *fSymbolBase;
+    const struct nlist *fLocalSyms;
+    unsigned int fNSects;
+    int fNLocal;
+    int fNewStringsLen;
+    Boolean fIsKernel, fNoKernelExecutable, fIsKmem;
+    Boolean fImageDirty, fSymbolsDirty;
+};
+
+static DataRef sFilesTable;
+static struct fileRecord *sKernelFile;
+
+static DataRef sMergedFiles;
+static DataRef sMergeMetaClasses;
+static Boolean sMergedKernel;
+
+static void errprintf(const char *fmt, ...)
+{
+    extern void kld_error_vprintf(const char *format, va_list ap);
+
+    va_list ap;
+
+    va_start(ap, fmt);
+    kld_error_vprintf(fmt, ap);
+    va_end(ap);
+
+DIE();
+}
+
+static __inline__ unsigned long DataGetLength(DataRef data)
+{
+    return data->fLength;
+}
+
+static __inline__ unsigned char *DataGetPtr(DataRef data)
+{
+    return data->fData;
+}
+
+
+static __inline__ Boolean DataContainsAddr(DataRef data, void *vAddr)
+{
+    unsigned char *addr = vAddr;
+
+    return (data->fData <= addr) && (addr < data->fData + data->fLength);
+}
+
+static __inline__ Boolean DataAddLength(DataRef data, unsigned long length)
+{
+    static Boolean DataSetLength(DataRef data, unsigned long length);
+    return DataSetLength(data, data->fLength + length);
+}
+
+static __inline__ Boolean
+DataAppendBytes(DataRef data, const void *addr, unsigned int len)
+{
+    unsigned long size = DataGetLength(data);
+
+    if (!DataAddLength(data, len))
+       return false;
+
+    bcopy(addr, DataGetPtr(data) + size, len);
+    return true;
+}
+
+static __inline__ Boolean DataAppendData(DataRef dst, DataRef src)
+{
+    return DataAppendBytes(dst, DataGetPtr(src), DataGetLength(src));
+}
+
+static Boolean DataSetLength(DataRef data, unsigned long length)
+{
+    // Don't bother to ever shrink a data object.
+    if (length > data->fCapacity) {
+       unsigned char *newData;
+       unsigned long newCapacity;
+
+       newCapacity  = length + kDataCapacityIncrement - 1;
+       newCapacity &= ~(kDataCapacityIncrement - 1);
+       newData = (unsigned char *) realloc(data->fData, newCapacity);
+       if (!newData)
+           return false;
+
+       bzero(newData + data->fCapacity, newCapacity - data->fCapacity);
+       data->fData = newData;
+       data->fCapacity = newCapacity;
+    }
+
+    data->fLength = length;
+    return true;
+}
+
+static DataRef DataCreate(unsigned long length)
+{
+    DataRef data = (DataRef) malloc(sizeof(Data));
+
+    if (data) {
+       if (!length)
+           data->fCapacity = kDataCapacityIncrement;
+       else {
+           data->fCapacity  = length + kDataCapacityIncrement - 1;
+           data->fCapacity &= ~(kDataCapacityIncrement - 1);
+       }
+
+       data->fData = (unsigned char *) malloc(data->fCapacity);
+       if (!data->fData) {
+           free(data);
+           return NULL;
+       }
+
+       bzero(data->fData, data->fCapacity);
+       data->fLength = length;
+    }
+    return data;
+}
+
+static void DataRelease(DataRef data)
+{
+    if (data) {
+       if (data->fData)
+           free(data->fData);
+       data->fData = 0;
+       free(data);
+    }
+}
+
+static const char *
+symbolname(const struct fileRecord *file, const struct nlist *sym)
+{
+    unsigned long strsize;
+    long strx = sym->n_un.n_strx;
+
+    if (strx >= 0)
+       return file->fStringBase + strx;
+
+    strsize = file->fSymtab->strsize;
+    strx = -strx;
+    if (strx < strsize)
+       return file->fStringBase + strx;
+
+    strx -= strsize;
+    return (char *) DataGetPtr(file->fNewStrings) + strx;
+}
+
+static struct fileRecord *getFile(const char *path)
+{
+    if (sFilesTable) {
+       int i, nfiles;
+       struct fileRecord **files;
+
+        // Check to see if we have already merged this file
+       nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
+       files = (struct fileRecord **) DataGetPtr(sFilesTable);
+       for (i = 0; i < nfiles; i++) {
+           if (!strcmp(path, files[i]->fPath))
+               return files[i];
+       }
+    }
+
+    return NULL;
+}
+
+static struct fileRecord * addFile(struct fileRecord *file)
+{
+    struct fileRecord *newFile;
+
+    if (!sFilesTable) {
+       sFilesTable = DataCreate(0);
+       if (!sFilesTable)
+           return NULL;
+    }
+
+    newFile = (struct fileRecord *) malloc(sizeof(struct fileRecord));
+    if (!newFile)
+       return NULL;
+
+    if (!DataAppendBytes(sFilesTable, &newFile, sizeof(newFile))) {
+       free(newFile);
+       return NULL;
+    }
+
+    bcopy(file, newFile, sizeof(struct fileRecord));
+    return newFile;
+}
+
+// @@@ gvdl: need to clean up the sMergeMetaClasses
+// @@@ gvdl: I had better fix the object file up again
+static void removeFile(struct fileRecord *file)
+{
+    if (file->fClassList) {
+       DataRelease(file->fClassList);
+       file->fClassList = 0;
+    }
+
+    if (file->fSectData) {
+       struct sectionRecord *section;
+       unsigned int i, nsect;
+
+       nsect = file->fNSects;
+       section = file->fSections;
+       for (i = 0; i < nsect; i++, section++) {
+           if (section->fRelocCache) {
+               DataRelease(section->fRelocCache);
+               section->fRelocCache = 0;
+           }
+       }
+
+       DataRelease(file->fSectData);
+       file->fSectData = 0;
+       file->fSections = 0;
+       file->fNSects = 0;
+    }
+
+    if (file->fMap) {
+#if KERNEL
+       if (file->fIsKmem)
+           kmem_free(kernel_map, (vm_address_t) file->fMap, file->fMapSize);
+#else /* !KERNEL */
+       if (file->fPadEnd) {
+           vm_address_t padVM;
+           vm_size_t padSize;
+
+           padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
+           padSize  = (vm_size_t) ((vm_address_t) file->fPadEnd - padVM);
+           (void) vm_deallocate(mach_task_self(), padVM, padSize);
+           file->fPadEnd = 0;
+       }
+
+       (void) munmap((caddr_t) file->fMap, file->fMapSize);
+#endif /* !KERNEL */
+       file->fMap = 0;
+    }
+
+    file->fPath = 0;
+}
+
+#if !KERNEL
+static Boolean
+mapObjectFile(struct fileRecord *file)
+{
+    Boolean result = false;
+    static unsigned char *sFileMapBaseAddr;
+
+    int fd = 0;
+
+    if (!sFileMapBaseAddr) {
+        kern_return_t ret;
+       vm_address_t probeAddr;
+
+       // If we don't already have a base addr find any random chunk
+       // of 32 meg of VM and to use the 16 meg boundrary as a base.
+        ret = vm_allocate(mach_task_self(), &probeAddr,
+                           32 * 1024 * 1024, VM_FLAGS_ANYWHERE);
+       return_if(KERN_SUCCESS != ret, false,
+           ("Unable to allocate base memory %s\n", mach_error_string(ret)));
+        (void) vm_deallocate(mach_task_self(), probeAddr, 32 * 1024 * 1024);
+
+       // Now round to the next 16 Meg boundrary
+       probeAddr = (probeAddr +  (16 * 1024 * 1024 - 1))
+                              & ~(16 * 1024 * 1024 - 1);
+       sFileMapBaseAddr = (unsigned char *) probeAddr;
+    }
+
+    fd = open(file->fPath, O_RDONLY, 0);
+    return_if(fd == -1, false, ("Can't open %s for reading - %s\n",
+       file->fPath, strerror(errno)));
+
+    do {
+       kern_return_t ret;
+       struct stat sb;
+       int retaddr = -1;
+
+       break_if(fstat(fd, &sb) == -1,
+           ("Can't stat %s - %s\n", file->fPath, strerror(errno)));
+
+       file->fMapSize = sb.st_size;
+       file->fMap = sFileMapBaseAddr;
+       ret = KERN_SUCCESS;
+       while (file->fMap < kTopAddr) {
+           vm_address_t padVM;
+           vm_address_t padVMEnd;
+           vm_size_t padSize;
+
+           padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
+           retaddr = (int) mmap(file->fMap, file->fMapSize,
+                                PROT_READ|PROT_WRITE, 
+                                MAP_FIXED|MAP_FILE|MAP_PRIVATE,
+                                fd, 0);
+           if (-1 == retaddr) {
+               break_if(ENOMEM != errno,
+                   ("mmap failed %d - %s\n", errno, strerror(errno)));
+
+               file->fMap = (unsigned char *) padVM;
+               continue;
+           }
+
+
+           // Round up padVM to the next page after the file and assign at
+           // least another fMapSize more room rounded up to the next page
+           // boundary.
+           padVMEnd = round_page(padVM + file->fMapSize);
+           padSize  = padVMEnd - padVM;
+           ret = vm_allocate(
+               mach_task_self(), &padVM, padSize, VM_FLAGS_FIXED);
+           if (KERN_SUCCESS == ret) {
+               file->fPadEnd = (unsigned char *) padVMEnd;
+               break;
+           }
+           else {
+               munmap(file->fMap, file->fMapSize);
+               break_if(KERN_INVALID_ADDRESS != ret,
+                   ("Unable to allocate pad vm for %s - %s\n",
+                       file->fPath, mach_error_string(ret)));
+
+               file->fMap = (unsigned char *) padVMEnd;
+               continue; // try again wherever the vm system wants
+           }
+       }
+
+       if (-1 == retaddr || KERN_SUCCESS != ret)
+           break;
+
+       break_if(file->fMap >= kTopAddr,
+           ("Unable to map memory %s\n", file->fPath));
+
+       sFileMapBaseAddr = file->fPadEnd;
+       result = true;
+    } while(0);
+
+    close(fd);
+    return result;
+}
+#endif /* !KERNEL */
+
+static Boolean findBestArch(struct fileRecord *file)
+{
+    unsigned long magic;
+    struct fat_header *fat;
+
+
+    file->fMachOSize = file->fMapSize;
+    file->fMachO = file->fMap;
+    magic = ((const struct mach_header *) file->fMachO)->magic;
+    fat = (struct fat_header *) file->fMachO;
+
+    // Try to figure out what type of file this is
+    return_if(file->fMapSize < sizeof(unsigned long), false,
+       ("%s isn't a valid object file - no magic\n", file->fPath));
+
+#if KERNEL
+
+    // CIGAM is byte-swapped MAGIC
+    if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
+
+        load_return_t load_return;
+        struct fat_arch fatinfo;
+
+        load_return = fatfile_getarch(NULL, (vm_address_t) fat, &fatinfo);
+       return_if(load_return != LOAD_SUCCESS, false,
+           ("Extension \"%s\": has no code for this computer\n", file->fPath));
+
+       file->fMachO = file->fMap + fatinfo.offset;
+       file->fMachOSize = fatinfo.size;
+       magic = ((const struct mach_header *) file->fMachO)->magic;
+    }
+
+#else /* !KERNEL */
+
+    // Do we need to in-place swap the endianness of the fat header?
+    if (magic == FAT_CIGAM) {
+       unsigned long i;
+       struct fat_arch *arch;
+
+       fat->nfat_arch = NXSwapBigLongToHost(fat->nfat_arch);
+       return_if(file->fMapSize < sizeof(struct fat_header)
+                                   + fat->nfat_arch * sizeof(struct fat_arch),
+           false, ("%s is too fat\n", file->fPath));
+
+       arch = (struct fat_arch *) &fat[1];
+       for (i = 0; i < fat->nfat_arch; i++) {
+           arch[i].cputype    = NXSwapBigLongToHost(arch[i].cputype);
+           arch[i].cpusubtype = NXSwapBigLongToHost(arch[i].cpusubtype);
+           arch[i].offset     = NXSwapBigLongToHost(arch[i].offset);
+           arch[i].size       = NXSwapBigLongToHost(arch[i].size);
+           arch[i].align      = NXSwapBigLongToHost(arch[i].align);
+       }
+
+       magic = NXSwapBigLongToHost(fat->magic);
+    }
+
+    // Now see if we can find any valid architectures
+    if (magic == FAT_MAGIC) {
+       const NXArchInfo *myArch;
+       unsigned long fatsize;
+       struct fat_arch *arch;
+
+       fatsize = sizeof(struct fat_header)
+           + fat->nfat_arch * sizeof(struct fat_arch);
+       return_if(file->fMapSize < fatsize,
+           false, ("%s isn't a valid fat file\n", file->fPath));
+
+       myArch = NXGetLocalArchInfo();
+       arch = NXFindBestFatArch(myArch->cputype, myArch->cpusubtype,
+               (struct fat_arch *) &fat[1], fat->nfat_arch);
+       return_if(!arch,
+           false, ("%s hasn't got arch for %s\n", file->fPath, myArch->name));
+       return_if(arch->offset + arch->size > file->fMapSize,
+           false, ("%s's %s arch is incomplete\n", file->fPath, myArch->name));
+       file->fMachO = file->fMap + arch->offset;
+       file->fMachOSize = arch->size;
+       magic = ((const struct mach_header *) file->fMachO)->magic;
+    }
+
+#endif /* KERNEL */
+
+    return_if(magic != MH_MAGIC,
+       false, ("%s isn't a valid mach-o\n", file->fPath));
+
+    return true;
+}
+
+static Boolean
+parseSegments(struct fileRecord *file, struct segment_command *seg)
+{
+    struct sectionRecord *sections;
+    int i, nsects = seg->nsects;
+    const struct segmentMap {
+       struct segment_command seg;
+       const struct section sect[1];
+    } *segMap;
+
+    if (!nsects) {
+#if KERNEL
+       // We don't need to look for the LinkEdit segment unless
+       // we are running in the kernel environment.
+       if (!strcmp(kLinkEditSegName, seg->segname)) {
+           // Grab symbol table from linkedit we will need this later
+           file->fSymbolBase = (void *) seg;
+       }
+#endif
+
+       return true;    // Nothing more to do, so that was easy.
+    }
+
+    if (!file->fSectData) {
+       file->fSectData = DataCreate(0);
+       if (!file->fSectData)
+           return false;
+    }
+
+    // Increase length of section DataRef and cache data pointer
+    if (!DataAddLength(file->fSectData, nsects * sizeof(struct sectionRecord)))
+       return false;
+    file->fSections = (struct sectionRecord *) DataGetPtr(file->fSectData);
+
+    // Initialise the new sections
+    sections = &file->fSections[file->fNSects];
+    file->fNSects += nsects;
+    for (i = 0, segMap = (struct segmentMap *) seg; i < nsects; i++)
+       sections[i].fSection = &segMap->sect[i];
+
+    return true;
+}
+
+// @@@ gvdl:  These functions need to be hashed they are
+// going to be way too slow for production code.
+static const struct nlist *
+findSymbolByAddress(const struct fileRecord *file, void *entry)
+{
+    // not quite so dumb linear search of all symbols
+    const struct nlist *sym;
+    int i, nsyms;
+
+    // First try to find the symbol in the most likely place which is the
+    // extern symbols
+    sym = file->fLocalSyms;
+    for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
+       if (sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
+           return sym;
+    }
+
+    // Didn't find it in the external symbols so try to local symbols before
+    // giving up.
+    sym = file->fSymbolBase;
+    for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
+       if ( (sym->n_type & N_EXT) )
+           return NULL;
+       if ( sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
+           return sym;
+    }
+
+    return NULL;
+}
+
+struct searchContext {
+    const char *fSymname;
+    const char *fStrbase;
+};
+
+static int symbolSearch(const void *vKey, const void *vSym)
+{
+    const struct searchContext *key = (const struct searchContext *) vKey;
+    const struct nlist *sym = (const struct nlist *) vSym;
+
+    return strcmp(key->fSymname, key->fStrbase + sym->n_un.n_strx);
+}
+
+static const struct nlist *
+findSymbolByName(struct fileRecord *file, const char *symname)
+{
+    struct searchContext context;
+
+    context.fSymname = symname;
+    context.fStrbase = file->fStringBase;
+    return (struct nlist *)
+       bsearch(&context,
+               file->fLocalSyms, file->fNLocal, sizeof(struct nlist),
+               symbolSearch);
+}
+
+static Boolean
+relocateSection(const struct fileRecord *file, struct sectionRecord *sectionRec)
+{
+    const struct nlist *symbol;
+    const struct section *section;
+    struct relocRecord *rec;
+    struct relocation_info *rinfo;
+    unsigned long i;
+    unsigned long r_address, r_symbolnum, r_length;
+    enum reloc_type_generic r_type;
+    UInt8 *sectionBase;
+    void **entry;
+
+    sectionRec->fRelocCache = DataCreate(
+       sectionRec->fSection->nreloc * sizeof(struct relocRecord));
+    if (!sectionRec->fRelocCache)
+       return false;
+
+    section = sectionRec->fSection;
+    sectionBase = file->fMachO + section->offset;
+
+    rec = (struct relocRecord *) DataGetPtr(sectionRec->fRelocCache);
+    rinfo = (struct relocation_info *) (file->fMachO + section->reloff);
+    for (i = 0; i < section->nreloc; i++, rec++, rinfo++) {
+
+       // Totally uninterested in scattered relocation entries
+       if ( (rinfo->r_address & R_SCATTERED) )
+           continue;
+
+       r_address = rinfo->r_address;
+       entry = (void **) (sectionBase + r_address);
+
+       /*
+        * The r_address field is really an offset into the contents of the
+        * section and must reference something inside the section (Note
+        * that this is not the case for PPC_RELOC_PAIR entries but this
+        * can't be one with the above checks).
+        */
+       return_if(r_address >= section->size, false,
+           ("Invalid relocation entry in %s - not in section\n", file->fPath));
+
+       // If we don't have a VANILLA entry or the Vanilla entry isn't
+       // a 'long' then ignore the entry and try the next.
+       r_type = (enum reloc_type_generic) rinfo->r_type;
+       r_length = rinfo->r_length;
+       if (r_type != GENERIC_RELOC_VANILLA || r_length != 2)
+           continue;
+
+       r_symbolnum = rinfo->r_symbolnum;
+
+       /*
+        * If rinfo->r_extern is set this relocation entry is an external entry
+        * else it is a local entry.
+        */
+       if (rinfo->r_extern) {
+           /*
+            * This is an external relocation entry.
+            * r_symbolnum is an index into the input file's symbol table
+            * of the symbol being refered to.  The symbol must be
+            * undefined to be used in an external relocation entry.
+            */
+           return_if(r_symbolnum >= file->fSymtab->nsyms, false, 
+               ("Invalid relocation entry in %s - no symbol\n", file->fPath));
+
+           /*
+            * If this is an indirect symbol resolve indirection (all chains
+            * of indirect symbols have been resolved so that they point at
+            * a symbol that is not an indirect symbol).
+            */
+           symbol = file->fSymbolBase;
+           if ((symbol[r_symbolnum].n_type & N_TYPE) == N_INDR)
+               r_symbolnum = symbol[r_symbolnum].n_value;
+           symbol = &symbol[r_symbolnum];
+
+           return_if(symbol->n_type != (N_EXT | N_UNDF), false, 
+               ("Invalid relocation entry in %s - extern\n", file->fPath));
+       }
+       else {
+           /*
+            * If the symbol is not in any section then it can't be a
+            * pointer to a local segment and I don't care about it.
+            */
+           if (r_symbolnum == R_ABS)
+               continue;
+
+           // Note segment references are offset by 1 from 0.
+           return_if(r_symbolnum > file->fNSects, false,
+               ("Invalid relocation entry in %s - local\n", file->fPath));
+
+           // Find the symbol, if any, that backs this entry 
+           symbol = findSymbolByAddress(file, *entry);
+       }
+
+       rec->fValue  = *entry;          // Save the previous value
+       rec->fRInfo  =  rinfo;          // Save a pointer to the reloc
+       rec->fSymbol =  symbol;         // Record the current symbol
+
+       *entry = (void *) rec;  // Save pointer to record in object image
+    }
+
+    ((struct fileRecord *) file)->fImageDirty = true;
+
+    return true;
+}
+
+static const struct nlist *
+findSymbolRefAtLocation(const struct fileRecord *file,
+                       struct sectionRecord *sctn, void **loc)
+{
+    if (file->fIsKernel) {
+       if (*loc)
+           return findSymbolByAddress(file, *loc);
+    }
+    else if (sctn->fRelocCache || relocateSection(file, sctn)) {
+       struct relocRecord *reloc = (struct relocRecord *) *loc;
+
+       if (DataContainsAddr(sctn->fRelocCache, reloc))
+           return reloc->fSymbol;
+    }
+
+    return NULL;
+}
+
+static Boolean
+addClass(struct fileRecord *file,
+        struct metaClassRecord *inClass,
+        const char *cname)
+{
+    struct metaClassRecord *newClass = NULL;
+    struct metaClassRecord **fileClasses = NULL;
+    int len;
+
+if (!file->fIsKernel) {        // @@@ gvdl:
+    DEBUG_LOG(("Adding Class %s\n", cname));
+}
+
+    if (!file->fClassList) {
+       file->fClassList = DataCreate(0);
+       if (!file->fClassList)
+           return false;
+    }
+
+    do {
+       // Attempt to allocate all necessary resource first
+       len = strlen(cname) + 1
+           + (int) (&((struct metaClassRecord *) 0)->fClassName);
+       newClass = (struct metaClassRecord *) malloc(len);
+       if (!newClass)
+           break;
+
+       if (!DataAddLength(file->fClassList, sizeof(struct metaClassRecord *)))
+           break;
+       fileClasses = (struct metaClassRecord **)
+           (DataGetPtr(file->fClassList) + DataGetLength(file->fClassList));
+
+       // Copy the meta Class structure and string name into newClass
+       // and insert object at end of the file->fClassList and sMergeMetaClasses 
+       *newClass = *inClass;
+       strcpy(newClass->fClassName, cname);
+       fileClasses[-1]   = newClass;
+
+       return true;
+    } while (0);
+
+    if (fileClasses)
+       DataAddLength(file->fClassList, -sizeof(struct metaClassRecord *));
+
+    if (newClass)
+       free(newClass);
+
+    return false;
+}
+
+static struct metaClassRecord *getClass(DataRef classList, const char *cname)
+{
+    if (classList) {
+       int i, nclass;
+       struct metaClassRecord **classes, *thisClass;
+    
+       nclass = DataGetLength(classList) / sizeof(struct metaClassRecord *);
+       classes = (struct metaClassRecord **) DataGetPtr(classList);
+       for (i = 0; i < nclass; i++) {
+           thisClass = classes[i];
+           if (!strcmp(thisClass->fClassName, cname))
+               return thisClass;
+       }
+    }
+
+    return NULL;
+}
+
+// Add the class 'cname' to the list of known OSObject based classes
+// Note 'sym' is the <cname>.superClass symbol. 
+static Boolean
+recordClass(struct fileRecord *file, const char *cname, const struct nlist *sym)
+{
+    char *supername = NULL;
+    const char *classname = NULL;
+    struct metaClassRecord newClass;
+    char strbuffer[1024];
+
+    // Only do the work actual work to find the super class if we are
+    // not currently working on  the kernel.  The kernel is the end
+    // of all superclass chains as by definition the kernel is binary
+    // compatible with itself.
+    if (!file->fIsKernel) {
+       const char *dot;
+       const struct nlist *supersym;
+       const struct section *section;
+       struct sectionRecord *sectionRec;
+       unsigned char sectind = sym->n_sect;
+       const char *superstr;
+       void **location;
+
+       // We can't resolve anything that isn't in a real section
+       // Note that the sectind is starts at one to make room for the
+       // NO_SECT flag but the fNSects field isn't offset so we have a
+       // '>' test.  Which means this isn't an OSObject based class
+       if (sectind == NO_SECT || sectind > file->fNSects)
+           return true;
+    
+       sectionRec = file->fSections + sectind - 1;
+       section = sectionRec->fSection;
+       location = (void **) ( file->fMachO + section->offset
+                           + sym->n_value - section->addr );
+    
+       supersym = findSymbolRefAtLocation(file, sectionRec, location);
+       if (!supersym)
+           return true;        // No superclass symbol then it isn't an OSObject.
+
+       // Find string in file and skip leading '_' and find last '.'
+       superstr = symbolname(file, supersym) + 1;
+       dot = strrchr(superstr, '.');
+       if (!dot || strcmp(dot, kGMetaSuffix))
+           return true;        // Not an OSObject superclass so ignore it.
+
+       supername = (char *) malloc(dot - superstr + 1);
+       strncpy(supername, superstr, dot - superstr);
+       supername[dot - superstr] = '\0';
+    }
+
+    do {
+       break_if(getClass(file->fClassList, cname),
+           ("Duplicate class %s in %s\n", cname, file->fPath));
+    
+       snprintf(strbuffer, sizeof(strbuffer), "%s%s", kVTablePrefix, cname);
+       newClass.fVTableSym = findSymbolByName(file, strbuffer);
+       break_if(!newClass.fVTableSym,
+           ("Can't find vtable %s in %s\n", cname, file->fPath));
+
+       newClass.fFile = file;
+       newClass.fSuperName = supername;
+       newClass.fPatchedVTable = NULL;
+    
+       // Can't use cname as it may be a stack variable
+       // However the vtable's string has the class name as a suffix
+       // so why don't we use that rather than mallocing a string.
+       classname = symbolname(file, newClass.fVTableSym)
+               + sizeof(kVTablePrefix) - 1;
+       break_if(!addClass(file, &newClass, classname), 
+                   ("recordClass - no memory?\n"));
+
+       return true;
+    } while (0);
+    
+    if (supername)
+       free(supername);
+
+    return false;
+}
+
+static Boolean getMetaClassGraph(struct fileRecord *file)
+{
+    const struct nlist *sym;
+    const char *strbase;
+    int i, nsyms;
+
+    // Search the symbol table for the local symbols that are generated
+    // by the metaclass system.  There are three metaclass variables
+    // that are relevant.
+    //
+    //   <ClassName>.metaClass A pointer to the meta class structure.
+    //  <ClassName>.superClass A pointer to the super class's meta class.
+    //  <ClassName>.gMetaClass The meta class structure itself.
+    //  ___vt<ClassName>       The VTable for the class <ClassName>.
+    //
+    // In this code I'm going to search for any symbols that
+    // ends in kSuperClassSuffix as this indicates this class is a conforming
+    // OSObject subclass and will need to be patched, and it also
+    // contains a pointer to the super class's meta class structure.
+    strbase = file->fStringBase;
+    sym = file->fLocalSyms;
+    for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
+       const char *symname;
+       const char *dot;
+       char classname[1024];
+       unsigned char n_type = sym->n_type & (N_TYPE | N_EXT);
+
+       // Check that the symbols is a global and that it has a name.
+       if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)
+       ||  !sym->n_un.n_strx)
+           continue;
+
+       // Only search from the last '.' in the symbol.
+       // but skip the leading '_' in all symbols first.
+       symname = strbase + sym->n_un.n_strx + 1;
+       dot = strrchr(symname, '.');
+       if (!dot || strcmp(dot, kSuperClassSuffix))
+           continue;
+
+       // Got a candidate so hand it over for class processing.
+       return_if(dot - symname >= (int) sizeof(classname),
+           false, ("Symbol %s is too long\n", symname));
+
+       bcopy(symname, classname, dot - symname);
+       classname[dot - symname] = '\0';
+       if (!recordClass(file, classname, sym))
+           return false;
+    }
+
+    return_if(!file->fClassList, false, ("Internal error, "
+             "getMetaClassGraph(%s) found no classes", file->fPath)); 
+
+    DEBUG_LOG(("Found %d classes in %x for %s\n",
+       DataGetLength(file->fClassList)/sizeof(void*),
+       file->fClassList, file->fPath));
+
+    return true;
+}
+
+static Boolean mergeOSObjectsForFile(const struct fileRecord *file)
+{
+    int i, nmerged;
+    Boolean foundDuplicates = false;
+
+DEBUG_LOG(("Merging file %s\n", file->fPath)); // @@@ gvdl:
+
+    if (!file->fClassList)
+       return true;
+
+    if (!sMergedFiles) {
+       sMergedFiles = DataCreate(0);
+       return_if(!sMergedFiles, false,
+           ("Unable to allocate memory metaclass list\n", file->fPath));
+    }
+
+    // Check to see if we have already merged this file
+    nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
+    for (i = 0; i < nmerged; i++) {
+       if (file == ((void **) DataGetPtr(sMergedFiles))[i])
+           return true;
+    }
+
+    if (!sMergeMetaClasses) {
+       sMergeMetaClasses = DataCreate(0);
+       return_if(!sMergeMetaClasses, false,
+           ("Unable to allocate memory metaclass list\n", file->fPath));
+    }
+    else {     /* perform a duplicate check */
+       int i, j, cnt1, cnt2;
+       struct metaClassRecord **list1, **list2;
+
+       list1 = (struct metaClassRecord **) DataGetPtr(file->fClassList);
+       cnt1  = DataGetLength(file->fClassList)  / sizeof(*list1);
+       list2 = (struct metaClassRecord **) DataGetPtr(sMergeMetaClasses);
+       cnt2  = DataGetLength(sMergeMetaClasses) / sizeof(*list2);
+
+       for (i = 0; i < cnt1; i++) {
+           for (j = 0; j < cnt2; j++) {
+               if (!strcmp(list1[i]->fClassName, list2[j]->fClassName)) {
+                   errprintf("duplicate class %s in %s & %s\n",
+                             list1[i]->fClassName,
+                             file->fPath, list2[j]->fFile->fPath);
+               }
+           }
+       }
+    }
+    if (foundDuplicates)
+       return false;
+
+    return_if(!DataAppendBytes(sMergedFiles, &file, sizeof(file)), false,
+       ("Unable to allocate memory to merge %s\n", file->fPath));
+
+    return_if(!DataAppendData(sMergeMetaClasses, file->fClassList), false,
+       ("Unable to allocate memory to merge %s\n", file->fPath));
+
+    if (file == sKernelFile)
+       sMergedKernel = true;
+
+    return true;
+}
+
+// Returns a pointer to the base of the section offset by the sections
+// base address.  The offset is so that we can add nlist::n_values directly
+// to this address and get a valid pointer in our memory.
+static unsigned char *
+getSectionForSymbol(const struct fileRecord *file, const struct nlist *symb,
+                   void ***endP)
+{
+    const struct section *section;
+    unsigned char sectind;
+    unsigned char *base;
+
+    sectind = symb->n_sect;    // Default to symbols section
+    if ((symb->n_type & N_TYPE) == N_ABS && file->fIsKernel) {
+       // Absolute symbol so we have to iterate over our sections
+       for (sectind = 1; sectind <= file->fNSects; sectind++) {
+           unsigned long start, end;
+
+           section = file->fSections[sectind - 1].fSection;
+           start = section->addr;
+           end   = start + section->size;
+           if (start <= symb->n_value && symb->n_value < end) {
+               // Found the relevant section
+               break;
+           }
+       }
+    }
+
+    // Is the vtable in a valid section?
+    return_if(sectind == NO_SECT || sectind > file->fNSects,
+       (unsigned char *) -1,
+       ("%s isn't a valid kext, bad section reference\n", file->fPath));
+
+    section = file->fSections[sectind - 1].fSection;
+
+    // for when we start walking the vtable so compute offset's now.
+    base = file->fMachO + section->offset;
+    *endP = (void **) (base + section->size);
+
+    return base - section->addr;       // return with addr offset
+}
+
+static Boolean resolveKernelVTable(struct metaClassRecord *metaClass)
+{
+    const struct fileRecord *file;
+    struct patchRecord *patchedVTable;
+    void **curEntry, **vtableEntries, **endSection;
+    unsigned char *sectionBase;
+    struct patchRecord *curPatch;
+    int classSize;
+
+    // Should never occur but it doesn't cost us anything to check.
+    if (metaClass->fPatchedVTable)
+       return true;
+
+DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName));      // @@@ gvdl:
+
+    // Do we have a valid vtable to patch?
+    return_if(!metaClass->fVTableSym,
+       false, ("Internal error - no class vtable symbol?\n"));
+
+    file = metaClass->fFile;
+
+    // If the metaClass we are being to ask is in the kernel then we
+    // need to do a quick scan to grab the fPatchList in a reliable format
+    // however we don't need to check the superclass in the kernel
+    // as the kernel vtables are always correct wrt themselves.
+    // Note this ends the superclass chain recursion.
+    return_if(!file->fIsKernel,
+       false, ("Internal error - resolveKernelVTable not kernel\n"));
+
+    if (file->fNoKernelExecutable) {
+       // Oh dear attempt to map the kernel's VM into my memory space
+       return_if(file->fNoKernelExecutable, false,
+           ("Internal error - fNoKernelExecutable not implemented yet\n"));
+    }
+
+    // We are going to need the base and the end
+    sectionBase = getSectionForSymbol(file, metaClass->fVTableSym, &endSection);
+    if (-1 == (long) sectionBase)
+       return false;
+
+    vtableEntries  = (void **) (sectionBase + metaClass->fVTableSym->n_value);
+    curEntry = vtableEntries + kVTablePreambleLen;
+    for (classSize = 0; curEntry < endSection && *curEntry; classSize++)
+       curEntry++;
+
+    return_if(*curEntry, false, ("Bad kernel image, short section\n"));
+
+    patchedVTable = (struct patchRecord *)
+       malloc((classSize + 1) * sizeof(struct patchRecord));
+    return_if(!patchedVTable, false, ("resolveKernelVTable - no memory\n"));
+
+    // Copy the vtable of this class into the patch table
+    curPatch = patchedVTable;
+    curEntry = vtableEntries + kVTablePreambleLen;
+    for (; *curEntry; curEntry++, curPatch++) {
+       curPatch->fSymbol = (struct nlist *) 
+           findSymbolByAddress(file, *curEntry);
+       curPatch->fType = kSymbolLocal;
+    }
+
+    // Tag the end of the patch vtable
+    curPatch->fSymbol = NULL;
+    metaClass->fPatchedVTable = patchedVTable;
+
+    return true;
+}
+
+// reloc->fPatch must contain a valid pointer on entry
+static struct nlist *
+getNewSymbol(struct fileRecord *file,
+            const struct relocRecord *reloc, const char *supername)
+{
+    unsigned int size, i, namelen;
+    struct nlist **sym;
+    struct nlist *msym;
+    const char *strbase;
+    struct relocation_info *rinfo;
+    long strx;
+
+    if (!file->fNewSymbols) {
+       file->fNewSymbols = DataCreate(0);
+       return_if(!file->fNewSymbols, NULL,
+           ("Unable to allocate new symbol table for %s\n", file->fPath));
+    }
+
+    // Make sure we have a string table as well for the new symbol
+    if (!file->fNewStrings) {
+       file->fNewStrings = DataCreate(0);
+       return_if(!file->fNewStrings, NULL,
+           ("Unable to allocate string table for %s\n", file->fPath));
+    }
+
+    rinfo = (struct relocation_info *) reloc->fRInfo;
+    size = DataGetLength(file->fNewSymbols) / sizeof(struct nlist *);
+    sym = (const struct nlist **) DataGetPtr(file->fNewSymbols);
+    // remember that the n_strx for new symbols names is negated
+    strbase = (const char *)
+               DataGetPtr(file->fNewStrings) - file->fSymtab->strsize;
+    for (i = 0; i < size; i++, sym++) {
+        const char *symname = strbase - (*sym)->n_un.n_strx;
+
+       if (!strcmp(symname, supername)) {
+           rinfo->r_symbolnum = i + file->fSymtab->nsyms;
+           file->fSymbolsDirty = true; 
+           return *sym;
+       }
+    }
+
+    // Assert that this is a vaild symbol.  I need this condition to be true
+    // for the later code to make non-zero.  So the first time through I'd 
+    // better make sure that it is 0.
+    return_if(reloc->fSymbol->n_sect, NULL,
+       ("Undefined symbol entry with non-zero section %s:%s\n",
+       file->fPath, symbolname(file, reloc->fSymbol)));
+
+    msym = (struct nlist *) malloc(sizeof(struct nlist));
+    return_if(!msym,
+       NULL, ("Unable to create symbol table entry for %s\n", file->fPath));
+
+    // If we are here we didn't find the symbol so create a new one now
+    if (!DataAppendBytes(file->fNewSymbols, &msym, sizeof(msym))) {
+       free(msym);
+       return_if(true,
+           NULL, ("Unable to grow symbol table for %s\n", file->fPath));
+    }
+
+    namelen = strlen(supername) + 1;
+    strx = DataGetLength(file->fNewStrings);
+    if (!DataAppendBytes(file->fNewStrings, supername, namelen)) {
+       free(msym);
+       DataAddLength(file->fNewSymbols, -sizeof(struct nlist)); // Undo harm
+       return_if(true, NULL,
+                ("Unable to grow string table for %s\n", file->fPath));
+    }
+
+    // Offset the string index by the original string table size
+    // and negate the address to indicate that this is a 'new' symbol
+    msym->n_un.n_strx = -(strx + file->fSymtab->strsize);
+    msym->n_type = (N_EXT | N_UNDF);
+    msym->n_sect = NO_SECT;
+    msym->n_desc = 0;
+    msym->n_value = 0;
+
+    // Mark the old symbol as being potentially deletable I can use the
+    // n_sect field as the input symbol must be of type N_UNDF which means
+    // that the n_sect field must be set to NO_SECT otherwise it is an
+    // in valid input file.
+    ((struct nlist *) reloc->fSymbol)->n_un.n_strx
+       = -reloc->fSymbol->n_un.n_strx;    
+    ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1;
+
+    rinfo->r_symbolnum = i + file->fSymtab->nsyms;
+    file->fSymbolsDirty = true; 
+    return msym;
+}
+
+static struct nlist *
+fixOldSymbol(struct fileRecord *file,
+            const struct relocRecord *reloc, const char *supername)
+{
+    unsigned int namelen;
+    struct nlist *sym = (struct nlist *) reloc->fSymbol;
+    const char *oldname = symbolname(file, sym);
+
+    // assert(sym->n_un.n_strx >= 0);
+
+    namelen = strlen(supername);
+    if (namelen < strlen(oldname)) {
+       // Overwrite old string in string table
+       strcpy((char *) oldname, supername);
+    }
+    else {
+       long strx;
+
+       // Make sure we have a string table as well for this symbol
+       if (!file->fNewStrings) {
+           file->fNewStrings = DataCreate(0);
+           return_if(!file->fNewStrings, NULL,
+               ("Unable to allocate string table for %s\n", file->fPath));
+       }
+
+       // Find the end of the fNewStrings data structure;
+       strx = DataGetLength(file->fNewStrings);
+       return_if(!DataAppendBytes(file->fNewStrings, supername, namelen + 1),
+           NULL, ("Unable to grow string table for %s\n", file->fPath));
+
+       // now add the current table size to the offset
+       sym->n_un.n_strx = strx + file->fSymtab->strsize;
+    }
+
+    // Mark the symbol as having been processed by negating it.
+    // Also note that we have dirtied the file and need to repair the
+    // symbol table.
+    sym->n_un.n_strx = -sym->n_un.n_strx;
+    file->fSymbolsDirty = true; 
+    return sym;
+}
+
+static enum patchState
+symbolCompare(const struct fileRecord *file,
+             const struct nlist *classsym,
+             const char *supername)
+{
+    const char *classname;
+    
+
+    // Check to see if the target function is locally defined
+    // if it is then we can assume this is a local vtable override
+    if ((classsym->n_type & N_TYPE) != N_UNDF)
+       return kSymbolLocal;
+
+    // Check to see if both symbols point to the same symbol name
+    // if so then we are still identical.
+    classname = symbolname(file, classsym);
+    if (!strcmp(classname, supername))
+       return kSymbolIdentical;
+
+    // Right now we know that the target's vtable entry is different from the
+    // superclass' vtable entry.  This means that we will have to apply a
+    // patch to the current entry, however before returning lets check to
+    // see if we have a _RESERVEDnnn field 'cause we can use this as a
+    // registration point that must align between vtables.
+    if (!strncmp(supername, kReservedPrefix, sizeof(kReservedPrefix) - 1))
+       return kSymbolMismatch;
+
+    // OK, we have a superclass difference where the superclass doesn't
+    // reference a pad function so assume that the superclass is correct.
+    if (!strncmp(classname, kReservedPrefix, sizeof(kReservedPrefix) - 1))
+       return kSymbolPadUpdate; 
+    else
+       return kSymbolSuperUpdate;
+}
+
+static Boolean patchVTable(struct metaClassRecord *metaClass)
+{
+    struct metaClassRecord *super = NULL;
+    struct fileRecord *file;
+    struct patchRecord *patchedVTable;
+    struct relocRecord **curReloc, **vtableRelocs, **endSection;
+    unsigned char *sectionBase;
+    int classSize;
+
+    // Should never occur but it doesn't cost us anything to check.
+    if (metaClass->fPatchedVTable)
+       return true;
+
+    // Do we have a valid vtable to patch?
+    return_if(!metaClass->fVTableSym,
+       false, ("Internal error - no class vtable symbol?\n"));
+
+    file = metaClass->fFile;
+
+    // If the metaClass we are being to ask is in the kernel then we
+    // need to do a quick scan to grab the fPatchList in a reliable format
+    // however we don't need to check the superclass in the kernel
+    // as the kernel vtables are always correct wrt themselves.
+    // Note this ends the superclass chain recursion.
+    return_if(file->fIsKernel,
+       false, ("Internal error - patchVTable shouldn't used for kernel\n"));
+
+    if (!metaClass->fSuperName)
+       return false;
+
+    // The class isn't in the kernel so make sure that the super class 
+    // is patched before patching ouselves.
+    super = getClass(sMergeMetaClasses, metaClass->fSuperName);
+    return_if(!super, false, ("Can't find superclass for %s : %s \n",
+       metaClass->fClassName, metaClass->fSuperName));
+
+    // Superclass recursion if necessary
+    if (!super->fPatchedVTable) {
+       Boolean res;
+
+       if (super->fFile->fIsKernel)
+           res = resolveKernelVTable(super);
+       else
+           res = patchVTable(super);
+       if (!res)
+           return false;
+    }
+
+DEBUG_LOG(("Patching %s\n", metaClass->fClassName));   // @@@ gvdl:
+
+    // We are going to need the base and the end
+
+    sectionBase = getSectionForSymbol(file,
+       metaClass->fVTableSym, (void ***) &endSection);
+    if (-1 == (long) sectionBase)
+       return false;
+
+    vtableRelocs  = (struct relocRecord **)
+                       (sectionBase + metaClass->fVTableSym->n_value);
+    curReloc = vtableRelocs + kVTablePreambleLen;
+    for (classSize = 0; curReloc < endSection && *curReloc; classSize++)
+       curReloc++;
+
+    return_if(*curReloc, false,
+       ("%s isn't a valid kext, short section\n", file->fPath));
+
+    patchedVTable = (struct patchRecord *)
+       malloc((classSize + 1) * sizeof(struct patchRecord));
+    return_if(!patchedVTable, false, ("patchedVTable - no memory\n"));
+
+    do {
+       struct patchRecord *curPatch;
+       struct nlist *symbol;
+
+       curPatch = patchedVTable;
+       curReloc = vtableRelocs + kVTablePreambleLen;
+
+       // Grab the super table patches if necessary
+       // Can't be patching a kernel table as we don't walk super
+       // class chains in the kernel symbol space.
+       if (super && super->fPatchedVTable) {
+           const struct patchRecord *spp;
+
+           spp = super->fPatchedVTable;
+
+           for ( ; spp->fSymbol; curReloc++, spp++, curPatch++) {
+               const char *supername =
+                   symbolname(super->fFile, spp->fSymbol);
+
+                symbol = (struct nlist *) (*curReloc)->fSymbol;
+
+               curPatch->fType = symbolCompare(file, symbol, supername);
+               switch (curPatch->fType) {
+               case kSymbolIdentical:
+               case kSymbolLocal:
+                   break;
+    
+               case kSymbolSuperUpdate:
+                   symbol = getNewSymbol(file, (*curReloc), supername);
+                   break;
+
+               case kSymbolPadUpdate:
+                   symbol = fixOldSymbol(file, (*curReloc), supername);
+                   break;
+
+               case kSymbolMismatch:
+                   errprintf("%s is not compatible with its %s superclass, "
+                             "broken superclass?\n",
+                             metaClass->fClassName, super->fClassName);
+                   goto abortPatch;
+
+               default:
+                   errprintf("Internal error - unknown patch type\n");
+                   goto abortPatch;
+               }
+               if (symbol) {
+                   curPatch->fSymbol = symbol;
+                   (*curReloc)->fSymbol = symbol;
+               }
+               else
+                   goto abortPatch;
+           }
+       }
+
+       // Copy the remainder of this class' vtable into the patch table
+       for (; *curReloc; curReloc++, curPatch++) {
+           // Local reloc symbols
+           curPatch->fType = kSymbolLocal;
+           curPatch->fSymbol = (struct nlist *) (*curReloc)->fSymbol;
+       }
+
+       // Tag the end of the patch vtable
+       curPatch->fSymbol = NULL;
+
+       metaClass->fPatchedVTable = patchedVTable;
+       return true;
+    } while(0);
+
+abortPatch:
+    if (patchedVTable)
+       free(patchedVTable);
+
+    return false;
+}
+
+static Boolean growImage(struct fileRecord *file, vm_size_t delta)
+{
+#if !KERNEL
+    file->fMachOSize += delta;
+    return (file->fMachO + file->fMachOSize <= file->fPadEnd);
+#else /* KERNEL */
+    vm_address_t startMachO, endMachO, endMap;
+    vm_offset_t newMachO;
+    vm_size_t newsize;
+    unsigned long i, nsect, nclass = 0;
+    struct metaClassRecord **classes = NULL;
+    struct sectionRecord *section;
+    kern_return_t ret;
+
+    startMachO = (vm_address_t) file->fMachO;
+    endMachO = startMachO + file->fMachOSize + delta;
+    endMap   = (vm_address_t) file->fMap + file->fMapSize;
+
+    // Do we have room in the current mapped image
+    if (endMachO < round_page(endMap)) {
+       file->fMachOSize += delta;
+       return true;
+    }
+
+    newsize = endMachO - startMachO;
+    if (newsize < round_page(file->fMapSize)) {
+       // We have room in the map if we shift the macho image within the
+       // current map.  We will have to patch up pointers into the object.
+       newMachO = (vm_offset_t) file->fMap;
+       bcopy((char *) startMachO, (char *) newMachO, file->fMachOSize);
+    }
+    else if (file->fIsKmem) {
+       // kmem_alloced mapping so we can try a kmem_realloc
+       ret = kmem_realloc(kernel_map,
+                         (vm_address_t) file->fMap,
+                         (vm_size_t) file->fMapSize,
+                         &newMachO,
+                         newsize);
+       if (KERN_SUCCESS != ret)
+           return false;
+
+       // If the mapping didn't move then just return
+       if ((vm_address_t) file->fMap == newMachO) {
+           file->fMachOSize = file->fMapSize = newsize;
+           return true;
+       }
+
+       // We have relocated the kmem image so we are going to have to
+       // move all of the pointers into the image around.
+    }
+    else {
+       // The image doesn't have room for us and I can't kmem_realloc
+       // then I just have to bite the bullet and copy the object code
+       // into a bigger memory segment
+       ret = kmem_alloc(kernel_map, &newMachO, newsize);
+       
+       if (KERN_SUCCESS != ret)
+           return false;
+       bcopy((char *) startMachO, (void *) newMachO, file->fMachOSize);
+       file->fIsKmem = true;
+    }
+
+
+    file->fMap = file->fMachO = (unsigned char *) newMachO;
+    file->fMapSize = newsize;
+    file->fMachOSize += delta; // Increment the image size
+
+    // If we are here then we have shifted the object image in memory
+    // I really should change all of my pointers into the image to machO offsets
+    // but I have run out of time.  So I'm going to very quickly go over the
+    // cached data structures and add adjustments to the addresses that are
+    // affected.  I wonder how long it will take me to get them all.
+    //
+    // For every pointer into the MachO I need to add an adjustment satisfying
+    // the following simultanous equations
+    // addr_old = macho_old + fixed_offset
+    // addr_new = macho_new + fixed_offset     therefore:
+    // addr_new = addr_old + (macho_new - macho_old)
+#define REBASE(addr, delta)    ( ((vm_address_t) (addr)) += (delta) )
+    delta = newMachO - startMachO;
+
+    // Rebase the cached in object 'struct symtab_command' pointer
+    REBASE(file->fSymtab, delta);
+
+    // Rebase the cached in object 'struct nlist' pointer for all symbols
+    REBASE(file->fSymbolBase, delta);
+
+    // Rebase the cached in object 'struct nlist' pointer for local symbols
+    REBASE(file->fLocalSyms, delta);
+
+    // Rebase the cached in object 'char' pointer for the string table
+    REBASE(file->fStringBase, delta);
+
+    // Ok now we have to go over all of the relocs one last time
+    // to clean up the pad updates which had their string index negated
+    // to indicate that we have finished with them.
+    section = file->fSections;
+    for (i = 0, nsect = file->fNSects; i < nsect; i++, section++)
+       REBASE(section->fSection, delta);
+
+    // We only ever grow images that contain class lists so dont bother
+    // the check if file->fClassList is non-zero 'cause it can't be
+    // assert(file->fClassList);
+    nclass = DataGetLength(file->fClassList)
+          / sizeof(struct metaClassRecord *);
+    classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
+    for (i = 0; i < nclass; i++) {
+       struct patchRecord *patch;
+
+       for (patch = classes[i]->fPatchedVTable; patch->fSymbol; patch++) {
+           vm_address_t symAddr = (vm_address_t) patch->fSymbol;
+           if (symAddr >= startMachO && symAddr < endMachO)
+               REBASE(patch->fSymbol, delta);
+       }
+    }
+
+
+#undef REBASE
+
+    return true;
+
+#endif /* KERNEL */
+}
+
+static Boolean
+prepareFileForLink(struct fileRecord *file)
+{
+    unsigned long i, last, numnewsyms, newsymsize, newstrsize;
+    struct sectionRecord *section;
+    struct nlist **symp, *sym;
+
+    // If we didn't even do a pseudo 'relocate' and dirty the image
+    // then we can just return now.
+    if (!file->fImageDirty)
+       return true;
+
+DEBUG_LOG(("Linking 2 %s\n", file->fPath));    // @@@ gvdl:
+
+    // We have to go over all of the relocs to repair the damage
+    // that we have done to the image when we did our 'relocation'
+    section = file->fSections;
+    for (i = 0, last = file->fNSects; i < last; i++, section++) {
+       unsigned char *sectionBase;
+       struct relocRecord *rec;
+       unsigned long j, nreloc;
+
+       if (section->fRelocCache) {
+           sectionBase = file->fMachO + section->fSection->offset;
+           nreloc = section->fSection->nreloc;
+           rec = (struct relocRecord *) DataGetPtr(section->fRelocCache);
+    
+           // We will need to repair the reloc list 
+           for (j = 0; j < nreloc; j++, rec++) {
+               void **entry;
+               struct nlist *sym;
+    
+               // Repair Damage to object image
+               entry = (void **) (sectionBase + rec->fRInfo->r_address);
+               *entry = rec->fValue;
+
+               // Check if the symbol that this relocation entry points
+               // to is marked as erasable 
+               sym = (struct nlist *) rec->fSymbol;
+               if (sym && sym->n_type == (N_EXT | N_UNDF)
+               &&  sym->n_sect == (unsigned char) -1) {
+                   // clear mark now
+                   sym->n_un.n_strx = -sym->n_un.n_strx;
+                   sym->n_sect = NO_SECT;
+               }
+           }
+
+           // Clean up the fRelocCache we don't need it any more.
+           DataRelease(section->fRelocCache);
+           section->fRelocCache = 0;
+       }
+    }
+    file->fImageDirty = false; // Image is clean
+
+    // If we didn't dirty the symbol table then just return
+    if (!file->fSymbolsDirty)
+       return true;
+
+    // calculate total file size increase and check against padding
+    numnewsyms  = (file->fNewSymbols)? DataGetLength(file->fNewSymbols) : 0;
+    numnewsyms /= sizeof(struct nlist *);
+    newsymsize  = numnewsyms * sizeof(struct nlist);
+    newstrsize  = (file->fNewStrings)? DataGetLength(file->fNewStrings) : 0;
+    newstrsize  = (newstrsize + 3) & ~3;       // Round to nearest word
+    
+    return_if(!growImage(file, newsymsize + newstrsize),
+       false, ("Unable to patch the extension, no memory\n", file->fPath));
+
+    // Push out the new symbol table if necessary
+    if (numnewsyms) {
+       caddr_t base;
+
+       // Move the string table out of the way of the grown symbol table
+       // Don't forget the '\0' from end of string table.
+       base = (caddr_t) file->fStringBase;
+       bcopy(base, base + newsymsize, file->fSymtab->strsize);
+       file->fStringBase     += newsymsize;
+       file->fSymtab->stroff += newsymsize;
+
+       // Now append the new symbols to the symbol table.
+       base = (caddr_t) file->fSymbolBase
+            + file->fSymtab->nsyms * sizeof(struct nlist);
+       symp = (struct nlist **) DataGetPtr(file->fNewSymbols);
+       for (i = 0; i < numnewsyms; i++, base += sizeof(struct nlist), symp++)
+           bcopy(*symp, base, sizeof(struct nlist));
+       file->fSymtab->nsyms  += numnewsyms;
+
+       DataRelease(file->fNewSymbols);
+       file->fNewSymbols = 0;
+    }
+
+    // Push out the new string table if necessary
+    if (newstrsize) {
+       caddr_t base = (caddr_t) file->fStringBase + file->fSymtab->strsize;
+       unsigned long actuallen = DataGetLength(file->fNewStrings);
+
+       // Set the last word in string table to zero before copying data
+       *((unsigned long *) ((char *) base + newstrsize - 4)) = 0;
+
+       // Now append the new strings to the end of the file
+       bcopy((caddr_t) DataGetPtr(file->fNewStrings), base, actuallen);
+
+       file->fSymtab->strsize += newstrsize;
+
+       DataRelease(file->fNewStrings);
+       file->fNewStrings = 0;
+    }
+
+    // Repair the symbol table string index values
+    // I used negative strx's to indicate symbol has been processed
+    sym = file->fSymbolBase;
+    for (i = 0, last = file->fSymtab->nsyms; i < last; i++, sym++) {
+       if (sym->n_un.n_strx < 0) {
+           if ( sym->n_type != (N_EXT | N_UNDF)
+           || (unsigned char) -1 != sym->n_sect)
+               sym->n_un.n_strx = -sym->n_un.n_strx;
+           else {
+               // This symbol isn't being used by any vtable's reloc so
+               // convert it into an N_ABS style of symbol, remove the
+               // external bit and null out the symbol name.
+               bzero(sym, sizeof(*sym));
+               sym->n_type = N_ABS;    /* type flag, see below */
+           }
+       }
+    }
+    file->fSymbolsDirty = false;
+
+    return true;
+}
+
+Boolean
+#if KERNEL
+kld_file_map(const char *pathName,
+            unsigned char *map,
+            size_t mapSize,
+            Boolean isKmem)
+#else
+kld_file_map(const char *pathName)
+#endif /* KERNEL */
+{
+    struct fileRecord file, *fp = 0;
+
+    // Already done no need to repeat
+    fp = getFile(pathName);
+    if (fp)
+       return true;
+
+    bzero(&file, sizeof(file));
+    file.fPath = pathName;
+
+#if KERNEL
+    file.fMap = map;
+    file.fMapSize = mapSize;
+    file.fIsKmem = isKmem;
+#else
+    if (!mapObjectFile(&file))
+       return false;
+#endif /* KERNEL */
+
+    do {
+       const struct machOMapping {
+           struct mach_header h;
+           struct load_command c[1];
+       } *machO;
+       const struct load_command *cmd;
+       const struct nlist *sym;
+       unsigned int i, firstlocal, nsyms;
+       unsigned long strsize;
+       const char *strbase;
+       Boolean foundOSObject;
+
+       if (!findBestArch(&file))
+           break;
+    
+       machO = (const struct machOMapping *) file.fMachO;
+       if (file.fMachOSize < machO->h.sizeofcmds)
+           break;
+
+       // If the file type is MH_EXECUTE then this must be a kernel
+       // as all Kernel extensions must be of type MH_OBJECT
+       for (i = 0, cmd = &machO->c[0]; i < machO->h.ncmds; i++) {
+           if (cmd->cmd == LC_SEGMENT) {
+               return_if(!parseSegments(&file, (struct segment_command *) cmd),
+                   false, ("%s isn't a valid mach-o, bad segment\n",
+                           file.fPath));
+           }
+           else if (cmd->cmd == LC_SYMTAB)
+               file.fSymtab = (struct symtab_command *) cmd;
+    
+           cmd = (struct load_command *) ((UInt8 *) cmd + cmd->cmdsize);
+       }
+       break_if(!file.fSymtab,
+           ("%s isn't a valid mach-o, no symbols\n", file.fPath));
+
+       // we found a link edit segment so recompute the bases
+       if (file.fSymbolBase) {
+           struct segment_command *link =
+               (struct segment_command *) file.fSymbolBase;
+
+           file.fSymbolBase = (struct nlist *)
+               (link->vmaddr + (file.fSymtab->symoff - link->fileoff));
+           file.fStringBase = (char *)
+               (link->vmaddr + (file.fSymtab->stroff - link->fileoff));
+           break_if( ( (caddr_t) file.fStringBase + file.fSymtab->strsize
+                     > (caddr_t) link->vmaddr + link->vmsize ),
+               ("%s isn't a valid mach-o le, bad symbols\n", file.fPath));
+       }
+       else {
+           file.fSymbolBase = (struct nlist *)
+               (file.fMachO + file.fSymtab->symoff); 
+           file.fStringBase = (char *)
+               (file.fMachO + file.fSymtab->stroff); 
+           break_if( ( file.fSymtab->stroff + file.fSymtab->strsize
+                     > file.fMachOSize ),
+               ("%s isn't a valid mach-o, bad symbols\n", file.fPath));
+       }
+
+       // If this file the kernel and do we have an executable image
+       file.fIsKernel = (MH_EXECUTE == machO->h.filetype);
+       file.fNoKernelExecutable = (vm_page_size == file.fSymtab->symoff)
+                               && (file.fSections[0].fSection->size == 0);
+
+       // Search for the first non-stab symbol in table
+       strsize = file.fSymtab->strsize;
+       strbase = file.fStringBase;
+       sym = file.fSymbolBase;
+       firstlocal = 0;
+       foundOSObject = false;
+       for (i = 0, nsyms = file.fSymtab->nsyms; i < nsyms; i++, sym++) {
+           if ((unsigned long) sym->n_un.n_strx > strsize)
+               break;
+
+           // Find the first exported symbol
+           if ( !file.fLocalSyms && (sym->n_type & N_EXT) ) {
+               file.fLocalSyms = sym;
+               firstlocal = i;
+           }
+
+           // Find the a OSObject based subclass by searching for symbols
+           // that have a suffix of '.superClass'
+           if (!foundOSObject
+           && ((sym->n_type & (N_TYPE | N_EXT)) == (N_SECT | N_EXT)
+            || (sym->n_type & (N_TYPE | N_EXT)) == (N_ABS | N_EXT))
+           &&  sym->n_un.n_strx) {
+               const char *dot;
+
+               // Only search from the last '.' in the symbol.
+               // but skip the leading '_' in all symbols first.
+               dot = strrchr(strbase + sym->n_un.n_strx + 1, '.');
+               if (dot && !strcmp(dot, kSuperClassSuffix))
+                   foundOSObject = true;
+           }
+
+           // Find the last local symbol
+           if ( !file.fNLocal && sym->n_type == (N_EXT | N_UNDF) )
+               file.fNLocal = i - firstlocal;
+
+       }
+       break_if(i < nsyms,
+           ("%s isn't a valid mach-o, bad symbol strings\n", file.fPath));
+
+       break_if(!file.fLocalSyms, ("%s has no symbols?\n", file.fPath));
+
+       // If we don't have any undefined symbols then all symbols
+       // must be local so just compute it now if necessary.
+       if ( !file.fNLocal )
+           file.fNLocal = i - firstlocal;
+
+       fp = addFile(&file);
+       if (!fp)
+           break;
+
+       if (foundOSObject && !getMetaClassGraph(fp))
+           break;
+
+       if (file.fIsKernel)
+           sKernelFile = fp;
+#if KERNEL
+       if (!sKernelFile) {
+           extern struct mach_header _mh_execute_header;
+           extern struct segment_command *getsegbyname(char *seg_name);
+    
+           struct segment_command *sg;
+           size_t kernelSize;
+           Boolean ret;
+
+           sg = (struct segment_command *) getsegbyname(kLinkEditSegName); 
+           break_if(!sg, ("Can't find kernel link edit segment\n"));
+    
+           kernelSize = sg->vmaddr + sg->vmsize - (size_t) &_mh_execute_header;
+           ret = kld_file_map(kld_basefile_name,
+               (unsigned char *) &_mh_execute_header, kernelSize,
+               /* isKmem */ false);
+           break_if(!ret, ("kld can't map kernel file"));
+       }
+#endif /* KERNEL */
+
+       return true;
+    } while(0);
+
+    removeFile(&file);
+
+    return false;
+}
+
+void *kld_file_getaddr(const char *pathName, long *size)
+{
+    struct fileRecord *file = getFile(pathName);
+
+    if (!file)
+       return 0;
+
+    if (size)
+       *size = file->fMachOSize;
+
+    return file->fMachO;
+}
+
+void *kld_file_lookupsymbol(const char *pathName, const char *symname)
+{
+    struct fileRecord *file = getFile(pathName);
+    const struct nlist *sym;
+    const struct section *section;
+    unsigned char *sectionBase;
+    unsigned char sectind;
+
+    return_if(!file,
+       NULL, ("Unknown file %s\n", pathName));
+
+    sym = findSymbolByName(file, symname);
+
+    // May be a non-extern symbol so look for it there
+    if (!sym) {
+       const char *strbase;
+       unsigned int i, nsyms;
+
+       sym = file->fSymbolBase;
+       strbase = file->fStringBase;
+       for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
+           if ( (sym->n_type & N_EXT) ) {
+               sym = 0;
+               break;  // Terminate search when we hit an extern
+           }
+           if ( (sym->n_type & N_STAB) )
+               continue;
+           if ( !strcmp(symname, strbase + sym->n_un.n_strx) )
+               break;
+       }
+    }
+
+    return_if(!sym,
+       NULL, ("Unknown symbol %s in %s\n", symname, pathName));
+
+    // Is the vtable in a valid section?
+    sectind = sym->n_sect;
+    return_if(sectind == NO_SECT || sectind > file->fNSects, NULL,
+       ("Malformed object file, invalid section reference for %s in %s\n",
+           symname, pathName));
+
+    section = file->fSections[sectind - 1].fSection;
+    sectionBase = file->fMachO + section->offset - section->addr;
+
+    return (void *) (sectionBase + sym->n_value);
+}
+
+Boolean kld_file_merge_OSObjects(const char *pathName)
+{
+    struct fileRecord *file = getFile(pathName);
+
+    return_if(!file,
+       false, ("Internal error - unable to find file %s\n", pathName));
+
+    return mergeOSObjectsForFile(file);
+}
+
+Boolean kld_file_patch_OSObjects(const char *pathName)
+{
+    struct fileRecord *file = getFile(pathName);
+    struct metaClassRecord **classes;
+    unsigned long i, last;
+
+    return_if(!file,
+       false, ("Internal error - unable to find file %s\n", pathName));
+
+DEBUG_LOG(("Patch file %s\n", pathName));      // @@@ gvdl:
+
+    // If we don't have any classes we can return now.
+    if (!file->fClassList)
+       return true;
+
+    // If we haven't alread merged the kernel then do it now
+    if (!sMergedKernel && sKernelFile)
+       mergeOSObjectsForFile(sKernelFile);
+    return_if(!sMergedKernel, false, ("Internal error no kernel?\n"));
+
+    if (!mergeOSObjectsForFile(file))
+       return false;
+
+    // Patch all of the classes in this executable
+    last = DataGetLength(file->fClassList) / sizeof(void *);
+    classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
+    for (i = 0; i < last; i++) {
+       if (!patchVTable(classes[i]))
+           return false;
+    }
+
+    return true;
+}
+
+Boolean kld_file_prepare_for_link()
+{
+    if (sMergedFiles) {
+       unsigned long i, nmerged = 0;
+       struct fileRecord **files;
+    
+       // Check to see if we have already merged this file
+       nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
+       files = (struct fileRecord **) DataGetPtr(sMergedFiles);
+       for (i = 0; i < nmerged; i++) {
+           if (!prepareFileForLink(files[i]))
+               return false;
+       }
+    }
+
+    // Clear down the meta class table and merged file lists
+    DataRelease(sMergeMetaClasses);
+    DataRelease(sMergedFiles);
+    sMergedFiles = sMergeMetaClasses = NULL;
+    sMergedKernel = false;
+
+    return true;
+}
+
+void kld_file_cleanup_all_resources()
+{
+    unsigned long i, nfiles;
+
+#if KERNEL     // @@@ gvdl:
+    // Debugger("kld_file_cleanup_all_resources");
+#endif
+
+    if (!sFilesTable || !(nfiles = DataGetLength(sFilesTable)))
+       return; // Nothing to do just return now
+
+    nfiles /= sizeof(struct fileRecord *);
+    for (i = 0; i < nfiles; i++)
+       removeFile(((void **) DataGetPtr(sFilesTable))[i]);
+
+    // Don't really have to clean up anything more as the whole
+    // malloc engine is going to be released and I couldn't be bothered.
+}
+
+#if !KERNEL
+Boolean kld_file_debug_dump(const char *pathName, const char *outName)
+{
+    const struct fileRecord *file = getFile(pathName);
+    int fd;
+    Boolean ret = false;
+
+    return_if(!file, false, ("Unknown file %s for dumping\n", pathName));
+
+    fd = open(outName, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+    return_if(-1 == fd, false, ("Can't create output file %s - %s(%d)\n",
+       outName, strerror(errno), errno));
+
+    do {
+       break_if(-1 == write(fd, file->fMachO, file->fMachOSize),
+           ("Can't dump output file %s - %s(%d)\n", 
+               outName, strerror(errno), errno));
+       ret = true;
+    } while(0);
+
+    close(fd);
+
+    return ret;
+}
+#endif /* !KERNEL */
+
diff --git a/kmodload.tproj/kld_patch.h b/kmodload.tproj/kld_patch.h
new file mode 100644 (file)
index 0000000..b0e6058
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License').  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * History:
+ *  2001-05-30         gvdl    Initial implementation of the vtable patcher.
+ */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#if KERNEL
+extern Boolean kld_file_map(const char *pathName,
+                           unsigned char *map, size_t mapSize,
+                           Boolean isKmem);
+#else
+extern Boolean kld_file_map(const char *pathName);
+
+extern void *
+    kld_file_lookupsymbol(const char *pathName, const char *symbolname);
+
+Boolean kld_file_debug_dump(const char *pathName, const char *outName);
+#endif /* KERNEL */
+
+extern void *kld_file_getaddr(const char *pathName, long *size);
+
+extern Boolean kld_file_merge_OSObjects(const char *pathName);
+
+extern Boolean kld_file_patch_OSObjects(const char *pathName);
+
+extern Boolean kld_file_prepare_for_link();
+
+extern void kld_file_cleanup_all_resources();
+
+__END_DECLS
index 497694452b6ecc837dbbe3863a65967cbcf24c12..4108282c5675788b0dc25f8a3638aae7b6b67be4 100644 (file)
  * Original code from:
  *     "kldload.c,v 1.5 1998/07/06 06:58:32 charnier Exp"
  */
-
 #ifndef lint
 static const char rcsid[] =
-       "$Id: kmodload.c,v 1.7 2001/02/05 19:53:16 lindak Exp $";
+       "$Id: kmodload.c,v 1.10 2001/08/02 20:57:01 lindak Exp $";
 #endif /* not lint */
 
 #include <stdlib.h>
@@ -63,6 +62,8 @@ static const char rcsid[] =
 #include <unistd.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
+
 #include <paths.h>
 
 #include <mach/mach.h>
@@ -71,12 +72,19 @@ static const char rcsid[] =
 #include <mach-o/kld.h>
 #include <mach-o/fat.h>
 
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "kld_patch.h"
+
 #define KMOD_ERROR_USAGE       1
 #define KMOD_ERROR_PERMS       2
 #define KMOD_ERROR_LOADING     3               
 #define KMOD_ERROR_INTERNAL    4
 #define KMOD_ERROR_ALREADY     5
 
+#define kKMOD_INFO_SYMBOLNAME "_kmod_info"
+#define kKmodsymsName "kmodsyms"
+
 static mach_port_t kernel_port;
 static mach_port_t kernel_priv_port;
 
@@ -96,26 +104,31 @@ static char *progname = "program name?";
 static int kmodsyms = 0;
 static int link_addrs_set = 0;
 static int verbose = 0;
-#define v_printf       if (verbose) printf
+
+static char *debugdumpfile = NULL;
 
 // must not be static; kld library calls
-void                           kld_error_vprintf(const char *format, va_list ap);
+extern void                    kld_error_vprintf(const char *format, va_list ap);
+static void                    e_printf(const char *fmt, ...);
+static void                    v_printf(const char *fmt, ...);
 
 static void                    machwarn(int error, const char *message);
 static void                    macherr(int error, const char *message);
 
-static unsigned long           linkedit_address(unsigned long size,
+static unsigned long   linkedit_address(unsigned long size,
                                                 unsigned long headers_size);
-static void                    cleanup_kernel_memory();
-static void                    link_base(const char *base,
+static void                    abort_load(int exitcode, const char *fmt, ...);
+static void                    map_and_patch(const char *base,
+                                                                 const char **library_paths,
+                                                                 const char *module);
+static void                    link_base(const char *base,
                                          const char **dependency_paths,
                                          const vm_address_t *dependency_addrs);
 static void                    clear_globals(void);
-static void                    map_module(char *module_path, char **object_addr,
-                                          long *object_size, kmod_info_t **kinfo);
-static struct mach_header      *link_module(const char *filename, 
+static kmod_info_t *map_module(const char *filename);
+static struct mach_header *link_module(const char *filename, 
                                             const char *output);
-static vm_address_t            patch_module(struct mach_header *mach_header);
+static vm_address_t            update_kmod_info(struct mach_header *mach_header);
 static kmod_t                  load_module(struct mach_header *mach_header,
                                            vm_address_t info);
 static void                    set_module_dependencies(kmod_t id);
@@ -125,11 +138,13 @@ static void
 usage(void)
 {
        if (kmodsyms) {
-               fprintf(stderr, "usage: kmodsyms [-v] [-k kernelfile] [-d dependencyfile] -o symbolfile modulefile\n");
-               fprintf(stderr, "       kmodsyms [-v]  -k kernelfile  [-d dependencyfile@address] -o symbolfile modulefile@address\n");
+               fprintf(stderr, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] -o symbolfile modulefile\n", progname);
+               fprintf(stderr, "       %s [-v]  -k kernelfile  [-d dependencyfile@address] -o symbolfile modulefile@address\n",
+                       progname);
        } else {
-               fprintf(stderr, "usage: kmodload [-v] [-k kernelfile] [-d dependencyfile] [-o symbolfile] modulefile\n");
+               fprintf(stderr, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] [-o symbolfile] modulefile\n", progname);
        }
+       fflush(stderr);
        exit(KMOD_ERROR_USAGE);
 }
 
@@ -148,30 +163,28 @@ main(int argc, char** argv)
 
        char * module_path = "";
        vm_address_t module_info = 0;
-       char *module_addr = 0;
-       long module_size = 0;
        vm_address_t module_faked_address = 0;
        kmod_t module_id = 0;
        kmod_info_t *file_kinfo;
 
-       if ((progname = rindex(argv[0], '/')) == NULL)
+       if ((progname = strrchr(argv[0], '/')) == NULL)
                progname = argv[0];
        else
                ++progname;
 
-       kmodsyms = !strcmp(progname, "kmodsyms");
+       kmodsyms = !strcmp(progname, kKmodsymsName);
 
        // XXX things to add:
        //  -p data string to send as outofband data on start
        //  -P data file to send as outofband data on start
 
-       while ((c = getopt(argc, argv, "d:o:k:v")) != -1)
+       while ((c = getopt(argc, argv, "D:d:o:k:v")) != -1)
                switch (c) {
                case 'd':
                        dependencies[dependency_count] = optarg;
                        if (kmodsyms) {
                                char *address;
-                               if ((address = rindex(optarg, '@'))) {
+                               if ((address = strrchr(optarg, '@'))) {
                                        *address++ = 0;
                                        loaded_addresses[dependency_count] = strtoul(address, NULL, 0);
                                        link_addrs_set++;
@@ -180,8 +193,8 @@ main(int argc, char** argv)
                                }
                        }
                        if (++dependency_count == MAX_DEPENDANCIES) {
-                               fprintf(stderr, "%s: internal error, dependency count overflow.\n", progname); 
-                               exit(KMOD_ERROR_INTERNAL);
+                               abort_load(KMOD_ERROR_INTERNAL, 
+                                       "internal error, dependency count overflow."); 
                        }
                        break;
                case 'o':
@@ -194,6 +207,9 @@ main(int argc, char** argv)
                case 'v':
                        verbose = 1;
                        break;
+               case 'D':
+                       debugdumpfile = optarg;
+                       break;
                default:
                        usage();
                }
@@ -213,7 +229,7 @@ main(int argc, char** argv)
                if (!gdbfile) usage();
 
                // check for @address
-               if ((address = rindex(module_path, '@'))) {
+               if ((address = strrchr(module_path, '@'))) {
                        *address++ = 0;
                        module_faked_address = strtoul(address, NULL, 0);
                        link_addrs_set++;
@@ -231,8 +247,8 @@ main(int argc, char** argv)
                }
        }
 
-       // map module and then check if it has been loaded
-       map_module(module_path, &module_addr, &module_size, &file_kinfo);
+       // map the module if possible, map_module will fail if there is a problem
+       file_kinfo = map_module(module_path);
 
        if (!link_addrs_set) {
                kmod_info_t *k;
@@ -240,9 +256,9 @@ main(int argc, char** argv)
                // we only need the kernel port if we need to lookup loaded kmods
                r = task_for_pid(mach_task_self(), 0, &kernel_port);
                machwarn(r, "unable to get kernel task port");
-               if (r) {
-                       fprintf(stderr, "%s: You must be running as root to load/check modules in the kernel.\n", progname);
-                       exit(KMOD_ERROR_PERMS);
+               if (KERN_SUCCESS != r) {
+                       abort_load(KMOD_ERROR_PERMS,
+                               "You must be running as root to load modules in the kernel.");
                }
 
                //get loaded modules
@@ -254,8 +270,8 @@ main(int argc, char** argv)
                while (k) {
                        if (!strcmp(k->name, file_kinfo->name)) {
                                if (!kmodsyms) {
-                                       fprintf(stderr, "%s: the module named '%s' is already loaded.\n", progname, k->name); 
-                                       exit(KMOD_ERROR_ALREADY);
+                                       abort_load(KMOD_ERROR_ALREADY,
+                                               "the module named '%s' is already loaded.", k->name); 
                                } else {
                                        module_faked_address = k->address;
                                }
@@ -265,14 +281,20 @@ main(int argc, char** argv)
                }
 
                if (kmodsyms && !module_faked_address) {
-                       fprintf(stderr, "%s: the module named '%s' has not been loaded.\n", progname, file_kinfo->name); 
-                       exit(KMOD_ERROR_USAGE);
+                       abort_load(KMOD_ERROR_USAGE,
+                               "the module named '%s' has not been loaded.", file_kinfo->name);
                }
                
                //XXX it would be nice to be able to verify this is the correct kernel
                //XXX by comparing the kernel version strings (once we have them)
        }
 
+       map_and_patch(kernel, dependencies, module_path);
+       if (debugdumpfile) kld_file_debug_dump(module_path, debugdumpfile);
+
+       // Tell the kld linker where to get its load address from
+       kld_address_func(linkedit_address);
+
        // link the kernel along with any dependencies
        link_base(kernel, dependencies, loaded_addresses);
 
@@ -280,13 +302,13 @@ main(int argc, char** argv)
            faked_kernel_load_address = module_faked_address;
 
            if (!faked_kernel_load_address) {
-               fprintf(stderr, "%s: internal error, fell thru without setting module load address.\n", progname); 
-               exit(KMOD_ERROR_INTERNAL);
+                       abort_load(KMOD_ERROR_INTERNAL,
+                         "internal error, fell thru without setting module load address.");
            }
        }
 
        rld_header = link_module(module_path, gdbfile);
-       module_info = patch_module(rld_header);
+       module_info = update_kmod_info(rld_header);
 
        if (kmodsyms) return 0;
 
@@ -303,123 +325,62 @@ main(int argc, char** argv)
 static void
 machwarn(int error, const char *message)
 {
-       if (error == KERN_SUCCESS) return;
-       fprintf(stderr, "%s: %s: %s\n", progname, message, mach_error_string(error));
+       if (KERN_SUCCESS != error)
+               e_printf("%s: %s", message, mach_error_string(error));
 }
 
 static void
 macherr(int error, const char *message)
 {
-       if (error == KERN_SUCCESS) return;
-       fprintf(stderr, "%s: %s: %s\n", progname, message, mach_error_string(error));
+       if (KERN_SUCCESS != error)
+               abort_load(KMOD_ERROR_INTERNAL,
+                       "%s: %s", message, mach_error_string(error));
+}
+
+static kmod_info_t *map_module(const char *filename)
+{
+       kmod_info_t *file_kinfo;
 
-       cleanup_kernel_memory();
+       if (!kld_file_map(filename))
+               exit(KMOD_ERROR_LOADING);
 
-       exit(KMOD_ERROR_INTERNAL);
+       file_kinfo = kld_file_lookupsymbol(filename, kKMOD_INFO_SYMBOLNAME);
+       if (!file_kinfo) {
+               abort_load(KMOD_ERROR_USAGE,
+                       "%s is not a valid kernel module.", filename);
+       }
+       
+       return file_kinfo;
 }
 
 static void
-map_module(char *module_path, char **object_addr, long *object_size, kmod_info_t **kinfo)
+map_and_patch(const char *base, const char **library_paths, const char *module)
 {
-       int fd;
-       struct stat stat_buf;
-       struct mach_header *mh;
-       char *p;
-
-       struct nlist nl[] = {
-               { "_kmod_info" },
-               { "" },
-       };
-
-       if((fd = open(module_path, O_RDONLY)) == -1){
-           fprintf(stderr, "%s: Can't open: %s\n", progname, module_path);
-           exit(KMOD_ERROR_USAGE);
-       }
-       if (nlist(module_path, nl)) {
-               fprintf(stderr, "%s: %s is not a valid kernel module.\n", progname, module_path);
-               exit(KMOD_ERROR_USAGE);
-       }
-       if(fstat(fd, &stat_buf) == -1){
-           fprintf(stderr, "%s: Can't stat file: %s\n", progname, module_path);
-           exit(KMOD_ERROR_PERMS);
-       }
-       *object_size = stat_buf.st_size;
-       if(map_fd(fd, 0, (vm_offset_t *)object_addr, TRUE, *object_size) != KERN_SUCCESS){
-           fprintf(stderr, "%s: Can't map file: %s\n", progname, module_path);
-           exit(KMOD_ERROR_INTERNAL);
-       }
-       close(fd);
-
-       if (NXSwapBigLongToHost(*((long *)*object_addr)) == FAT_MAGIC) {
-               struct host_basic_info hbi;
-               struct fat_header *fh;
-               struct fat_arch *fat_archs, *fap;
-               unsigned i, nfat_arch;
-
-               /* Get our host info */
-               i = HOST_BASIC_INFO_COUNT;
-               if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)(&hbi), &i) != KERN_SUCCESS) {
-                   fprintf(stderr, "%s: Can't get host's basic info\n", progname);
-                   exit(KMOD_ERROR_INTERNAL);
-               }
-
-               // get number of architectures
-               fh = (struct fat_header *)*object_addr;
-               nfat_arch = NXSwapBigLongToHost(fh->nfat_arch);
-
-               // find beginning of fat_arch struct
-               fat_archs = (struct fat_arch *)((char *)fh + sizeof(struct fat_header));
-
-               /*
-                * Convert archs to host byte ordering (a constraint of
-                * cpusubtype_getbestarch()
-                */
-               for (i = 0; i < nfat_arch; i++) {
-                       fat_archs[i].cputype =
-                               NXSwapBigLongToHost(fat_archs[i].cputype);
-                       fat_archs[i].cpusubtype =
-                             NXSwapBigLongToHost(fat_archs[i].cpusubtype);
-                       fat_archs[i].offset =
-                               NXSwapBigLongToHost(fat_archs[i].offset);
-                       fat_archs[i].size =
-                               NXSwapBigLongToHost(fat_archs[i].size);
-                       fat_archs[i].align =
-                               NXSwapBigLongToHost(fat_archs[i].align);
-               }
-
-// this code was lifted from Darwin/Libraries/NeXT/libc/gen.subproj/nlist.c
-// when cpusubtype_getbestarch exists this code should also be changed.
-#define        CPUSUBTYPE_SUPPORT      0
-
-#if    CPUSUBTYPE_SUPPORT
-               fap = cpusubtype_getbestarch(hbi.cpu_type, hbi.cpu_subtype,
-                                            fat_archs, nfat_arch);
-#else  CPUSUBTYPE_SUPPORT
-#warning       Use the cpusubtype functions!!!
-               fap = NULL;
-               for (i = 0; i < nfat_arch; i++) {
-                       if (fat_archs[i].cputype == hbi.cpu_type) {
-                               fap = &fat_archs[i];
-                               break;
-                       }
-               }
-#endif CPUSUBTYPE_SUPPORT
-               if (!fap) {
-                   fprintf(stderr, "%s: could not find the correct architecture in %s.\n", progname, module_path);
-                   exit(KMOD_ERROR_USAGE);
+       if (!kld_file_map(base))
+               exit(KMOD_ERROR_INTERNAL);
+       if (!kld_file_merge_OSObjects(base))
+               abort_load(KMOD_ERROR_LOADING, NULL);
+
+       if (*library_paths) {
+               char **library;
+               for (library = library_paths; *library; library++) {
+                       map_module(*library);
+                       if (!kld_file_patch_OSObjects(*library))
+                               abort_load(KMOD_ERROR_LOADING, NULL);
                }
-               
-               *object_addr += fap->offset;
-               *object_size = fap->size;
        }
 
-       mh = (struct mach_header *)*object_addr;
-       if (*((long *)mh) != MH_MAGIC) {
-           fprintf(stderr, "%s: invalid file format for file: %s\n", progname, module_path);
-           exit(KMOD_ERROR_USAGE);
-       }
-       p = *object_addr + sizeof(struct mach_header) + mh->sizeofcmds + nl->n_value;
-       *kinfo = (kmod_info_t *)p;
+       // Patch the vtables of the object module we are about to load
+       // The module has already been mapped in the main() routine as part
+       // of validation
+       if (!kld_file_patch_OSObjects(module))
+               abort_load(KMOD_ERROR_LOADING, NULL);
+
+       // During the patch up process the mapped images were modified
+       // to avoid having to allocate more data than necessary.
+       // Now we have to give the patcher a chance to clean up after itself.
+       if (!kld_file_prepare_for_link())
+               abort_load(KMOD_ERROR_LOADING, NULL);
 }
 
 static void
@@ -428,25 +389,34 @@ link_base(const char *base,
          const vm_address_t *dependency_addrs)
 {
        struct mach_header *rld_header;
+       char *base_addr;
+       long base_size;
        int ok;
 
-       ok = kld_load_basefile(base);
+       // Get the address and size of the base, usually the kernel
+       base_addr = kld_file_getaddr(base, &base_size);
+       if (!base_addr)
+               exit(KMOD_ERROR_INTERNAL);      // Error reported by kld library.
+
+       ok = kld_load_basefile_from_memory(base, base_addr, base_size);
        fflush(stdout);
-       if (!ok) {
-               fprintf(stderr, "%s: kld_load_basefile(%s) failed.\n", progname, base); 
-               exit(KMOD_ERROR_LOADING);
-       }
+       if (!ok)
+               abort_load(KMOD_ERROR_LOADING, "kld_load_basefile(%s) failed.", base); 
 
        if (*dependency_paths) {
                char **dependency = dependency_paths;
                const vm_address_t *load_addr = dependency_addrs;
 
                while (*dependency) {
-                       char *object_addr;
-                       long object_size;
                        kmod_info_t *file_kinfo;
 
-                       map_module(*dependency, &object_addr, &object_size, &file_kinfo);
+                       // Find the kmod_info structure in the image.
+                       file_kinfo =
+                               kld_file_lookupsymbol(*dependency, kKMOD_INFO_SYMBOLNAME);
+                       if (!file_kinfo) {
+                               abort_load(KMOD_ERROR_USAGE, 
+                                       "%s is not a valid kernel module.", *dependency);
+                       }
 
                        // find the address that this dependency is loaded at
                        if (kmodsyms && *load_addr) {
@@ -461,11 +431,10 @@ link_base(const char *base,
                                while (k) {
                                        if (!strcmp(k->name, file_kinfo->name)) {
                                                if (strcmp(k->version, file_kinfo->version)) {
-                                                       fprintf(stderr, "%s: loaded kernel module '%s' version differs.\n",
-                                                               progname, *dependency);
-                                                       fprintf(stderr, "%s: loaded version '%s', file version '%s'.\n",
-                                                               progname, k->version, file_kinfo->version);
-                                                       exit(KMOD_ERROR_LOADING);
+                                                       e_printf("loaded kernel module '%s' version differs.", *dependency);
+                                                       abort_load(KMOD_ERROR_LOADING, 
+                                                               "loaded version '%s', file version '%s'.",
+                                                               k->version, file_kinfo->version);
                                                }
                                                found_it++;
                                                break;
@@ -473,17 +442,15 @@ link_base(const char *base,
                                        k = (k->next) ? (k + 1) : 0;
                                }
                                if (!found_it) {
-                                       fprintf(stderr, "%s: kernel module '%s' is not loaded.\n", 
-                                               progname, *dependency);
-                                       exit(KMOD_ERROR_USAGE);
+                                       abort_load(KMOD_ERROR_USAGE, 
+                                               "kernel module '%s' is not loaded.", *dependency);
                                }       
                        
-                                tmp = malloc(sizeof(kmod_info_t));
-                               if (!tmp) {
-                                       fprintf(stderr, "%s: no memory.\n", progname);
-                                       exit(KMOD_ERROR_LOADING);
-                               }       
-                                *tmp = *k;
+                               tmp = malloc(sizeof(kmod_info_t));
+                               if (!tmp)
+                                       abort_load(KMOD_ERROR_LOADING, "no memory.");
+
+                               *tmp = *k;
                                tmp->next = module_dependencies;
                                module_dependencies = tmp;
 
@@ -492,7 +459,7 @@ link_base(const char *base,
 
                        rld_header = link_module(*dependency, 0);
 
-                       (void)patch_module(rld_header);
+                       (void) update_kmod_info(rld_header);
 
                        dependency++; load_addr++;
                }
@@ -526,47 +493,28 @@ linkedit_address(unsigned long size, unsigned long headers_size)
 
     if (faked_kernel_load_address) {
         kernel_load_address = faked_kernel_load_address + kernel_hdr_pad;
-        v_printf("%s: Returning fake load address of 0x%8x\n",
-            progname, kernel_load_address);
+        v_printf("Returning fake load address of 0x%8x", kernel_load_address);
         return kernel_load_address;
     }
     if (kmodsyms) {
-        fprintf(stderr, "%s: internal error, almost tried to alloc kernel memory.\n", progname); 
-        exit(KMOD_ERROR_INTERNAL);
+               abort_load(KMOD_ERROR_INTERNAL, 
+                       "internal error, almost tried to alloc kernel memory."); 
     }
 
     r = vm_allocate(kernel_port, &kernel_alloc_address, 
         kernel_alloc_size, TRUE);
     macherr(r, "unable to allocate kernel memory");
 
-    v_printf("%s: allocated %ld bytes in kernel space at 0x%8x\n",
-        progname, kernel_alloc_size, kernel_alloc_address);
+    v_printf("allocated %ld bytes in kernel space at 0x%8x",
+        kernel_alloc_size, kernel_alloc_address);
 
     kernel_load_address = kernel_alloc_address + kernel_hdr_pad;
 
-    v_printf("%s: Returning load address of 0x%x\n",
-        progname, kernel_load_address);
+    v_printf("Returning load address of 0x%x", kernel_load_address);
 
     return kernel_load_address;
 }
 
-static void
-cleanup_kernel_memory()
-{
-       int r;
-
-       if (faked_kernel_load_address) return;  
-
-       if (kernel_alloc_address || kernel_alloc_size) {        
-               v_printf("%s: freeing %ld bytes in kernel space at 0x%x\n",
-                        progname, kernel_alloc_size, kernel_alloc_address);
-               r = vm_deallocate(kernel_port, kernel_alloc_address, kernel_alloc_size);
-                clear_globals();
-               kernel_load_address = kernel_load_size = 0;
-               machwarn(r, "unable to cleanup kernel memory");
-       }
-}
-
 static void
 clear_globals(void)
 {
@@ -584,51 +532,50 @@ static struct mach_header *
 link_module(const char *filename, const char *output)
 {
        struct mach_header *rld_header;
+       char *object_addr;
+       long object_size;
        int ok;
 
-       kld_address_func(linkedit_address);
+       // Get the address of the thined MachO image.
+       object_addr = kld_file_getaddr(filename, &object_size);
+       if (!object_addr)
+               abort_load(KMOD_ERROR_LOADING, NULL);
 
-       ok = kld_load(&rld_header, filename, output);
+       ok = kld_load_from_memory(&rld_header, filename,
+                                                               object_addr, object_size, output);
        fflush(stdout);
-       if (!ok) {
-               fprintf(stderr, "%s: kld_load() failed.\n", progname);
-               cleanup_kernel_memory();
-               exit(KMOD_ERROR_LOADING);
-       }
+       if (!ok)
+               abort_load(KMOD_ERROR_LOADING, "kld_load() failed.");
 
        return rld_header;
 }
 
+// Update the kmod_info_t structure in the image to be laoded
+// Side effect of removing the kKMOD_INFO_SYMBOLNAME from the 
+// loaded symbol name space, otherwise we would have a duplicate
+// defined symbol failure
 vm_address_t
-patch_module(struct mach_header *mach_header)
+update_kmod_info(struct mach_header *mach_header)
 {
-       char * symbol = "_kmod_info";
+       char * symbol = kKMOD_INFO_SYMBOLNAME;
        kmod_info_t *info;
        unsigned long value;
        int ok;
 
-       ok = kld_lookup(symbol, &value);
-       fflush(stdout);
-       if (!ok) {
-               fprintf(stderr, "%s: kld_lookup(%s) failed.\n", progname, symbol);
-               cleanup_kernel_memory();
-               exit(KMOD_ERROR_LOADING);
-       }
+       ok = kld_lookup(symbol, &value); fflush(stdout);
+       if (!ok)
+               abort_load(KMOD_ERROR_LOADING, "kld_lookup(%s) failed.", symbol);
 
-       ok = kld_forget_symbol(symbol);
-       fflush(stdout);
-       if (!ok) {
-               fprintf(stderr, "%s: kld_forget_symbol(%s) failed.\n", progname, symbol);
-               cleanup_kernel_memory();
-               exit(KMOD_ERROR_INTERNAL);
-       }
+       ok = kld_forget_symbol(symbol); fflush(stdout);
+       if (!ok)
+               abort_load(KMOD_ERROR_LOADING, "kld_forget_symbol(%s) failed.", symbol);
 
        /* Get the kmod info by translating from the kernel address at value.
         */
        info = (kmod_info_t *)(value - (unsigned long)kernel_load_address + (unsigned long)mach_header);
-       v_printf("%s: kmod name: %s\n", progname, info->name);
-       v_printf("%s: kmod start @ 0x%x\n", progname, (vm_address_t)info->start);
-       v_printf("%s: kmod stop  @ 0x%x\n", progname, (vm_address_t)info->stop);
+       v_printf("kmod name: %s", info->name);
+       v_printf("kmod start @ 0x%x", (vm_address_t)info->start);
+       v_printf("kmod stop  @ 0x%x", (vm_address_t)info->stop);
 
        /* Record link info in kmod info struct, rounding the hdr_size to fit
         * the adjustment that was made.
@@ -637,16 +584,10 @@ patch_module(struct mach_header *mach_header)
        info->size = kernel_alloc_size;
        info->hdr_size = page_round(kernel_hdr_size);
 
-       if (!info->start) {
-               fprintf(stderr, "%s: invalid start address?\n", progname);
-               cleanup_kernel_memory();
-               exit(KMOD_ERROR_LOADING);
-       }
-       if (!info->stop) {
-               fprintf(stderr, "%s: invalid stop address?\n", progname);
-               cleanup_kernel_memory();
-               exit(KMOD_ERROR_LOADING);
-       }
+       if (!info->start)
+               abort_load(KMOD_ERROR_LOADING, "invalid start address?");
+       else if (!info->stop)
+               abort_load(KMOD_ERROR_LOADING, "invalid stop address?");
 
        return (vm_address_t)value;
 }
@@ -680,8 +621,8 @@ load_module(struct mach_header *mach_header, vm_address_t info)
     r = kmod_create(kernel_priv_port, info, &id);
     macherr(r, "unable to register module with kernel");
 
-    v_printf("%s: kmod id %d successfully created at 0x%x size %ld.\n", 
-        progname, id, kernel_alloc_address, kernel_alloc_size);
+    v_printf("kmod id %d successfully created at 0x%x size %ld.\n", 
+        id, kernel_alloc_address, kernel_alloc_size);
 
     // FIXME: make sure this happens even on failure
 
@@ -705,10 +646,9 @@ set_module_dependencies(kmod_t id)
                        clear_globals();
                        r = kmod_destroy(kernel_priv_port, id);
                        macherr(r, "kmod_destroy failed");
-                       exit(KMOD_ERROR_INTERNAL);
                }
 
-               v_printf("%s: kmod id %d reference count was sucessfully incremented.\n", progname, module->id);
+               v_printf("kmod id %d reference count was sucessfully incremented.", module->id);
 
                module = module->next;
        }
@@ -727,14 +667,64 @@ start_module(kmod_t id)
                clear_globals();
                kmod_destroy(kernel_priv_port, id);
                macherr(r, "kmod_destroy failed");
-               exit(KMOD_ERROR_INTERNAL);
        }
 
-       v_printf("%s: kmod id %d successfully started.\n", progname, id);
+       v_printf("kmod id %d successfully started.", id);
 }
 
-void
-kld_error_vprintf(const char *format, va_list ap){
-    vfprintf(stderr, format, ap);
-    return;
+static void e_printf(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       kld_error_vprintf(fmt, ap);
+       va_end(ap);
+}
+
+static void v_printf(const char *fmt, ...)
+{
+       va_list ap;
+       char msg[1024];
+
+       if (!verbose) return;
+
+       va_start(ap, fmt);
+       vsnprintf(msg, sizeof(msg), fmt, ap);
+       va_end(ap);
+
+       printf("%s: %s\n", progname, msg);
+}
+
+static void abort_load(int exitcode, const char *fmt, ...)
+{
+       if (fmt) {
+               va_list ap;
+       
+               va_start(ap, fmt);
+               kld_error_vprintf(fmt, ap);
+               va_end(ap);
+       }
+
+       if (!faked_kernel_load_address
+       && (kernel_alloc_address || kernel_alloc_size)) {       
+               int r;
+
+               v_printf("freeing %ld bytes in kernel space at 0x%x",
+                                       kernel_alloc_size, kernel_alloc_address);
+               r = vm_deallocate(kernel_port, kernel_alloc_address, kernel_alloc_size);
+               machwarn(r, "unable to cleanup kernel memory");
+       }
+
+       exit(exitcode);
+}
+
+__private_extern__ void
+kld_error_vprintf(const char *fmt, va_list ap)
+{
+    char msg[1024];
+
+    vsnprintf(msg, sizeof(msg), fmt, ap);
+    fprintf(stderr, "%s: %s", progname, msg);
+
+    fflush(stderr);
 }
index 16ef9e743d4e13245257002d85d7940320590f59..fc2cf35c93cde70583d297b1ea7c63776b6c844a 100644 (file)
@@ -62,8 +62,8 @@
 #include <mach/mach_types.h>
 #include <mach/message.h>
 #include <mach/mach_syscalls.h>
-#include <mach/clock.h>
 #include <mach/clock_types.h>
+#include <mach/mach_time.h>
 
 #include <libkern/OSTypes.h>
 
@@ -145,15 +145,18 @@ struct ct {
         char name[32];
 } codes_tab[MAX_ENTRIES];
 
+/* If NUMPARMS changes from the kernel, then PATHLENGTH will also reflect the change */
+#define NUMPARMS 23
+#define PATHLENGTH (NUMPARMS*sizeof(long))
 
 struct th_info {
         int  thread;
         int  type;
         int  child_thread;
-        int  vfslookup;
         int  arg1;
         double stime;
-        char pathname[32];
+        long *pathptr;
+        char pathname[PATHLENGTH + 1];
 };
 
 #define MAX_THREADS 512
@@ -202,40 +205,6 @@ static kern_return_t       set_standard_policy(void);
 int decrementer_val = 0;     /* Value used to reset decrementer */
 int set_remove_flag = 1;     /* By default, remove trace buffer */
 
-/* raw read of the timebase register */
-void clock_get_uptime( register AbsoluteTime *result)
-{
-#ifdef __ppc__
-
-        register UInt32  hic;
-        do {
-         asm volatile("  mftbu %0" : "=r" (result->hi));
-         asm volatile("  mftb  %0" : "=r" (result->lo));
-         asm volatile("  mftbu %0" : "=r" (hic));
-        } while (hic != result->hi);
-
-#else
-        result->lo = 0;
-        result->hi = 0;
-#endif /* __ppc__ */
-
-}
-
-typedef unsigned long long  abstime_scalar_t;
-
-#define AbsoluteTime_to_scalar(x)   \
-                        (*(abstime_scalar_t *)(x))
-
-/* t1 += t2 */
-#define ADD_ABSOLUTETIME(t1, t2)                \
-       (AbsoluteTime_to_scalar(t1) +=              \
-                               AbsoluteTime_to_scalar(t2))
-
-/* t1 -= t2 */
-#define SUB_ABSOLUTETIME(t1, t2)                \
-       (AbsoluteTime_to_scalar(t1) -=              \
-                               AbsoluteTime_to_scalar(t2))
-
 int
 quit(s)
 char *s;
@@ -717,10 +686,10 @@ int  argc;
 char *argv[];
 {
         mach_timespec_t remain;
-       unsigned long long start, stop;
-       AbsoluteTime timestamp1;
-       AbsoluteTime timestamp2;
-       AbsoluteTime adeadline, adelay;
+       uint64_t start, stop;
+       uint64_t timestamp1;
+       uint64_t timestamp2;
+       uint64_t adeadline, adelay;
        double fdelay;
        int      elapsed_usecs;
        double   nanosecs_to_sleep;
@@ -825,7 +794,7 @@ char *argv[];
 
        nanosecs_to_sleep = (double)(num_of_usecs_to_sleep * 1000);
        fdelay = nanosecs_to_sleep * (divisor /1000);
-       AbsoluteTime_to_scalar(&adelay) = (abstime_scalar_t)fdelay;
+       adelay = (uint64_t)fdelay;
 
        init_code_file();
 
@@ -890,17 +859,14 @@ char *argv[];
                        refresh_time = curr_time + 1;
                }
 
-               clock_get_uptime(&timestamp1);
-               adeadline = timestamp1;
-               ADD_ABSOLUTETIME(&adeadline, &adelay);
+               timestamp1 = mach_absolute_time();
+               adeadline = timestamp1 + adelay;
                mk_wait_until(adeadline);
-               clock_get_uptime(&timestamp2);
+               timestamp2 = mach_absolute_time();
 
-               start = (((unsigned long long)timestamp1.hi) << 32) |
-                         (unsigned long long)((unsigned int)(timestamp1.lo));
+               start = timestamp1;
 
-               stop = (((unsigned long long)timestamp2.hi) << 32) |
-                        (unsigned long long)((unsigned int)(timestamp2.lo));
+               stop = timestamp2;
 
                elapsed_usecs = (int)(((double)(stop - start)) / divisor);
 
@@ -945,23 +911,17 @@ char *argv[];
                        gotSIGWINCH = 0;
                }
        }
-       }
-
+}
 
 
 void getdivisor()
 {
+  mach_timebase_info_data_t info;
 
-    unsigned int delta;
-    unsigned int abs_to_ns_num;
-    unsigned int abs_to_ns_denom;
-    unsigned int proc_to_abs_num;
-    unsigned int proc_to_abs_denom;
+  (void) mach_timebase_info (&info);
 
-    (void)MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
-                      &proc_to_abs_num,  &proc_to_abs_denom);
+  divisor = ( (double)info.denom / (double)info.numer) * 1000;
 
-    divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000;
 }
 
 /* This is the realtime band */
@@ -1097,8 +1057,13 @@ void create_map_entry(int thread, char *command)
 #endif
     map->valid = 1;
     map->thread = thread;
-    (void)strncpy (map->command, command, sizeof(map->command));
-    map->command[sizeof(map->command)-1] = '\0';
+    /*
+      The trace entry that returns the command name will hold
+      at most, MAXCOMLEN chars, and in that case, is not
+      guaranteed to be null terminated.
+    */
+    (void)strncpy (map->command, command, MAXCOMLEN);
+    map->command[MAXCOMLEN] = '\0';
 }
 
 
@@ -1168,10 +1133,10 @@ char *find_code(type)
 }
 
 
-void sample_sc(long long start, long long stop)
+void sample_sc(uint64_t start, uint64_t stop)
 {
        kd_buf   *kd, *last_mach_sched, *last_decrementer_kd, *start_kd, *end_of_sample;
-       unsigned long long now;
+       uint64_t now;
        int count;
        int first_entry = 1;
        char   command[32];
@@ -1211,7 +1176,7 @@ void sample_sc(long long start, long long stop)
                for (i = 0; i < cur_max; i++) {
                        th_state[i].thread = 0;
                        th_state[i].type = -1;
-                       th_state[i].vfslookup = 0;
+                       th_state[i].pathptr = (long *)0;
                        th_state[i].pathname[0] = 0;
                }
                cur_max = 0;
@@ -1237,6 +1202,7 @@ void sample_sc(long long start, long long stop)
        for (kd = (kd_buf *)my_buffer; kd < end_of_sample; kd++) {
                int debugid, thread, cpunum;
                int type, clen, mode;
+               int len;
                char *p;
                long *sargptr;
                double i_latency;
@@ -1263,8 +1229,8 @@ void sample_sc(long long start, long long stop)
                if (type == DECR_TRAP)
                        i_latency = handle_decrementer(kd);
 
-               now = (((unsigned long long)kd->timestamp.tv_sec) << 32) |
-                       (unsigned long long)((unsigned int)(kd->timestamp.tv_nsec));
+               now = (((uint64_t)kd->timestamp.tv_sec) << 32) |
+                       (uint64_t)((unsigned int)(kd->timestamp.tv_nsec));
 
                timestamp = ((double)now) / divisor;
 
@@ -1432,32 +1398,48 @@ void sample_sc(long long start, long long stop)
 
                            ti->thread = thread;
                            ti->type   = -1;
-                           ti->vfslookup = 0;
+                           ti->pathptr = (long *)0;
                            ti->child_thread = 0;
                    }
-                   if (ti->vfslookup == 0) {
-                           ti->vfslookup = 1;
+                   if (!ti->pathptr) {
                            ti->arg1 = kd->arg1;
-                           memset(&ti->pathname[0], 0, 32);
+                           memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
                            sargptr = (long *)&ti->pathname[0];
                                
                            *sargptr++ = kd->arg2;
                            *sargptr++ = kd->arg3;
                            *sargptr++ = kd->arg4;
-
-                   } else if (ti->vfslookup == 1) {
-                           ti->vfslookup = 0;
-         
-                           sargptr = (long *)&ti->pathname[12];
-                           *sargptr++ = kd->arg1;
-                           *sargptr++ = kd->arg2;
-                           *sargptr++ = kd->arg3;
-                           *sargptr++ = kd->arg4;
+                           ti->pathptr = sargptr;
+
+                   } else {
+                           sargptr = ti->pathptr;
+
+                           /*
+                               We don't want to overrun our pathname buffer if the
+                               kernel sends us more VFS_LOOKUP entries than we can
+                               handle.
+                           */
+
+                            if ((long *)sargptr < (long *)&ti->pathname[PATHLENGTH])
+                             {
+                               *sargptr++ = kd->arg1;
+                               *sargptr++ = kd->arg2;
+                               *sargptr++ = kd->arg3;
+                               *sargptr++ = kd->arg4;
+                               ti->pathptr = sargptr;
+
+                               /* print the tail end of the pathname */
+                               len = strlen(ti->pathname);
+                               if (len > 28)
+                                 len -= 28;
+                               else
+                                 len = 0;
                            
-                           if (log_fp) {
-                             fprintf(log_fp, "%9.1f %8.1f\t\t%-28.28s %-28s    %-8x   %-8x  %d  %s\n",
-                                   timestamp - start_bias, delta, "VFS_LOOKUP", 
-                                   ti->pathname, ti->arg1, thread, cpunum, command);
+                               if (log_fp) {
+                                 fprintf(log_fp, "%9.1f %8.1f\t\t%-28.28s %-28s    %-8x   %-8x  %d  %s\n",
+                                         timestamp - start_bias, delta, "VFS_LOOKUP", 
+                                         &ti->pathname[len], ti->arg1, thread, cpunum, command);
+                               }
                            }
                    }
                    last_timestamp = timestamp;
@@ -1554,7 +1536,8 @@ enter_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, double
        else
               ti->type = -1;
        ti->stime  = timestamp;
-       ti->vfslookup = 0;
+       ti->pathptr = (long *)0;
+
 #if 0
        if (print_info && fp)
               fprintf(fp, "cur_max = %d,  ti = %x,  type = %x,  thread = %x\n", cur_max, ti, ti->type, ti->thread);
@@ -1607,7 +1590,7 @@ exit_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, double t
 
                       ti->thread = thread;
                       ti->child_thread = 0;
-                      ti->vfslookup = 0;
+                      ti->pathptr = (long *)0;
               }
        }
        ti->type = -1;
@@ -1654,7 +1637,7 @@ check_for_thread_update(int thread, int type, kd_buf *kd)
 
                    ti->thread = thread;
                    ti->type   = -1;
-                   ti->vfslookup = 0;
+                   ti->pathptr = (long *)0;
            }
            ti->child_thread = kd->arg1;
            return (1);
@@ -1684,7 +1667,8 @@ kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, d
        double timestamp, last_timestamp, delta, start_bias;
        int thread, cpunum;
        int debugid, type, clen;
-       unsigned long long now;
+       int len;
+       uint64_t now;
        struct th_info *ti;
        long  *sargptr;
        char  *p;
@@ -1721,8 +1705,8 @@ kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, d
        if (kd_stop >= end_of_sample)
                kd_stop = end_of_sample - 1;
 
-       now = (((unsigned long long)kd_start->timestamp.tv_sec) << 32) |
-               (unsigned long long)((unsigned int)(kd_start->timestamp.tv_nsec));
+       now = (((uint64_t)kd_start->timestamp.tv_sec) << 32) |
+               (uint64_t)((unsigned int)(kd_start->timestamp.tv_nsec));
        timestamp = ((double)now) / divisor;
 
        for (kd = kd_start; kd <= kd_stop; kd++) {
@@ -1741,8 +1725,8 @@ kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, d
                debugid = kd->debugid;
                type    = kd->debugid & DBG_FUNC_MASK;
 
-               now = (((unsigned long long)kd->timestamp.tv_sec) << 32) |
-                       (unsigned long long)((unsigned int)(kd->timestamp.tv_nsec));
+               now = (((uint64_t)kd->timestamp.tv_sec) << 32) |
+                       (uint64_t)((unsigned int)(kd->timestamp.tv_nsec));
 
                timestamp = ((double)now) / divisor;
 
@@ -1838,31 +1822,46 @@ kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, d
 
                            ti->thread = thread;
                            ti->type   = -1;
-                           ti->vfslookup = 0;
+                           ti->pathptr = (long *)0;
                            ti->child_thread = 0;
                    }
-                   if (ti->vfslookup == 0) {
-                           ti->vfslookup = 1;
+                   if (!ti->pathptr) {
                            ti->arg1 = kd->arg1;
-                           memset(&ti->pathname[0], 0, 32);
+                           memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
                            sargptr = (long *)&ti->pathname[0];
                                
                            *sargptr++ = kd->arg2;
                            *sargptr++ = kd->arg3;
                            *sargptr++ = kd->arg4;
-
-                   } else if (ti->vfslookup == 1) {
-                           ti->vfslookup = 0;
-         
-                           sargptr = (long *)&ti->pathname[12];
-                           *sargptr++ = kd->arg1;
-                           *sargptr++ = kd->arg2;
-                           *sargptr++ = kd->arg3;
-                           *sargptr++ = kd->arg4;
+                           ti->pathptr = sargptr;
+
+                   } else {
+                           sargptr = ti->pathptr;
+
+                           /*
+                               We don't want to overrun our pathname buffer if the
+                               kernel sends us more VFS_LOOKUP entries than we can
+                               handle.
+                           */
+
+                            if ((long *)sargptr < (long *)&ti->pathname[PATHLENGTH])
+                             {
+                               *sargptr++ = kd->arg1;
+                               *sargptr++ = kd->arg2;
+                               *sargptr++ = kd->arg3;
+                               *sargptr++ = kd->arg4;
+
+                               /* print the tail end of the pathname */
+                               len = strlen(ti->pathname);
+                               if (len > 28)
+                                 len -= 28;
+                               else
+                                 len = 0;
                            
-                           fprintf(log_fp, "%9.1f %8.1f\t\t%-28.28s %-28s    %-8x   %-8x  %d  %s\n",
-                                   timestamp - start_bias, delta, "VFS_LOOKUP", 
-                                   ti->pathname, ti->arg1, thread, cpunum, command);
+                               fprintf(log_fp, "%9.1f %8.1f\t\t%-28.28s %-28s    %-8x   %-8x  %d  %s\n",
+                                       timestamp - start_bias, delta, "VFS_LOOKUP", 
+                                       &ti->pathname[len], ti->arg1, thread, cpunum, command);
+                             }
                    }
                    last_timestamp = timestamp;
                    break;
index 9a4897781da75e653fecf9efca09ea5ae046e1aa..cbfd71987f5afac2b8fa17eeb9f124b7bd3587a8 100644 (file)
@@ -364,6 +364,7 @@ main(argc, argv)
 
        (void)chown(ttyn, pwd->pw_uid,
            (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+       (void)chmod(ttyn, 0620);
        (void)setgid(pwd->pw_gid);
 
        initgroups(username, pwd->pw_gid);
index aed70c009be810ec662b724e12aa559c6aa8af48..debd28386e879432edc1be2d90d3a81f1563e6e7 100644 (file)
@@ -26,7 +26,7 @@ DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-FRAMEWORKS = -framework IOKit
+FRAMEWORKS = -framework CoreFoundation -framework IOKit
 
 
 NEXTSTEP_BUILD_OUTPUT_DIR = /$(USER)/BUILD
index 25536c72bd9c043a0f04a329d722988cff759fd5..3184bf46def79102b37dc23e17ea008ffbdcbffb 100644 (file)
@@ -2,7 +2,7 @@
     DYNAMIC_CODE_GEN = YES; 
     FILESTABLE = {
         BUNDLES = (); 
-        FRAMEWORKS = (IOKit.framework); 
+        FRAMEWORKS = (CoreFoundation.framework, IOKit.framework); 
         H_FILES = (); 
         LIBS = (); 
         OTHER_LINKED = (nvram.c); 
index 86ed4916c223aafc05510f8158d3cc48836e9602..5198d9aeadbba17d4bda465472d4a51f951a5070 100644 (file)
@@ -56,7 +56,7 @@ cc -I. -DKERNEL_PRIVATE -O -o sc_usage sc_usage.c
 
 #include <sys/sysctl.h>
 #include <errno.h>
-#import <mach/clock_types.h>
+#include <mach/mach_time.h>
 #include <err.h>
 
 
@@ -89,6 +89,9 @@ long   start_time = 0;
 #define MAX_NESTED  8
 #define MAX_FAULTS  5
 
+/* If NUMPARMS from kernel changes, it will be reflected in PATHLENGTH as well */
+#define NUMPARMS 23
+#define PATHLENGTH (NUMPARMS*sizeof(long))
 
 char *state_name[] = {
         "Dont Know",
@@ -104,12 +107,6 @@ char *state_name[] = {
 #define WAITING     3
 #define PREEMPTED   4
 
-typedef struct {
-        natural_t hi;
-        natural_t lo;
-} AbsoluteTime;
-
-
 struct entry {
         int  sc_state;
         int  type;
@@ -125,7 +122,8 @@ struct th_info {
         int  depth;
         int  vfslookup;
         int  curpri;
-        char pathname[32];
+        long *pathptr;
+        char pathname[PATHLENGTH + 1];
         struct entry th_entry[MAX_NESTED];
 };
 
@@ -266,29 +264,6 @@ void sigwinch()
                newLINES = 1;
 }
 
-
-/* raw read of the timebase register */
-void clock_get_uptime(
-        AbsoluteTime    *result)
-{
-#ifdef __ppc__
-
-        natural_t       hi, lo, hic;
-
-        do {
-         asm volatile("  mftbu %0" : "=r" (hi));
-         asm volatile("  mftb %0" : "=r" (lo));
-         asm volatile("  mftbu %0" : "=r" (hic));
-        } while (hic != hi);
-
-        result->lo = lo;
-        result->hi = hi;
-#else
-        result->lo = 0;
-        result->hi = 0;
-#endif /* __ppc__ */
-}
-
 int
 exit_usage(myname) {
 
@@ -600,6 +575,7 @@ void screen_update()
         char    *p1, *p2, *p3;
        char    tbuf[256];
        int     clen;
+       int     plen;
        int     n, i, rows;
        long    curr_time;
        long    elapsed_secs;
@@ -851,7 +827,7 @@ void screen_update()
                printf("\n");
 
        if (num_of_threads) {
-               sprintf(tbuf, "\nCURRENT_TYPE              LAST_PATHNAME_WAITED_FOR   CUR_WAIT_TIME  THRD#  PRI\n");
+               sprintf(tbuf, "\nCURRENT_TYPE              LAST_PATHNAME_WAITED_FOR     CUR_WAIT_TIME THRD# PRI\n");
 
                if (tbuf[COLS-2] != '\n') {
                        tbuf[COLS-1] = '\n';
@@ -876,14 +852,10 @@ void screen_update()
                
        for (i = 0; i < num_of_threads; i++, ti++) {
                struct entry *te;
-               unsigned long long now;
-               AbsoluteTime timestamp;
+               uint64_t now;
                int      secs, time_secs, time_usecs;
 
-               clock_get_uptime(&timestamp);
-
-               now = (((unsigned long long)timestamp.hi) << 32) |
-                       (unsigned long long)((unsigned int)(timestamp.lo));
+               now = mach_absolute_time();
 
                while (ti->thread == 0 && ti < &th_state[MAX_THREADS])
                        ti++;
@@ -906,7 +878,13 @@ void screen_update()
                }
                clen = strlen(tbuf);
                
-               sprintf(&tbuf[clen], "   %-28.28s  ", ti->pathname);
+               /* print the tail end of the pathname */
+               plen = strlen(ti->pathname);
+               if (plen > 34)
+                 plen -= 34;
+               else
+                 plen = 0;
+               sprintf(&tbuf[clen], "   %-34.34s ", &ti->pathname[plen]);
 
                clen += strlen(&tbuf[clen]);
 
@@ -917,7 +895,7 @@ void screen_update()
 
                print_time(&tbuf[clen], time_usecs, time_secs);
                clen += strlen(&tbuf[clen]);
-               sprintf(&tbuf[clen], "      %2d  %3d\n", i, ti->curpri);
+               sprintf(&tbuf[clen], "  %2d %3d\n", i, ti->curpri);
 
                if (tbuf[COLS-2] != '\n') {
                        tbuf[COLS-1] = '\n';
@@ -1175,13 +1153,9 @@ sort_scalls() {
        struct th_info *ti;
        struct sc_entry *se;
        struct entry *te;
-       unsigned long long now;
-       AbsoluteTime timestamp;
-
-       clock_get_uptime(&timestamp);
+       uint64_t now;
 
-       now = (((unsigned long long)timestamp.hi) << 32) |
-               (unsigned long long)((unsigned int)(timestamp.lo));
+       now = mach_absolute_time();
 
        for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
                if (ti->thread == 0)
@@ -1215,6 +1189,7 @@ sort_scalls() {
                                if ((unsigned long)(((double)now - te->otime) / divisor) > 5000000) {
                                        ti->thread = 0;
                                        ti->vfslookup = 0;
+                                       ti->pathptr = (long *)0;
                                        ti->pathname[0] = 0;
                                        num_of_threads--;
                                }
@@ -1417,6 +1392,7 @@ sample_sc()
                        th_state[i].depth = 0;
                        th_state[i].thread = 0;
                        th_state[i].vfslookup = 0;
+                       th_state[i].pathptr = (long *)0;
                        th_state[i].pathname[0] = 0;
                }
                num_of_threads = 0;
@@ -1432,7 +1408,7 @@ sample_sc()
        for (i = 0; i < count; i++) {
                int debugid, baseid, thread;
                int type, code;
-               unsigned long long now;
+               uint64_t now;
                struct th_info *ti, *switched_out, *switched_in;
                struct sc_entry *se;
                struct entry *te;
@@ -1445,8 +1421,8 @@ sample_sc()
                switched_out = (struct th_info *)0;
                switched_in  = (struct th_info *)0;
 
-               now = (((unsigned long long)kd[i].timestamp.tv_sec) << 32) |
-                       (unsigned long long)((unsigned int)(kd[i].timestamp.tv_nsec));
+               now = (((uint64_t)kd[i].timestamp.tv_sec) << 32) |
+                       (uint64_t)((unsigned int)(kd[i].timestamp.tv_nsec));
                baseid = debugid & 0xffff0000;
 
                if (debugid == vfs_lookup) {
@@ -1455,22 +1431,32 @@ sample_sc()
                        if ((ti = find_thread(thread)) == (struct th_info *)0)
                                continue;
                        if (ti->vfslookup == 1) {
-                               ti->vfslookup = 2;
-                               memset(&ti->pathname[0], 0, 32);
-                               sargptr = (long *)&ti->pathname[0];
-                               
+                               ti->vfslookup++;
+                               memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
+                               sargptr = (long *)&ti->pathname[0];
+
                                *sargptr++ = kd[i].arg2;
                                *sargptr++ = kd[i].arg3;
                                *sargptr++ = kd[i].arg4;
+                               ti->pathptr = sargptr;
+
+                       } else if (ti->vfslookup > 1) {
+                               ti->vfslookup++;
+                               sargptr = ti->pathptr;
 
-                       } else if (ti->vfslookup == 2) {
-                               ti->vfslookup = 3;
-         
-                               sargptr = (long *)&ti->pathname[12];
+                               /*
+                                 We don't want to overrun our pathname buffer if the
+                                 kernel sends us more VFS_LOOKUP entries than we can
+                                 handle.
+                               */
+
+                               if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
+                                 continue;
                                *sargptr++ = kd[i].arg1;
                                *sargptr++ = kd[i].arg2;
                                *sargptr++ = kd[i].arg3;
                                *sargptr++ = kd[i].arg4;
+                               ti->pathptr = sargptr;
                        }
                        continue;
 
@@ -1617,7 +1603,7 @@ sample_sc()
                        se->delta_count++;
                        se->total_count++;
 
-                       if (ti->depth) {
+                       while (ti->depth) {
                                te = &ti->th_entry[ti->depth-1];
 
                                if (te->type == type) {
@@ -1653,6 +1639,20 @@ sample_sc()
 
                                        te->stime = (double)now;
                                        te->otime = (double)now;
+
+                                       break;
+                               }
+                               ti->depth--;
+
+                               if (ti->depth == 0) {
+                                       /* 
+                                        * headed back to user mode
+                                        * start the time accumulation
+                                        */
+                                       te = &ti->th_entry[0];
+                                       te->sc_state = USER_MODE;
+                                       te->stime = (double)now;
+                                       te->otime = (double)now;
                                }
                        }
                }
@@ -1699,20 +1699,14 @@ char *s;
        exit(1);
 }
 
-
 void getdivisor()
 {
+  mach_timebase_info_data_t info;
 
-    unsigned int delta;
-    unsigned int abs_to_ns_num;
-    unsigned int abs_to_ns_denom;
-    unsigned int proc_to_abs_num;
-    unsigned int proc_to_abs_denom;
+  (void) mach_timebase_info (&info);
 
-    MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
-                      &proc_to_abs_num,  &proc_to_abs_denom);
+  divisor = ( (double)info.denom / (double)info.numer) * 1000;
 
-    divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000;
 }
 
 
index 8a46599aa192073489778b05bf7659d356904fb1..25331b5b309af2e3c9f796ca84e87bd4022b7af9 100644 (file)
@@ -1,4 +1,4 @@
-772
+773
 0xff000104     MSG_mach_notify_port_deleted
 0xff000114     MSG_mach_notify_port_destroyed
 0xff000118     MSG_mach_notify_no_senders
@@ -20,7 +20,7 @@
 0xff000354     MSG_processor_set_default
 0xff000358     MSG_processor_set_create
 0xff00035c     MSG_mach_memory_object_memory_entry_64
-0xff000360     MSG_host_statistics
+0xff000360     MSG_host_statistics
 0xff000640     MSG_host_get_boot_info
 0xff000644     MSG_host_reboot
 0xff000648     MSG_host_priv_statistics
 0xff001f40     MSG_memory_object_get_attributes
 0xff001f44     MSG_memory_object_change_attributes
 0xff001f48     MSG_memory_object_synchronize_completed
-0xff001f50     MSG_memory_object_lock_request
-0xff001f58     MSG_memory_object_destroy
-0xff001f64     MSG_vm_object_upl_request
-0xff001f68     MSG_vm_pager_upl_request
-0xff001f6c     MSG_vm_upl_map
-0xff001f70     MSG_vm_upl_unmap
-0xff001f74     MSG_vm_upl_abort
-0xff001f78     MSG_vm_upl_commit
-0xff001f7c     MSG_vm_upl_commit_range
-0xff002008     MSG_vm_object_upl_request
-0xff00200c     MSG_vm_pager_upl_request
-0xff002010     MSG_vm_upl_abort
-0xff002014     MSG_vm_upl_abort_range
-0xff002018     MSG_vm_upl_commit
-0xff00201c     MSG_vm_upl_commit_range
+0xff001f4c     MSG_memory_object_lock_request
+0xff001f50     MSG_memory_object_destroy
+0xff001f54     MSG_memory_object_upl_request
+0xff001f58     MSG_memory_object_super_upl_request
+0xff001f5c     MSG_memory_object_page_op
+0xff001f60     MSG_memory_object_recover_named
+0xff001f64     MSG_memory_object_release_name
+0xff002008     MSG_upl_abort
+0xff00200c     MSG_upl_abort_range
+0xff002010     MSG_upl_commit
+0xff002014     MSG_upl_commit_range
 0xff002260     MSG_memory_object_init
 0xff002264     MSG_memory_object_terminate
 0xff002268     MSG_memory_object_data_request
-0xff00226c     MSG_memory_object_data_unlock
-0xff002270     MSG_memory_object_lock_completed
-0xff002278     MSG_memory_object_data_return
-0xff00227c     MSG_memory_object_synchronize
-0xff002280     MSG_memory_object_change_completed
+0xff00226c     MSG_memory_object_data_return
+0xff002270     MSG_memory_object_data_initialize
+0xff002274     MSG_memory_object_data_unlock
+0xff002278     MSG_memory_object_synchronize
+0xff00227c     MSG_memory_object_unmap
 0xff002328     MSG_memory_object_create
-0xff00232c     MSG_memory_object_data_initialize
 0xff00238c     MSG_default_pager_object_create
 0xff002390     MSG_default_pager_info
 0xff002394     MSG_default_pager_objects
 0xff002bc8     MSG_io_iterator_next
 0xff002bcc     MSG_io_iterator_reset
 0xff002bd0     MSG_io_service_get_matching_services
-0xff002bd4     MSG_io_service_add_notification_old
+0xff002bd4     MSG_io_registry_entry_get_property
 0xff002bd8     MSG_io_registry_create_iterator
 0xff002bdc     MSG_io_registry_iterator_enter_entry
 0xff002be0     MSG_io_registry_iterator_exit_entry
 0xff002be4     MSG_io_registry_entry_from_path
 0xff002be8     MSG_io_registry_entry_get_name
 0xff002bec     MSG_io_registry_entry_get_properties
-0xff002bf0     MSG_io_registry_entry_get_property
+0xff002bf0     MSG_io_registry_entry_get_property_bytes
 0xff002bf4     MSG_io_registry_entry_get_child_iterator
 0xff002bf8     MSG_io_registry_entry_get_parent_iterator
 0xff002bfc     MSG_io_service_open
 0xff002c8c     MSG_io_service_acknowledge_notification
 0xff002c90     MSG_io_connect_get_notification_semaphore
 0xff002c94     MSG_io_connect_unmap_memory
+0xff002c98     MSG_io_registry_entry_get_location_in_plane
+0xff002c9c     MSG_io_registry_entry_get_property_recursively
 0xff002ee0     MSG_processor_start
 0xff002ee4     MSG_processor_exit
 0xff002ee8     MSG_processor_info
 0xff003bc0     MSG_vm_region_64
 0xff003bc4     MSG_mach_make_memory_entry_64
 0xff003bc8     MSG_vm_map_64
+0xff003bcc     MSG_vm_map_get_upl
+0xff003bd0     MSG_vm_upl_map
+0xff003bd4     MSG_vm_upl_unmap
 0xff003e80     MSG_processor_set_statistics
 0xff003e84     MSG_processor_set_destroy
 0xff003e88     MSG_processor_set_max_priority
 0x1300000      MACH_vmfault
 0x1400000      MACH_SCHED
 0x1400008      MACH_STKHANDOFF
+0x1400018      MACH_MKRUNNABLE
 0x1500000      MACH_MSGID_INVALID
 0x1090000      DecrTrap
 0x1090004      DecrSet
 0x10c0158      MSC_kern_invalid_#86
 0x10c015c      MSC_kern_invalid_#87
 0x10c0160      MSC_kern_invalid_#88
-0x10c0164      MSC_kern_invalid_#89
-0x10c0168      MSC_mk_wait_until
+0x10c0164      MSC_mach_timebase_info
+0x10c0168      MSC_mach_wait_until
 0x10c016c      MSC_mk_timer_create
 0x10c0170      MSC_mk_timer_destroy
 0x10c0174      MSC_mk_timer_arm
index 8dbfac99a5a168ea1579ae3447c1cbe52e567cad..aa6611699bd5a40527f7a794ef9d686ac7b28241 100644 (file)
@@ -28,7 +28,7 @@ DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-FRAMEWORKS = -framework IOKit
+FRAMEWORKS = -framework CoreFoundation -framework IOKit
 
 
 NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
index b1fcde60eb181f9bfc322a5deab051c1cd3c2737..8068b70bcffc06f2e9a8e123defd2655f1339766 100644 (file)
@@ -1,7 +1,7 @@
 {
     DYNAMIC_CODE_GEN = YES; 
     FILESTABLE = {
-        FRAMEWORKS = (IOKit.framework); 
+        FRAMEWORKS = (CoreFoundation.framework, IOKit.framework); 
         H_FILES = (); 
         OTHER_LINKED = (top.c); 
         OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, top.1); 
index 3907ed89439d327b5205949cca0b0759a0367572..d4dd62809d7082eeb4eee1abf2c8a55117908fb5 100644 (file)
@@ -445,17 +445,6 @@ pmem_doit(task_port_t task, int pid, int *shared, int *private, int *aliased, in
                mach_msg_type_number_t  count;
                vm_size_t               size;
 
-               if ( !split && (address >= FW_CODE_BEG_ADDR && address < FW_DATA_END_ADDR)) {
-                       vm_region_basic_info_data_64_t    b_info;
-                         
-                       count = VM_REGION_BASIC_INFO_COUNT_64;
-                       if (err = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info,
-                                           &count, &object_name))
-                               break;
-
-                       if (b_info.reserved)
-                               split = 1;
-               }
                count = VM_REGION_TOP_INFO_COUNT;
 
                if (err = vm_region(task, &address, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info,
@@ -466,6 +455,17 @@ pmem_doit(task_port_t task, int pid, int *shared, int *private, int *aliased, in
 
                        *fw_private += info.private_pages_resident * vm_page_size;
 
+                       if ( !split && info.share_mode == SM_EMPTY) {
+                               vm_region_basic_info_data_64_t    b_info;
+                         
+                               count = VM_REGION_BASIC_INFO_COUNT_64;
+                               if (err = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info,
+                                           &count, &object_name))
+                                       break;
+
+                               if (b_info.reserved)
+                                       split = 1;
+                       }
                        if (info.share_mode != SM_PRIVATE) {
                                address += size;
                                continue;
@@ -830,20 +830,23 @@ void get_proc_info(kpb, pi)
                                (void) vm_deallocate(mach_task_self(), (vm_offset_t)thread_table,
                                                     table_size * sizeof(*thread_table));
 
-                               if (mach_port_names(task, &names, &ncnt,
-                                                   &types, &tcnt) == KERN_SUCCESS) {
-                                       pi->num_ports = ncnt;
-                                       pi->orig_num_ports = ncnt;
-                                       (void) vm_deallocate(mach_task_self(),
-                                                            (vm_offset_t) names,
-                                                            ncnt * sizeof(*names));
-                                       (void) vm_deallocate(mach_task_self(),
-                                                            (vm_offset_t) types,
-                                                            tcnt * sizeof(*types));
-                               } else {
-                                       pi->num_ports = -1;
-                               }
-                       
+                               if (!events_only) {
+                                       if (mach_port_names(task, &names, &ncnt,
+                                                           &types, &tcnt) == KERN_SUCCESS) {
+                                               pi->num_ports = ncnt;
+                                               pi->orig_num_ports = ncnt;
+                                               (void) vm_deallocate(mach_task_self(),
+                                                                    (vm_offset_t) names,
+                                                                    ncnt * sizeof(*names));
+                                               (void) vm_deallocate(mach_task_self(),
+                                                                    (vm_offset_t) types,
+                                                                    tcnt * sizeof(*types));
+                                       } else {
+                                               pi->num_ports = -1;
+                                       }
+                               } else
+                                       pi->num_ports = 0;
+
                                if (events_only) {
                                        task_events_info_data_t tei;
 
@@ -1202,6 +1205,7 @@ main(argc, argv)
        char    *argv[];
 {
        char    *myname = "top";
+       int     ch;
        int     delay = Default_DELAY;
        kern_return_t   error;
 
@@ -1225,19 +1229,11 @@ main(argc, argv)
        events_delta = 0;
        events_accumulate = 0;
 
-       while (argc > 1 && argv[1][0] == '-') {
-               switch (argv[1][1]) {
+       while ((ch = getopt(argc, argv, "uwks:edal:")) != EOF) {
+              switch(ch) {
                case 's':
-                       if (argv[1][2])
-                               delay = atoi(&argv[1][2]);
-                       else {
-                               argc--;
-                               argv++;
-
-                               if (argc > 1)
-                                       delay = atoi(&argv[1][0]);
-                       }
-                       break;
+                       delay = atoi(optarg);
+                       break;
                case 'u':
                        sort_by_usage = 1;
                        break;
@@ -1259,21 +1255,13 @@ main(argc, argv)
                        events_accumulate = 1;
                        break;
                case 'l':
-                       if (argv[1][2])
-                               logcnt = atoi(&argv[1][2]);
-                       else {
-                               argc--;
-                               argv++;
-
-                               if (argc > 1)
-                                       logcnt = atoi(&argv[1][0]);
-                       }
+                       logcnt = atoi(optarg);
                        oneshot = 1;
                        LINES = 80;
                        COLS  = 132;
                        break;
                default:
-                       fprintf(stderr, "Usage: %s [-u] [-w] [-k] [-sn] [-e] [-d] [number]\n", myname);
+                       fprintf(stderr, "Usage: %s [-u] [-w] [-k] [-sn] [-e | -d | -a] [-ln] [number]\n", myname);
                        fprintf(stderr, "  -u      enables sort by usage\n");
                        fprintf(stderr, "  -w      enables wide output of additional info\n");
                        fprintf(stderr, "  -k      generate vm info for kernel(proc 0)... expensive\n");
@@ -1286,9 +1274,11 @@ main(argc, argv)
 
                        exit(1);
                }
-               argc--;
-               argv++;
        }
+
+       argc -= optind;
+       //argv += optind;
+
        if (events_only)
          {
            if ( wide_output || do_proc0_vm)
@@ -1303,8 +1293,8 @@ main(argc, argv)
        host_port = get_host_port();
 
        /* get count of top processes to display (if any) */
-       if (argc > 1) {
-               wanted_topn = topn = atoi(argv[1]);
+       if (argc) {
+               wanted_topn = topn = atoi(argv[optind]);
        } else
                wanted_topn = -1;
 
@@ -1448,7 +1438,7 @@ void screen_update()
        unsigned long long      total_virtual_size;
        unsigned long long      total_private_size;
        unsigned long long      total_shared_size;
-       unsigned int            total_memory_regions;
+       unsigned int            total_memory_regions = 0;
        unsigned int            total_shared_objects;
        unsigned int            total_fw_code_size;
        unsigned int            total_fw_data_size;
@@ -1492,9 +1482,11 @@ void screen_update()
                mach_error("host_info", error);
                exit(EXIT_FAILURE);
        }
-       getNETWORKcounters();
-       getDISKcounters();
-
+       
+       if (events_only) {
+               getNETWORKcounters();
+               getDISKcounters();
+       }
        /* count up process states and get pointers to interesting procs */
 
        mpid = 0;
@@ -1746,7 +1738,7 @@ void screen_update()
                        i_kbytes = i_net.kbytes;
                        o_kbytes = o_net.kbytes;
                }
-               sprintf(tbuf, "en0:   %10d ipkts/%dK", i_io, i_kbytes);
+               sprintf(tbuf, "Networks:%10d ipkts/%dK", i_io, i_kbytes);
                clen = strlen(tbuf);
                memset(&tbuf[clen], ' ', 36 - clen);
                sprintf(&tbuf[36], "%10d opkts /%dK\n", o_io, o_kbytes);
@@ -1792,7 +1784,7 @@ void screen_update()
                        i_kbytes = i_dsk.kbytes;
                        o_kbytes = o_dsk.kbytes;
                }
-               sprintf(tbuf, "Disks: %10d reads/%dK", i_io, i_kbytes);
+               sprintf(tbuf, "Disks:   %10d reads/%dK", i_io, i_kbytes);
                clen = strlen(tbuf);
                memset(&tbuf[clen], ' ', 36 - clen);
                sprintf(&tbuf[36], "%10d writes/%dK\n", o_io, o_kbytes);
@@ -1835,7 +1827,7 @@ void screen_update()
                        pageins = vm_stat.pageins;
                        pageouts = vm_stat.pageouts;
                }
-               sprintf(tbuf, "VM:    %10d pageins", pageins);
+               sprintf(tbuf, "VM:      %10d pageins", pageins);
                clen = strlen(tbuf);
                memset(&tbuf[clen], ' ', 36 - clen);
                sprintf(&tbuf[36], "%10d pageouts\n", pageouts);
@@ -2199,25 +2191,26 @@ getNETWORKcounters()
        if (kread(nl_net[N_IFNET].n_value, (char *)&ifnethead, sizeof ifnethead))
               return;
 
+        i_net.io = 0;
+       o_net.io = 0;
+                         
+       i_net.kbytes = 0;
+       o_net.kbytes = 0;
+
        for (off = (u_long)ifnethead.tqh_first; off; ) {
-                  char name[16], tname[16];
+                  char tname[16];
 
                  if (kread(off, (char *)&ifnet, sizeof ifnet))
                          break;
                  if (kread((u_long)ifnet.if_name, tname, 16))
                          break;
-                  tname[15] = '\0';
 
-                 snprintf(name, 16, "%s%d", tname, ifnet.if_unit);
-
-                 if (strcmp(name, "en0") == 0) {
-                         i_net.io = ifnet.if_ipackets;
-                         o_net.io = ifnet.if_opackets;
+                 if (strncmp(tname, "lo", 2)) {
+                         i_net.io += ifnet.if_ipackets;
+                         o_net.io += ifnet.if_opackets;
                          
-                         i_net.kbytes = ifnet.if_ibytes/1024;
-                         o_net.kbytes = ifnet.if_obytes/1024;
-
-                         return;
+                         i_net.kbytes += ifnet.if_ibytes/1024;
+                         o_net.kbytes += ifnet.if_obytes/1024;
                  }
                  off = (u_long) ifnet.if_link.tqe_next;
        }