libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libunwind] Basic use of dynamic features?


From: Tommy Hoffner
Subject: Re: [libunwind] Basic use of dynamic features?
Date: Tue, 14 Dec 2004 17:15:23 +0100
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040421

David Mosberger wrote:

Hi Tommy,


On Thu, 02 Dec 2004 17:30:42 +0100, Tommy Hoffner <address@hidden> said:


  Tommy> Generalizing my test (e.g. removing UNW_LOCAL_ONLY and having
  Tommy> a stackunwinder present in the code) forced me to link
  Tommy> against libunwind-ia64, which in turn made my initial test
  Tommy> fail (it only registers dynamically created unwind-info and
  Tommy> uses throw and catch).  As I understood it UNW_LOCAL_ONLY
  Tommy> limits the functionality to a pure subset of what you get
  Tommy> otherwise.

Yes, that's definitely the intent.

  Tommy> I also thought that using the same functionality in
  Tommy> libunwind.so and libunwind-ia64.so would give me the same
  Tommy> results as long as I'm only using the "local"
  Tommy> functionality. Have I missinterpreted something basic here?

Nope.  It sounds like you may have run into a bug.  Definitely try
0.98 first, though.  Many bugs have been fixed since 0.97.

  Tommy> And yes, I can live with UNW_LOCAL_ONLY for my basic
  Tommy> functionality but looking at writing my own stackdump
  Tommy> function seems to force me to use remote features.  If I want
  Tommy> to write my own stackdump function that I could call from the
  Tommy> commandline in a debugger. I therefor need to get some kind
  Tommy> of reference to the stack I want to dump. Calling a function
  Tommy> from the command line in the debugger makes the calling
  Tommy> function to be placed on another callstack than the
  Tommy> application I want to debug. I'm not shure on exactly how it
  Tommy> is implemented but functions like this can access the
  Tommy> applicatons data so I assume the correlation between them
  Tommy> (called function and the application I'm debugging) could be
  Tommy> viewed as two threads (same data, different stacks).  Do I
  Tommy> need remote functionality to be able to access another
  Tommy> threads callstack (whitout it doing things like
  Tommy> unw_local_init itself)?  Any tips on how to do it?

I'm not sure I'm following completely here (it's late, what can I say...).

If removing UNW_LOCAL_ONLY still doesn't work with libunwind v0.98.3,
any chance you could provide a minimal test-case that demonstrates the
problem?  That would help immensely.
Ok, I tried 0.98.3 from debian. Now the UNW_LOCAL_ONLY doesn't work either :-)

First, it seems to me that you now have to link statically to get _U_dyn_register and _U_dyn_cancel. It links towards libunwind.so.7 as well. Is this the intended behaviour?

I've tried numerous combinations of compilers (Ecc, gcc-3.3 and gcc-3.4) and libraris (libstdc++5 and lidstdc++6)). When using libunwind 0.97, all combinations works for UNW_LOCAL_ONLY, but when changing to 0.98.3 no cobination works (i.e. the c++ stack unwinder does not recognize the dynamically created unwind info.)

I'm attaching a modified testcase from your suite. (The commented function was what I was trying to do when a wrote the first contribution to this thread)

/Tommy

Thanks,

        --david

#CXX=icpc -gcc-name=gcc-3.4
#CC=icpc -gcc-name=gcc-3.4
#AS=ias
#LDFLAGS=-L/usr/lib -lunwind

CXX=g++-3.4
CC=g++-3.4
#AS=gas

CXXFLAGS=-O0 -g

jitunw: jitunw.o flush-cache.o /usr/lib/libunwind.a


clean:
        rm jitunw jitunw.o flush-cache.o
/* libunwind - a platform-independent unwind library
   Copyright (C) 2002-2003 Hewlett-Packard Co
        Contributed by David Mosberger-Tang <address@hidden>

This file is part of libunwind.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */

/* This file tests dynamic code-generation via function-cloning.  */

#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/mman.h>

#define panic(args...)                          \
        { fprintf (stderr, args); exit (-1); }

// void where_mlu(int max) {
//   unw_cursor_t cursor;
//   char name[128], off[32];
//   unw_word_t ip, offset;
//   unw_context_t uc;
//   int count = 0;
//   int as;

//   unw_getcontext (&uc);
//   //  unw_init_local (&cursor, &uc);
//   as = unw_init_remote(&cursor, unw_local_addr_space, &uc);
//   fprintf (stderr, "unw_create_addr_space() failed. Error %d\n",as);

//   do
//     {
//       unw_get_reg (&cursor, UNW_REG_IP, &ip);
//       name[0] = '\0';
//       off[0] = '\0';
//       if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0
//        && off > 0)
//      snprintf (off, sizeof (off), "+0x%lx", (long) offset);
//       printf ("ip = %lx <%s%s>\n", (long) ip, name, off);
//       ++count;
//     }
//   while ((count<=max) & (unw_step (&cursor) > 0));
// }

typedef void (*thrower_t) ();
typedef void (*template_t) (void (*)());

struct fdesc
  {
    long code;
    long gp;
  };
# define get_fdesc(fdesc,func)  (fdesc = *(struct fdesc *) &(func))
# define get_funcp(fdesc)       ((template_t) &(fdesc))
# define get_gp(fdesc)          ((fdesc).gp)

extern "C" void flush_cache (void *addr, size_t len);

// This is the C++ code that is called by the "JITed" code
void thrower ()
{
  //  where_mlu(10);
   throw("Throw");
}

// This is the master that is used for "generating" the "JITed" code
// The reason the thrower isn't called directly is to increase the
// chance that the code doesn't needs relocation

void template_func (thrower_t func)
{
  (*func)();
}

int
main (int argc, char *argv[])
{
  unw_dyn_region_info_t *region;
  unw_dyn_info_t di;
  struct fdesc fdesc;
  template_t funcp;
  void *mem;
  int length = getpagesize();
  int no_jit=0;

  fprintf(stderr,"pagesize %d\n",length );

  if (argc > 1)
    no_jit++;

  // Fake JITed code
  mem = malloc (length);
  get_fdesc (fdesc, template_func);
  memcpy (mem, (void *) fdesc.code, 200);
  mprotect ((void *) ((long) mem & ~(getpagesize () - 1)),
            2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);
  flush_cache (mem, length);

  // register the "JITed" function:
  // These fields and values are just an example from Mosberger's
  // testcases that seems to be sufficient for this test. It is not 
  // a definite selection of what we want to set.
  region = static_cast<unw_dyn_region_info_t*> (alloca (_U_dyn_region_info_size 
(2)));
  region->next = NULL;
  region->insn_count = 256;
  region->op_count = 2;
  _U_dyn_op_alias (&region->op[0], 0, -1, fdesc.code);
  _U_dyn_op_stop (&region->op[1]);

  memset (&di, 0, sizeof (di));
  di.start_ip = (long) mem;
  di.end_ip = (long) mem + 16*region->insn_count/3;
  di.gp = get_gp (fdesc);
  di.format = UNW_INFO_FORMAT_DYNAMIC;
  di.u.pi.name_ptr = (unw_word_t) "copy_of_template";
  di.u.pi.regions = region;

  _U_dyn_register (&di);

  /* call "JITed" function: */
  fdesc.code = (long) mem;
  funcp = get_funcp (fdesc);

  try {
    if (no_jit)
      template_func(thrower);
    else
      (*funcp) (thrower);
  }
  catch (const char *p) {
    printf("SUCCESS! (Caught %s)\n\n",p);
  }
  
  _U_dyn_cancel (&di);
  return -1;
}
        .global flush_cache

        .proc flush_cache
flush_cache:
        .prologue
        alloc r2=ar.pfs,2,0,0,0
        add r8=31,in1                   // round up to 32 byte-boundary
        ;;
        shr.u r8=r8,5                   // we flush 32 bytes per iteration
        ;;
        add r8=-1,r8
        .save ar.lc, r3
        mov r3=ar.lc                    // save ar.lc
        ;;
        .body

        mov ar.lc=r8
        ;;
.loop:  fc in0                          // issuable on M0 only
        add in0=32,in0
        br.cloop.sptk.few .loop
        ;;
        sync.i
        ;;
        srlz.i
        ;;
        mov ar.lc=r3                    // restore ar.lc
        br.ret.sptk.many rp
        .endp flush_cache


reply via email to

[Prev in Thread] Current Thread [Next in Thread]