Friday, January 20, 2006

Pre-order your Mac OS X Internals book!

If you're interested in Mac OS X hacking you've undoubtedly run across Amit Singh's website www.kernelthread.com which is likely one of the richest resources on the net. Well, I had the pleasure of meeting him today. He gave a talk on Mac OS X Internals which is the topic of a book that he has coming out soon (I'm waiting on pins and needles). It's available for pre-order on Amazon. So, order yours today! I've already ordered mine ;-)

Sunday, January 08, 2006

Macworld 2006

I'm heading up to Macworld tomorrow. I don't know if there will be anything terribly interesting going on tomorrow, but we'll see. I'm sure the "Stevenote" on Tuesday will be great as always, though.

Friday, January 06, 2006

Darwin, ptrace(), and registers

Most Unix systems have a ptrace() system call which can be used to trace a process. This call is commonly used by debuggers to peek and poke in another process's memory. Darwin (the Unix foundation of Mac OS X) does offer a ptrace() call, but it's not as robust as on other platforms.

For example, on Linux I can read the registers of a target process using pseudo-code like:


struct user regs;
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
ptrace(PTRACE_GETREGS, pid, NULL, ®s);

The problem is that Darwin doesn't offer a PTRACE_GETREGS equivalent. Darwin does, however, offer similar functionality through the use of some Mach API calls. Below is a sample program that takes a PID as an argument, and prints out some of the register values for its first Mach thread.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <mach/mach.h>

int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "usage: getregs \n");
exit(EXIT_FAILURE);
}

pid_t pid = atoi(argv[1]);
mach_port_t task;
kern_return_t err;

/* Get the mach task for the target process */
err = task_for_pid(mach_task_self(), pid, &task);
if (err != KERN_SUCCESS) {
fprintf(stderr, "task_for_pid() failed\n");
exit(EXIT_FAILURE);
}

/* Suspend the target process */
err = task_suspend(task);
if (err != KERN_SUCCESS) {
fprintf(stderr, "task_suspend() failed\n");
exit(EXIT_FAILURE);
}

/* Get all threads in the specified task */
thread_act_port_array_t threadList;
mach_msg_type_number_t threadCount;
err = task_threads(task, &threadList, &threadCount);
if (err != KERN_SUCCESS) {
fprintf(stderr, "task_threads() failed\n");
exit(EXIT_FAILURE);
}
assert(threadCount > 0);

/* Get the thread state for the first thread */
ppc_thread_state_t state;
mach_msg_type_number_t stateCount;
stateCount = PPC_THREAD_STATE_COUNT;
err = thread_get_state(threadList[0],
PPC_THREAD_STATE,
(thread_state_t)&state,
&stateCount);
if (err != KERN_SUCCESS) {
fprintf(stderr, "thread_get_state() failed\n");
exit(EXIT_FAILURE);
}

/* Print some register values */
assert(stateCount == PPC_THREAD_STATE_COUNT);
printf("pc = %p\n", state.srr0);
printf("r0 = %p\n", state.r0);
printf("r1 = %p\n", state.r1);
printf("r2 = %p\n", state.r2);
printf("r3 = %p\n", state.r3);
printf("r4 = %p\n", state.r4);

/* Resume the task (process) */
err = task_resume(task);
if (err != KERN_SUCCESS) {
fprintf(stderr, "task_resume() failed\n");
exit(EXIT_FAILURE);
}

return EXIT_SUCCESS;
}


I haven't really tested the above program thoroughly, so it's possible it has some bugs. But regardless, I think the general idea is sound.

Thursday, January 05, 2006

Two Cool Bash Tricks

I'll start off this blog with two super-cool bash shell tricks. You'll be the envy of your friends with these up your sleeve.


  1. The "/dev/tcp" trick


    Bash does some super-cool magic when you access /dev/tcp/hostname/port. It will create a TCP socket that is connected to the named host on the given port. This lets you easily use network sockets with regular shell IO redirection. For example, the following simply prints the time from NIST:

    cat < /dev/tcp/time.nist.gov/13

    And YES, you can read AND write to these sockets. Here's how. The following example fetches the source for the www.google.com homepage.

    exec 5<> /dev/tcp/www.google.com/80
    printf "GET / HTTP/1.0\n\n" >&5
    cat <&5
    exec 5>&-

    Check out the bash(1) manpage for more details.

  2. Process Substitution


    This trick allows you to use a process *almost* anywhere you can use a file. To illustrate, let's consider the diff command. Most versions of diff require you to pass exactly two file names as arguments. But what if we want to diff something, like the contents of a directory, that doesn't necessarily exist in a file? This is where we can use process substitution. For example, to diff the contents of two directories, you could use:

    diff <(find dir1) <(find dir2)

    The syntax <(command) creates a named pipe, and attaches command's STDOUT to the pipe. So, anything that reads from the pipe will actually be reading the output of command. To prove this to yourself, try the following:

    $ echo <(/bin/true)
    /dev/fd/63
    $ ls -l <(/bin/true)
    lr-x------ 1 jgm eng 64 Jul 13 21:50 /dev/fd/63 -> pipe:[31340331]
    $ file <(/bin/true)
    /dev/fd/63: broken symbolic link to pipe:[31340360]

    Similarly, you can use the syntax >(command) to have the command read from the pipe. An example is:

    tar cvf >(gzip -c > dir.tar.gz) dir

    Obviously, there are better ways to accomplish taring and compressing, but the point was to use process substitution.

First Post

(Just setting this thing up)

I ...

- work as a Mac OS X Software Engineer
- got married recently
- live in CA