Re: Dynamic symbol table

Karl Vogel <[email protected]>
Newsgroups gmane.comp.kde.devel.optimize
Message-ID <[email protected]>
Lubos Lunak wrote:

> On Tuesday 20 of July 2004 18:37, Karl Vogel wrote:
>>
>> X 08048520        0 X 008 paddr 08048000 acc 08048520 pgoff 00000000 foff
>> 00000000 fnam=/usr/bin/kedit A 002498a3        0 X 002 paddr 00432000 acc
>> 004323f4 pgoff 00000000 foff 00000000 fnam=/usr/lib/libkdeinit_kedit.so A
> 
>  How did you get this? Is it some profiling tool? I don't see anything
>  similar
> in /proc.

I wrote a quick 'n dirty hack to generate this. The tool definately needs to 
TLC, but anyway I'll attach it.

Build it with (Makefile):
---
tracer: tracer.c
        $(CC) -Wall -Os -shared -o tracer tracer.c -ldl
---

Usage is:
  LD_PRELOAD=./tracer executable

Output will go to stderr. The tool assumes it's in /home somewhere, so it 
doesn't mprotect stuff that lives in /home -- ie. as to not block itself :)

Either way.. a valgrind based execution flow tracer would be nicer, but this 
kind of works also. (on Fedora Core 2)

>  Not everything from the file is supposed to be loaded when executing it.
> There may be debug data or similar. If you run 'objdump --headers' on the
> file, find first sections that is not marked LOAD, and its file offset
> column gives in hex how much of the file is actually loaded. (If you just
> strip the file it gives almost the same number.)

Yups.. was aware of this.. otherwise I don't think my KDE would load this 
fast, seeing that my libqt is 63Mb :)

btw: 'readelf -e executable'  also works.. and the output is more readable

_______________________________________________
Kde-optimize mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/kde-optimize
tracer.c (text/x-csrc, 5.2 KB)
/*
 * Crude LD_PRELOAD hack to show which pages are faulted
 * during execution.
 *
 * Usage:
 *   LD_PRELOAD=./tracer executable
 *
 * Output of the tracer is to stderr.
 *
 * The tracer has to be in /home somewhere (hey I said it
 * was crude.. didn't I!).
 *
 * Author: Karl Vogel
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <dlfcn.h>
#define __USE_GNU
#include <sys/ucontext.h>
#include <unistd.h>
#include <errno.h>

static void init (void) __attribute__ ((constructor));
static __sighandler_t (*libc_signal) (int __sig, __sighandler_t __handler);
extern int __sigaction(int __sig, __const struct sigaction *__restrict __act,
		       struct sigaction *__restrict __oact);

#define MAXMAPS 200

static struct map {
  unsigned long start;
  unsigned long end;
  char name[256];
  int prot;
  unsigned long pgoff;
} maps[MAXMAPS];
static int mapcount;



static int findmap(void *addr)
{
  unsigned long vmaddr= (unsigned long)addr;
  int i;
  int rv= -1;

  for (i= 0; i<mapcount; i++) {
    if ( vmaddr >= maps[i].start && vmaddr <= maps[i].end) {
      rv= i;
      break;
    }
  }
  if (rv == -1) {
    fprintf(stderr, "E SEGV_MAPERR in unknown range!\n");
    abort();
  }
  return rv;
}

static void mysig(int signum, siginfo_t *si,
		 void *vuc)
{
  static unsigned long oldaddr= 0;

  unsigned long addr;
  int i;
  ucontext_t *uc= (ucontext_t *)vuc;
  char type;

  switch(si->si_code) {
  case SEGV_MAPERR:
    fprintf(stderr, "Unhandled SEGV_MAPERR\n");
    abort();
    break;

  case SEGV_ACCERR:
    addr= (unsigned long)si->si_addr;
    addr &= ~(0x1000-1);
    i= findmap(si->si_addr);
    type = (uc->uc_mcontext.gregs[REG_EIP] != (unsigned int)si->si_addr)?'A':'X';

    fprintf(stderr, "%c %08x %8lu X %03d paddr %08lx acc %08lx pgoff %08lx foff %08lx fnam=%s\n",
	    type,
	    uc->uc_mcontext.gregs[REG_EIP], 
	    maps[i].pgoff + addr-maps[i].start, 
	    i, 
	    addr, 
	    (unsigned long)si->si_addr, 
	    maps[i].pgoff,
            maps[i].pgoff + addr-maps[i].start, 
	    maps[i].name
	    );

    if (mprotect((void *)addr, 0x1000, maps[i].prot)==-1) {
      perror("mprotect");
      abort();
    }
    break;

  default:
    fprintf(stderr, "signum %d  si_code= %d\n", signum, si->si_code);
    abort();
    break;
  }

  if (oldaddr == (unsigned long)si->si_addr) {
    fprintf(stderr, "Double whammy!\n");
    abort();
  }
  oldaddr= (unsigned long)si->si_addr;
}

__sighandler_t signal (int __sig, __sighandler_t __handler)
{
  switch(__sig) {
  case SIGFPE:
  case SIGSEGV:
  case SIGILL:
  case SIGABRT:
  case SIGBUS:
    fprintf(stderr, "E trying to set signal %d -- Ignoring!!!\n", __sig);
    break;
  default:
    return libc_signal(__sig, __handler);
    break;
  }
  return SIG_ERR;
}

int sigaction(int __sig, __const struct sigaction *__restrict __act,
			      struct sigaction *__restrict __oact)
{
  switch(__sig) {
  case SIGFPE:
  case SIGSEGV:
  case SIGILL:
  case SIGABRT:
  case SIGBUS:
    fprintf(stderr, "E trying to set sigaction %d -- Ignoring!!!\n", __sig);
    break;
  default:
    return __sigaction(__sig, __act, __oact);
    break;
  }
  errno= EINVAL;
  return 0;
}



static void init(void)
{
  struct sigaction sa = {
    .sa_sigaction = mysig,
    .sa_flags = SA_SIGINFO | SA_RESTART
  };
  FILE *fp;
  char buf[256];
  unsigned long vm_start, vm_end;
  char read,write,share,exec;
  unsigned long pgoff;
  unsigned long vm_size;
  int skip;
  unsigned long inode;

  memset((char *)maps, 0, sizeof(maps));
  mapcount= 0;

  sigemptyset(&sa.sa_mask);
  if (__sigaction(SIGSEGV, &sa, 0) < 0)
    return;

  fp= fopen("/proc/self/maps", "r");
  if (!fp) {
    perror("fopen");
    abort();
  }

  while(fgets(buf, sizeof(buf), fp)) {
    sscanf(buf, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu",
	   &vm_start,&vm_end, &read,&write,&exec,&share,
	   &pgoff, &skip, &skip, &inode);

    if (inode==0)
      continue;

    buf[strlen(buf)-1]= 0;

    /*
     * Lookup the signal() symbol in the currently mapped
     * libc, as it's not exported like __sigaction is.
     */
    if (strstr(&buf[49], "libc")) {
      void *handle= dlopen(&buf[49], RTLD_LAZY);
      if (!handle) {
	fprintf(stderr, "dlopen: %s", dlerror());
	abort();
      }

      libc_signal= dlsym(handle, "signal");
      if (!handle) {
	fprintf(stderr, "dlsym: %s", dlerror());
	abort();
      }

      /*
       * Don't trap on myself (installed in /home) or on the libraries
       * that contain the functions I'm using here (/lib)
       */
    } else if ( exec == 'x' &&
		buf[49] == '/' &&
		strncmp(&buf[49], "/lib/", 5) &&
		strncmp(&buf[49], "/home", 5)
		) {

      vm_size= vm_end-vm_start;
      maps[mapcount].start= vm_start;
      maps[mapcount].end= vm_end;
      maps[mapcount].pgoff= pgoff;
      maps[mapcount].prot= 0;

      if (read=='r')
	maps[mapcount].prot |= PROT_READ;
      if (write=='w')
	maps[mapcount].prot |= PROT_WRITE;
      if (exec=='x')
	maps[mapcount].prot |= PROT_EXEC;

      strcpy(maps[mapcount].name, &buf[49]);
      mapcount++;
      if (mprotect((void *)vm_start, vm_size, PROT_NONE) == -1) {
	perror("mprotect");
	abort();
      }
    }
  }
  fclose(fp);

  fprintf(stderr, "INIT:%d\n", getpid());
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.