[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-optimize
Subject:    Re: Dynamic symbol table
From:       Karl Vogel <karl.vogel () seagha ! com>
Date:       2004-07-21 11:16:52
Message-ID: 200407211316.52096.karl.vogel () seagha ! com
[Download RAW message or body]

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

["tracer.c" (text/x-csrc)]

/*
 * 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());
}


_______________________________________________
Kde-optimize mailing list
Kde-optimize@kde.org
https://mail.kde.org/mailman/listinfo/kde-optimize


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic