Quantcast
Channel: Nikolay Igotti
Viewing all articles
Browse latest Browse all 30

Context sensitive function behavior

$
0
0
Usually C, unlike dynamic languages, considered not so easy to write context sensitive code. To demonstrate that this is feasible, at least on some systems and compilers I wrote following hack. Function foxy() behaves differently depending on who called it. This behavior could be useful in profilers, and some modularity checks (for example if you want to ensure noone calls your static functions even by pointers).
#include <elf.h>
#include <stdio.h>
#include <stdint.h>

typedef struct {
  intptr_t start;
  intptr_t end;
  char* value;
} range_t;


static range_t ranges[2];

int compute_size(void* start) {
  Dl_info dlip;
  Elf32_Sym* sym = 0;
  int rv = dladdr1(start, &dlip, (void**)&sym, RTLD_DL_SYMENT);
  return (rv && sym) ? sym->st_size : -1;
}

void init_ranges() {
  int i;

  ranges[0].start = (intptr_t)&foo;
  ranges[0].value = "foo";
  ranges[1].start = (intptr_t)&bar;
  ranges[1].value = "bar";

  for (i=0; i < sizeof(ranges)/sizeof(ranges[0]); i++) {
    int sz = compute_size((void*)ranges[i].start);
    if (sz < 0) {
      sz = 0;
    }
    ranges[i].end = ranges[i].start + sz;
  }
}

char* foxy() {
  intptr_t caller = (intptr_t)__builtin_return_address (0);
  int i, idx = -1;
  
  for (i=0; i < sizeof(ranges)/sizeof(ranges[0]); i++) {
    if (caller >= ranges[i].start && caller < ranges[i].end) {
      idx = i;
      break;
    }
  }

   if (idx != -1) {
    return ranges[i].value;
  }

  return "other";
}


void foo() {
  printf("foo=%s\n", foxy());
}

void bar() {
  printf("bar=%s\n", foxy());
}

void boo() {
  printf("boo=%s\n", foxy());
}




int main() {
  init_ranges();
  foo();
  bar();
  boo();
  return 0;
}

Viewing all articles
Browse latest Browse all 30

Trending Articles