This page is not available in 繁體中文, as a result the English (en_US) version is shown instead.
libdebug

debug.c:

#include <glib.h>

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>

void ld_attach() __attribute((constructor));
static gboolean ld_read_cb(GIOChannel *source, GIOCondition cond,
                           gpointer data);
static gboolean ld_conn_cb(GIOChannel *source, GIOCondition cond,
                           gpointer data);
static int ld_create_socket();

static guint source_id = -1;

void
ld_attach()
{
    int fd = ld_create_socket();

    if (fd == -1) {
        return;
    }

    GIOChannel *channel = g_io_channel_unix_new(fd);

    source_id = g_io_add_watch(channel, G_IO_IN | G_IO_HUP, ld_conn_cb, NULL);
}

static gboolean
ld_conn_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
{
    struct sockaddr_in in_addr;
    socklen_t size = -1;

    if (cond == G_IO_IN) {
        int fd = g_io_channel_unix_get_fd(channel);
        int new_fd = -1;

        size = sizeof(in_addr);
        if ((new_fd = accept(fd, (struct sockaddr *)&in_addr, &size)) == -1) {
            perror("accept");
            return TRUE;
        }

        GIOChannel *channel2 = g_io_channel_unix_new(new_fd);
        source_id = g_io_add_watch(channel2, G_IO_IN | G_IO_HUP, ld_read_cb,
                                   NULL);
    }

    return TRUE;
}

static gboolean
ld_read_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
{
    int addr = 0;
    char *line = NULL;

    if (cond == G_IO_IN) {
        while (g_io_channel_read_line(channel, &line, NULL, NULL, NULL) == 
               G_IO_STATUS_NORMAL) {
            if (sscanf(line, "%x\n", &addr) == 1) {
                char *ptr = GINT_TO_POINTER(addr);
                int i = 0;

                printf("Reading address %p: ", ptr);

                for (i = 0; i < 10 && *ptr; i++, ptr++) {
                    printf("%c", *ptr);
                }

                printf("\n");
            }
        }
    } else if (cond == G_IO_ERR || cond == G_IO_HUP) {
        g_io_channel_shutdown(channel, FALSE, NULL);
    }

    return TRUE;
}

static int
ld_create_socket()
{
    int fd = -1;
    struct sockaddr_in addr;

    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(34567);

    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("bind");
        return -1;
    }

    if (listen(fd, 0) == -1) {
        perror("listen");
        return -1;
    }

    return fd;
}

main.c:

#include <stdio.h>
#include <glib.h>

int
main(int argc, char **argv)
{
    GMainLoop *mainloop = g_main_loop_new(NULL, FALSE);
    printf("%p: %s\n", argv[0], argv[0]);

    g_main_loop_run(mainloop);

    return 0;
}

Makefile:

LSRC=                                           \
    debug.c                                     \


SRC=                                            \
    main.c                                      \


LOBJ = $(LSRC:.c=.o)

OBJ = $(SRC:.c=.o)

CFLAGS += -Wall -g -Werror -Wextra -Wfloat-equal -Wbad-function-cast -Wcast-qual -Winline -Wno-unused-parameter
CFLAGS += `pkg-config --cflags glib-2.0` -I$(PWD)
LFLAGS += `pkg-config --libs glib-2.0`

LIBOUT = libdebug.so

OUT = test

all: $(LIBOUT) $(OUT)

$(OUT): $(OBJ)
    $(CC) $(CFLAGS) $(LFLAGS) $(OBJ) -L$(PWD) -o $(OUT)

$(LIBOUT): $(LOBJ)
    $(CC) -shared -Wl,-soname,$(LIBOUT) $(CFLAGS) $(LFLAGS) $(LOBJ) -o $(LIBOUT)

$(OBJ): %.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

$(LOBJ): %.o: %.c
    $(CC) -fPIC $(CFLAGS) -c $< -o $@

clean:
    $(RM) $(LOBJ) $(LIBOUT) $(OUT) $(OBJ)

To run:

$ make
$ LD_PRELOAD=./libdebug.so ./test
0xbfc5b9b7: ./test

Then in another terminal:

$ telnet 127.0.0.1 34567
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
0xbfc5b9b7

You should see this printed out in the original terminal:

$ LD_PRELOAD=./libdebug.so ./test
0xbfc5b9b7: ./test
Reading address 0xbfc5b9b7: ./test

Printing the result in the telnet window is left as an exercise for the reader.

by khc on Sat Sep 30 21:44:59 2006 Permlink
Tags: computer