Ejemplo n.º 1
0
int
addrtosymstr(void *pc, char *buffer, int size)
{
	Dl_info info;
	Sym *sym;

	if (dladdr1(pc, &info, (void **)&sym,
	    RTLD_DL_SYMENT) == 0) {
		return (snprintf(buffer, size, "[0x%p]", pc));
	}

	if ((info.dli_fname != NULL && info.dli_sname != NULL) &&
	    ((uintptr_t)pc - (uintptr_t)info.dli_saddr < sym->st_size)) {
		/*
		 * we have containing symbol info
		 */
		return (snprintf(buffer, size, "%s'%s+0x%x [0x%p]",
		    info.dli_fname,
		    info.dli_sname,
		    (unsigned long)pc - (unsigned long)info.dli_saddr,
		    pc));
	} else {
		/*
		 * no local symbol info
		 */
		return (snprintf(buffer, size, "%s'0x%p [0x%p]",
		    info.dli_fname,
		    (unsigned long)pc - (unsigned long)info.dli_fbase,
		    pc));
	}
}
Ejemplo n.º 2
0
static int fmt(uintptr_t pc, int sig, void *userdata)
{
    fmt_userdata_t *u = userdata;
    diag_backtrace_param_t *p = u->p;
    diag_output_t *o = u->o;
    int rc;
    Dl_info dlip = {0};

#ifdef BROKEN_SIGNAL_UCONTEXT_T
    if (u->skips) {
        --u->skips;
        return 0;
    }
#endif

    rc = dladdr1((void *)pc, &dlip, NULL, 0);
    if (rc != 0) {
        char buf[128];
        char addr_buf[20];
        char offset_buf[20];
        const char *module_path = dlip.dli_fname;
        const char *module = NULL;
        const char *function = dlip.dli_sname;

        module = module_path;
        if (module) {
            module = strrchr(module_path, '/');
            if (module) {
                module += 1;
            }
        }
        add_int(addr_buf, addr_buf + sizeof addr_buf - 1, (long long)pc, 16);
        add_int(offset_buf, offset_buf + sizeof offset_buf - 1,
                (long long)((char *)pc - (char *)dlip.dli_saddr), 16);

        output_frame(buf, buf + sizeof buf - 1,
                     p->backtrace_fields,
                     module_path, module, function,
                     offset_buf, addr_buf);

        if (o->output_mode == DIAG_CALL_FN) {
            o->output_fn(o->user_data, buf);
        }
        else {
            write(o->outfile, buf, strlen(buf));
            write(o->outfile, "\n", 1);
        }
    }
    else {
        /* printf("dladdr1 failed, errno %d\n", errno); */
    }

    ++u->cur;
    return u->cur >= u->count;
}
Ejemplo n.º 3
0
void *get_func_end(void *func)
{
	int r;
	Dl_info dl_info;
	ElfW(Sym) *elf_info;

	r = dladdr1(func, &dl_info, (void **) &elf_info, RTLD_DL_SYMENT);
	if (r == 0)
		return NULL;
	if (elf_info == NULL)
		return NULL;
	if (dl_info.dli_saddr == NULL)
		return NULL;

	return ((unsigned char *) func) + elf_info->st_size;
}
Ejemplo n.º 4
0
/* Called for each frame on the stack to print it's contents */
static int
xorg_backtrace_frame(uintptr_t pc, int signo, void *arg)
{
    Dl_info dlinfo;
    ElfSym *dlsym;
    char header[32];
    int depth = *((int *) arg);

    if (signo) {
        char signame[SIG2STR_MAX];

        if (sig2str(signo, signame) != 0) {
            strcpy(signame, "unknown");
        }

        ErrorFSigSafe("** Signal %u (%s)\n", signo, signame);
    }

    snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc);
    *((int *) arg) = depth + 1;

    /* Ask system dynamic loader for info on the address */
    if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) {
        unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr;
        const char *symname;

        if (offset < dlsym->st_size) {  /* inside a function */
            symname = dlinfo.dli_sname;
        }
        else {                  /* found which file it was in, but not which function */
            symname = "<section start>";
            offset = pc - (uintptr_t) dlinfo.dli_fbase;
        }
        ErrorFSigSafe("%s: %s:%s+0x%x\n", header, dlinfo.dli_fname, symname,
                      offset);

    }
    else {
        /* Couldn't find symbol info from system dynamic loader, should
         * probably poke elfloader here, but haven't written that code yet,
         * so we just print the pc.
         */
        ErrorFSigSafe("%s\n", header);
    }

    return 0;
}
Ejemplo n.º 5
0
static int
do_test (void)
{
  void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY);
  if (handle == NULL)
    printf ("nonexistent: %s\n", dlerror ());
  else
    exit (1);

  handle = dlopen ("modstatic2.so", RTLD_LAZY);
  if (handle == NULL)
    {
      printf ("%s\n", dlerror ());
      exit (1);
    }

  int (*test) (FILE *, int);
  test = dlsym (handle, "test");
  if (test == NULL)
    {
      printf ("%s\n", dlerror ());
      exit (1);
    }

  Dl_info info;
  int res = dladdr (test, &info);
  if (res == 0)
    {
      puts ("dladdr returned 0");
      exit (1);
    }
  else
    {
      if (strstr (info.dli_fname, "modstatic2.so") == NULL
	  || strcmp (info.dli_sname, "test") != 0)
	{
	  printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname);
	  exit (1);
	}
      if (info.dli_saddr != (void *) test)
	{
	  printf ("saddr %p != test %p\n", info.dli_saddr, test);
	  exit (1);
	}
    }

  ElfW(Sym) *sym;
  void *symp;
  res = dladdr1 (test, &info, &symp, RTLD_DL_SYMENT);
  if (res == 0)
    {
      puts ("dladdr1 returned 0");
      exit (1);
    }
  else
    {
      if (strstr (info.dli_fname, "modstatic2.so") == NULL
	  || strcmp (info.dli_sname, "test") != 0)
	{
	  printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname);
	  exit (1);
	}
      if (info.dli_saddr != (void *) test)
	{
	  printf ("saddr %p != test %p\n", info.dli_saddr, test);
	  exit (1);
	}
      sym = symp;
      if (sym == NULL)
	{
	  puts ("sym == NULL\n");
	  exit (1);
	}
      if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
	{
	  printf ("bind %d visibility %d\n",
		  (int) ELF32_ST_BIND (sym->st_info),
		  (int) ELF32_ST_VISIBILITY (sym->st_other));
	  exit (1);
	}
    }

  Lmid_t lmid;
  res = dlinfo (handle, RTLD_DI_LMID, &lmid);
  if (res != 0)
    {
      printf ("dlinfo returned %d %s\n", res, dlerror ());
      exit (1);
    }
  else if (lmid != LM_ID_BASE)
    {
      printf ("lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE);
      exit (1);
    }

  res = test (stdout, 2);
  if (res != 4)
    {
      printf ("Got %i, expected 4\n", res);
      exit (1);
    }

  void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY);
  if (handle2 == NULL)
    {
      printf ("libdl.so: %s\n", dlerror ());
      exit (1);
    }

  if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL)
    {
      printf ("dlvsym: %s\n", dlerror ());
      exit (1);
    }

  void *(*dlsymfn) (void *, const char *);
  dlsymfn = dlsym (handle2, "dlsym");
  if (dlsymfn == NULL)
    {
      printf ("dlsym \"dlsym\": %s\n", dlerror ());
      exit (1);
    }
  void *test2 = dlsymfn (handle, "test");
  if (test2 == NULL)
    {
      printf ("%s\n", dlerror ());
      exit (1);
    }
  else if (test2 != (void *) test)
    {
      printf ("test %p != test2 %p\n", test, test2);
      exit (1);
    }

  dlclose (handle2);
  dlclose (handle);

  handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY);
  if (handle == NULL)
    {
      printf ("%s\n", dlerror ());
      exit (1);
    }
  dlclose (handle);

  handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY);
  if (handle == NULL)
    printf ("LM_ID_NEWLM: %s\n", dlerror ());
  else
    {
      puts ("LM_ID_NEWLM unexpectedly succeeded");
      exit (1);
    }

  return 0;
}
Ejemplo n.º 6
0
static void
vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd)
{
    Dl_info dlip;
    DRI_ELFSYM* sym=0;
    int rv;
    void *alPatch;
    void *pMesaEntry;
    char patch[FAKEDRI_JMP64_PATCH_SIZE];
    void *shift;
    int ignore_size=false;

#ifndef VBOX_NO_MESA_PATCH_REPORTS
    crDebug("\nvboxPatchMesaExport: %s", psFuncName);
#endif

    pMesaEntry = dlsym(RTLD_DEFAULT, psFuncName);

    if (!pMesaEntry)
    {
        crDebug("%s not defined in current scope, are we being loaded by mesa's libGL.so?", psFuncName);
        return;
    }

    rv = dladdr1(pMesaEntry, &dlip, (void**)&sym, RTLD_DL_SYMENT);
    if (!rv || !sym)
    {
        crError("Failed to get size for %p(%s)", pMesaEntry, psFuncName);
        return;
    }

#if VBOX_OGL_GLX_USE_CSTUBS
    {
        Dl_info dlip1;
        DRI_ELFSYM* sym1=0;
        int rv;

        rv = dladdr1(pStart, &dlip1, (void**)&sym1, RTLD_DL_SYMENT);
        if (!rv || !sym1)
        {
            crError("Failed to get size for vbox %p", pStart);
            return;
        }

        pEnd = pStart + sym1->st_size;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
        crDebug("VBox Entry: %p, start: %p(%s:%s), size: %li", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
# endif
    }
#endif

#ifndef VBOX_NO_MESA_PATCH_REPORTS
    crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %li", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
    crDebug("VBox code: start: %p, end %p, size: %li", pStart, pEnd, pEnd-pStart);
#endif

#ifndef VBOX_OGL_GLX_USE_CSTUBS
    if (sym->st_size<(pEnd-pStart))
#endif
    {
#ifdef RT_ARCH_AMD64
        int64_t offset;
#endif
        /* Try to insert 5 bytes jmp/jmpq to our stub code */

    	if (sym->st_size<5)
        {
            /*@todo we don't really know the size of targeted static function, but it's long enough in practice. We will also patch same place twice, but it's ok.*/
            if (!crStrcmp(psFuncName, "glXDestroyContext") || !crStrcmp(psFuncName, "glXFreeContextEXT"))
            {
                if (((unsigned char*)dlip.dli_saddr)[0]==0xEB)
                {
                    /*it's a rel8 jmp, so we're going to patch the place it targets instead of jmp itself*/
                    dlip.dli_saddr = (void*) ((intptr_t)dlip.dli_saddr + ((char*)dlip.dli_saddr)[1] + 2);
                    ignore_size = true;
                }
                else
                {
                    crError("Can't patch size is too small.(%s)", psFuncName);
                    return;
                }
            }
            else if (!crStrcmp(psFuncName, "glXCreateGLXPixmapMESA"))
            {
                /*@todo it's just a return 0, which we're fine with for now*/
                return;
            }
            else
            {
                crError("Can't patch size is too small.(%s)", psFuncName);
                return;
            }
        }

        shift = (void*)((intptr_t)pStart-((intptr_t)dlip.dli_saddr+5));
#ifdef RT_ARCH_AMD64
        offset = (intptr_t)shift;
        if (offset>INT32_MAX || offset<INT32_MIN)
        {
            /*try to insert 64bit abs jmp*/
            if (sym->st_size>=FAKEDRI_JMP64_PATCH_SIZE || ignore_size)
            {
# ifndef VBOX_NO_MESA_PATCH_REPORTS
                crDebug("Inserting movq/jmp instead");
# endif
                /*add 64bit abs jmp*/
                patch[0] = 0x49; /*movq %r11,imm64*/
                patch[1] = 0xBB;
                crMemcpy(&patch[2], &pStart, 8);
                patch[10] = 0x41; /*jmp *%r11*/
                patch[11] = 0xFF;
                patch[12] = 0xE3;
                pStart = &patch[0];
                pEnd = &patch[FAKEDRI_JMP64_PATCH_SIZE];
            }
            else
            {
                FAKEDRI_PatchNode *pNode;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
                crDebug("Can't patch offset is too big. Pushing for 2nd pass(%s)", psFuncName);
# endif
                /*Add patch node to repatch with chain jmps in 2nd pass*/
                pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
                if (!pNode)
                {
                    crError("Not enough memory.");
                    return;
                }
                pNode->psFuncName = psFuncName;
                pNode->pDstStart = dlip.dli_saddr;
                pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
                pNode->pSrcStart = pStart;
                pNode->pSrcEnd = pEnd; 
                pNode->pNext = g_pRepatchList;
                g_pRepatchList = pNode;
                return;
            }
        }
        else
#endif
        {
#ifndef VBOX_NO_MESA_PATCH_REPORTS
            crDebug("Inserting jmp[q] with shift %p instead", shift);
#endif
            patch[0] = 0xE9;
            crMemcpy(&patch[1], &shift, 4);
            pStart = &patch[0];
            pEnd = &patch[5];
        }
    }

    vboxApplyPatch(psFuncName, dlip.dli_saddr, pStart, pEnd-pStart);

#ifdef RT_ARCH_AMD64
    /*Add rest of mesa function body to free list*/
    if (sym->st_size-(pEnd-pStart)>=FAKEDRI_JMP64_PATCH_SIZE)
    {
        FAKEDRI_PatchNode *pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
        if (pNode)
        {
                pNode->psFuncName = psFuncName;
                pNode->pDstStart = dlip.dli_saddr+(pEnd-pStart);
                pNode->pDstEnd = dlip.dli_saddr+sym->st_size; 
                pNode->pSrcStart = dlip.dli_saddr;
                pNode->pSrcEnd = NULL;
                pNode->pNext = g_pFreeList;
                g_pFreeList = pNode;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
                crDebug("Added free node %s, func start=%p, free start=%p, size=%#lx",
                        psFuncName, pNode->pSrcStart, pNode->pDstStart, pNode->pDstEnd-pNode->pDstStart);
# endif
        }
    }
#endif
}
Ejemplo n.º 7
0
int
test (FILE *out, int a)
{
  fputs ("in modstatic2.c (test)\n", out);

  void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY);
  if (handle == NULL)
    fprintf (out, "nonexistent: %s\n", dlerror ());
  else
    exit (1);

  handle = dlopen ("modstatic2.so", RTLD_LAZY);
  if (handle == NULL)
    {
      fprintf (out, "%s\n", dlerror ());
      exit (1);
    }

  int (*test2) (FILE *, int);
  test2 = dlsym (handle, "test");
  if (test2 == NULL)
    {
      fprintf (out, "%s\n", dlerror ());
      exit (1);
    }
  if (test2 != test)
    {
      fprintf (out, "test %p != test2 %p\n", test, test2);
      exit (1);
    }

  Dl_info info;
  int res = dladdr (test2, &info);
  if (res == 0)
    {
      fputs ("dladdr returned 0\n", out);
      exit (1);
    }
  else
    {
      if (strstr (info.dli_fname, "modstatic2.so") == NULL
	  || strcmp (info.dli_sname, "test") != 0)
	{
	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
	  exit (1);
	}
      if (info.dli_saddr != (void *) test2)
	{
	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
	  exit (1);
	}
    }

  ElfW(Sym) *sym;
  void *symp;
  res = dladdr1 (test2, &info, &symp, RTLD_DL_SYMENT);
  if (res == 0)
    {
      fputs ("dladdr1 returned 0\n", out);
      exit (1);
    }
  else
    {
      if (strstr (info.dli_fname, "modstatic2.so") == NULL
	  || strcmp (info.dli_sname, "test") != 0)
	{
	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
	  exit (1);
	}
      if (info.dli_saddr != (void *) test2)
	{
	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
	  exit (1);
	}
      sym = symp;
      if (sym == NULL)
	{
	  fputs ("sym == NULL\n", out);
	  exit (1);
	}
      if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
	{
	  fprintf (out, "bind %d visibility %d\n",
		   (int) ELF32_ST_BIND (sym->st_info),
		   (int) ELF32_ST_VISIBILITY (sym->st_other));
	  exit (1);
	}
    }

  Lmid_t lmid;
  res = dlinfo (handle, RTLD_DI_LMID, &lmid);
  if (res != 0)
    {
      fprintf (out, "dlinfo returned %d %s\n", res, dlerror ());
      exit (1);
    }
  else if (lmid != LM_ID_BASE)
    {
      fprintf (out, "lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE);
      exit (1);
    }

  void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY);
  if (handle2 == NULL)
    {
      fprintf (out, "libdl.so: %s\n", dlerror ());
      exit (1);
    }

#ifdef DO_VERSIONING
  if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL)
    {
      fprintf (out, "dlvsym: %s\n", dlerror ());
      exit (1);
    }
#endif

  void *(*dlsymfn) (void *, const char *);
  dlsymfn = dlsym (handle2, "dlsym");
  if (dlsymfn == NULL)
    {
      fprintf (out, "dlsym \"dlsym\": %s\n", dlerror ());
      exit (1);
    }
  void *test3 = dlsymfn (handle, "test");
  if (test3 == NULL)
    {
      fprintf (out, "%s\n", dlerror ());
      exit (1);
    }
  else if (test3 != (void *) test2)
    {
      fprintf (out, "test2 %p != test3 %p\n", test2, test3);
      exit (1);
    }

  dlclose (handle2);
  dlclose (handle);

  handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY);
  if (handle == NULL)
    {
      fprintf (out, "%s\n", dlerror ());
      exit (1);
    }
  dlclose (handle);

  handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY);
  if (handle == NULL)
    fprintf (out, "LM_ID_NEWLM: %s\n", dlerror ());
  else
    {
      fputs ("LM_ID_NEWLM unexpectedly succeeded\n", out);
      exit (1);
    }

  handle = dlopen ("modstatic.so", RTLD_LAZY);
  if (handle == NULL)
    {
      fprintf (out, "%s\n", dlerror ());
      exit (1);
    }

  int (*test4) (int);
  test4 = dlsym (handle, "test");
  if (test4 == NULL)
    {
      fprintf (out, "%s\n", dlerror ());
      exit (1);
    }

  res = test4 (16);
  if (res != 16 + 16)
    {
      fprintf (out, "modstatic.so (test) returned %d\n", res);
      exit (1);
    }

  res = dladdr1 (test4, &info, &symp, RTLD_DL_SYMENT);
  if (res == 0)
    {
      fputs ("dladdr1 returned 0\n", out);
      exit (1);
    }
  else
    {
      if (strstr (info.dli_fname, "modstatic.so") == NULL
	  || strcmp (info.dli_sname, "test") != 0)
	{
	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
	  exit (1);
	}
      if (info.dli_saddr != (void *) test4)
	{
	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test4);
	  exit (1);
	}
      sym = symp;
      if (sym == NULL)
	{
	  fputs ("sym == NULL\n", out);
	  exit (1);
	}
      if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
	{
	  fprintf (out, "bind %d visibility %d\n",
		   (int) ELF32_ST_BIND (sym->st_info),
		   (int) ELF32_ST_VISIBILITY (sym->st_other));
	  exit (1);
	}
    }

  dlclose (handle);

  fputs ("leaving modstatic2.c (test)\n", out);
  return a + a;
}