Fix instrumentation regressions for libc-2.29 on ARM (#653)
[dyninst.git] / dyninstAPI_RT / src / RTlinux.c
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  *
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  *
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 /************************************************************************
32  * $Id: RTlinux.c,v 1.54 2008/04/11 23:30:44 legendre Exp $
33  * RTlinux.c: mutatee-side library function specific to Linux
34  ************************************************************************/
35
36 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
37 #include "dyninstAPI_RT/src/RTthread.h"
38 #include "dyninstAPI_RT/src/RTcommon.h"
39 #include <assert.h>
40 #include <stdio.h>
41 #include <errno.h>
42 #include <unistd.h>
43
44 #if !defined(DYNINST_RT_STATIC_LIB)
45 #include <dlfcn.h>
46 #endif
47
48 #include <sys/types.h>
49 #include <sys/syscall.h>
50 #include <string.h>
51 #include <errno.h>
52 #include <signal.h>
53 #include <sys/mman.h>
54 #include <link.h>
55
56 #if defined(DYNINST_RT_STATIC_LIB)
57 /*
58  * The weak symbol here removes the dependence of the static version of this
59  * library on pthread_self. If pthread_self is available, then it will be
60  * linked.  Otherwise, the linker will ignore it.
61  */
62 #pragma weak pthread_self
63 extern pthread_t pthread_self(void);
64 #else
65 #include <pthread.h>
66 #endif
67
68 extern double DYNINSTstaticHeap_512K_lowmemHeap_1[];
69 extern double DYNINSTstaticHeap_16M_anyHeap_1[];
70 extern unsigned long sizeOfLowMemHeap1;
71 extern unsigned long sizeOfAnyHeap1;
72
73 static struct trap_mapping_header *getStaticTrapMap(unsigned long addr);
74
75 #if defined(arch_power) && defined(arch_64bit) && defined(os_linux)
76 unsigned long DYNINSTlinkSave;
77 unsigned long DYNINSTtocSave;
78 #endif
79
80 /************************************************************************
81  * void DYNINSTbreakPoint(void)
82  *
83  * stop oneself.
84 ************************************************************************/
85
86 #ifndef SYS_tkill
87 #define SYS_tkill 238
88 #endif
89
90 int t_kill(int pid, int sig) {
91     static int has_tkill = 1;
92     long int result = 0;
93     if (has_tkill) {
94         result = syscall(SYS_tkill, pid, sig);
95         if (result == -1 && errno == ENOSYS) {
96             has_tkill = 0;
97         }
98     }
99     if (!has_tkill) {
100         result = kill(pid, sig);
101     }
102
103     return (result == 0);
104 }
105
106 void DYNINSTbreakPoint()
107 {
108    if (DYNINSTstaticMode)
109       return;
110    // Call into a funtion that contains a 
111    // trap instruction. 
112    DYNINSTtrapFunction();
113 }
114
115 static int failed_breakpoint = 0;
116 void uncaught_breakpoint(int sig)
117 {
118    (void)sig; /* unused parameter */
119    failed_breakpoint = 1;
120 }
121
122 void DYNINSTsafeBreakPoint()
123 {
124    if (DYNINSTstaticMode)
125       return;
126
127     DYNINST_break_point_event = 2; /* Not the same as above */
128     //    while (DYNINST_break_point_event)
129     kill(dyn_lwp_self(), SIGSTOP);
130 }
131
132 void mark_heaps_exec() {
133         /* Grab the page size, to align the heap pointer. */
134         long int pageSize = sysconf( _SC_PAGESIZE );
135         if( pageSize == 0 || pageSize == - 1 ) {
136                 fprintf( stderr, "*** Failed to obtain page size, guessing 16K.\n" );
137                 perror( "mark_heaps_exec" );
138                 pageSize = 1024 * 16;
139                 } /* end pageSize initialization */
140
141         /* Align the heap pointer. */
142         unsigned long int alignedHeapPointer = (unsigned long int) DYNINSTstaticHeap_16M_anyHeap_1;
143         alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
144         unsigned long int adjustedSize = (unsigned long int) DYNINSTstaticHeap_16M_anyHeap_1 - alignedHeapPointer + sizeOfAnyHeap1;
145
146         /* Make the heap's page executable. */
147         int result = mprotect( (void *) alignedHeapPointer, (size_t) adjustedSize, PROT_READ | PROT_WRITE | PROT_EXEC );
148         if( result != 0 ) {
149                 fprintf( stderr, "%s[%d]: Couldn't make DYNINSTstaticHeap_16M_anyHeap_1 executable!\n", __FILE__, __LINE__);
150                 perror( "mark_heaps_exec" );
151                 }
152         RTprintf( "*** Marked memory from 0x%lx to 0x%lx executable.\n", alignedHeapPointer, alignedHeapPointer + adjustedSize );
153
154         /* Mark _both_ heaps executable. */
155         alignedHeapPointer = (unsigned long int) DYNINSTstaticHeap_512K_lowmemHeap_1;
156         alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
157         adjustedSize = (unsigned long int) DYNINSTstaticHeap_512K_lowmemHeap_1 - alignedHeapPointer + sizeOfLowMemHeap1;
158
159         /* Make the heap's page executable. */
160         result = mprotect( (void *) alignedHeapPointer, (size_t) adjustedSize, PROT_READ | PROT_WRITE | PROT_EXEC );
161         if( result != 0 ) {
162                 fprintf( stderr, "%s[%d]: Couldn't make DYNINSTstaticHeap_512K_lowmemHeap_1 executable!\n", __FILE__, __LINE__ );
163                 perror( "mark_heaps_exec" );
164                 }
165         RTprintf( "*** Marked memory from 0x%lx to 0x%lx executable.\n", alignedHeapPointer, alignedHeapPointer + adjustedSize );
166         } /* end mark_heaps_exec() */
167
168 /************************************************************************
169  * void DYNINSTos_init(void)
170  *
171  * OS initialization function
172 ************************************************************************/
173 int DYNINST_sysEntry;
174
175 #if !defined(DYNINST_RT_STATIC_LIB)
176 /*
177  * For now, removing dependence of static version of this library
178  * on libdl.
179  */
180 typedef struct dlopen_args {
181   const char *libname;
182   int mode;
183   void *result;
184   void *caller;
185 } dlopen_args_t;
186
187 void *(*DYNINST_do_dlopen)(dlopen_args_t *) = NULL;
188
189 static int get_dlopen_error() {
190    char *err_str;
191    err_str = dlerror();
192    if (err_str) {
193       strncpy(gLoadLibraryErrorString, err_str, (size_t) ERROR_STRING_LENGTH);
194       return 1;
195    }
196    else {
197       sprintf(gLoadLibraryErrorString,"unknown error with dlopen");
198       return 0;
199    }
200    return 0;
201 }
202
203 int DYNINSTloadLibrary(char *libname)
204 {
205    void *res;
206    gLoadLibraryErrorString[0]='\0';
207    res = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
208    if (res)
209    {
210       return 1;
211    }
212
213    get_dlopen_error();
214 #if defined(arch_x86)
215    /* dlopen on recent glibcs has a "security check" so that
216       only registered modules can call it. Unfortunately, progs
217       that don't include libdl break this check, so that we
218       can only call _dl_open (the dlopen worker function) from
219       within glibc. We do this by calling do_dlopen
220       We fool this check by calling an addr written by the
221       mutator */
222    if (strstr(gLoadLibraryErrorString, "invalid caller") != NULL &&
223        DYNINST_do_dlopen != NULL) {
224       dlopen_args_t args;
225       args.libname = libname;
226       args.mode = RTLD_NOW | RTLD_GLOBAL;
227       args.result = 0;
228       args.caller = (void *)DYNINST_do_dlopen;
229       // There's a do_dlopen function in glibc. However, it's _not_
230       // exported; thus, getting the address is a bit of a pain.
231
232       (*DYNINST_do_dlopen)(&args);
233       // Duplicate the above
234       if (args.result != NULL)
235       {
236          return 1;
237       }
238       else
239          get_dlopen_error();
240    }
241 #endif
242    return 0;
243 }
244 #endif
245
246 //Define this value so that we can compile on a system that doesn't have
247 // gettid and still run on one that does.
248 #if !defined(SYS_gettid)
249
250 #if defined(arch_x86)
251 #define SYS_gettid 224
252 #elif defined(arch_x86_64)
253 #define SYS_gettid 186
254 #endif
255
256 #endif
257
258 int dyn_lwp_self()
259 {
260    static int gettid_not_valid = 0;
261    int result;
262
263    if (gettid_not_valid)
264       return getpid();
265
266    result = syscall((long int) SYS_gettid);
267    if (result == -1 && errno == ENOSYS)
268    {
269       gettid_not_valid = 1;
270       return getpid();
271    }
272    return result;
273 }
274
275 int dyn_pid_self()
276 {
277    return getpid();
278 }
279
280 dyntid_t (*DYNINST_pthread_self)(void);
281
282 dyntid_t dyn_pthread_self()
283 {
284    dyntid_t me;
285    if (DYNINSTstaticMode) {
286 #if defined(DYNINST_RT_STATIC_LIB)
287        /* This special case is necessary because the static
288         * version of libc doesn't define a version of pthread_self
289         * unlike the shared version of the library.
290         */
291        if( !pthread_self ) {
292            return (dyntid_t) DYNINST_SINGLETHREADED;
293        }
294 #endif
295       return (dyntid_t) pthread_self();
296    }
297    if (!DYNINST_pthread_self) {
298       return (dyntid_t) DYNINST_SINGLETHREADED;
299    }
300    me = (*DYNINST_pthread_self)();
301    return (dyntid_t) me;
302 }
303
304 /*
305    We reserve index 0 for the initial thread. This value varies by
306    platform but is always constant for that platform. Wrap that
307    platform-ness here.
308 */
309 int DYNINST_am_initial_thread( dyntid_t tid ) {
310         (void)tid; /* unused parameter */
311         if( dyn_lwp_self() == getpid() ) {
312                 return 1;
313    }
314         return 0;
315 } /* end DYNINST_am_initial_thread() */
316
317 #if defined(cap_mutatee_traps)
318
319 #include <ucontext.h>
320
321 // Register numbers experimentally verified
322
323 #if defined(arch_x86)
324   #define UC_PC(x) x->uc_mcontext.gregs[14]
325 #elif defined(arch_x86_64)
326   #if defined(MUTATEE_32)
327     #define UC_PC(x) x->uc_mcontext.gregs[14]
328   #else // 64-bit
329     #define UC_PC(x) x->uc_mcontext.gregs[16]
330   #endif // amd-64
331 #elif defined(arch_power)
332   #if defined(arch_64bit)
333     #define UC_PC(x) x->uc_mcontext.regs->gpr[32]
334   #else // 32-bit
335     #define UC_PC(x) x->uc_mcontext.uc_regs->gregs[32]
336   #endif // power
337 #elif defined(arch_aarch64)
338         //#warning "UC_PC: in aarch64, pc is not directly accessable."
339         //aarch64 pc is not one of 31 GPRs, but an independent reg
340         #define UC_PC(x) x->uc_mcontext.pc
341 #endif // UC_PC
342
343 extern volatile unsigned long dyninstTrapTableUsed;
344 extern volatile unsigned long dyninstTrapTableVersion;
345 extern volatile trapMapping_t *dyninstTrapTable;
346 extern volatile unsigned long dyninstTrapTableIsSorted;
347
348 /**
349  * This comment is now obsolete, left for historic purposes
350  *
351  * Called by the SIGTRAP handler, dyninstTrapHandler.  This function is
352  * closly intwined with dyninstTrapHandler, don't modify one without
353  * understanding the other.
354  *
355  * This function sets up the calling context that was passed to the
356  * SIGTRAP handler so that control will be redirected to our instrumentation
357  * when we do the setcontext call.
358  *
359  * There are a couple things that make this more difficult than it should be:
360  *   1. The OS provided calling context is similar to the GLIBC calling context,
361  *      but not compatible.  We'll create a new GLIBC compatible context and
362  *      copy the possibly stomped registers from the OS context into it.  The
363  *      incompatiblities seem to deal with FP and other special purpose registers.
364  *   2. setcontext doesn't restore the flags register.  Thus dyninstTrapHandler
365  *      will save the flags register first thing and pass us its value in the
366  *      flags parameter.  We'll then push the instrumentation entry and flags
367  *      onto the context's stack.  Instead of transfering control straight to the
368  *      instrumentation, we'll actually go back to dyninstTrapHandler, which will
369  *      do a popf/ret to restore flags and go to instrumentation.  The 'retPoint'
370  *      parameter is the address in dyninstTrapHandler the popf/ret can be found.
371  **/
372
373 void dyninstTrapHandler(int sig, siginfo_t *sg, ucontext_t *context)
374 {
375    void *orig_ip;
376    void *trap_to;
377    (void)sig; /* unused parameter */
378    (void)sg; /* unused parameter */
379
380    orig_ip = (void *) UC_PC(context);
381    assert(orig_ip);
382    // Find the new IP we're going to and substitute. Leave everything else untouched.
383    if (DYNINSTstaticMode) {
384       unsigned long zero = 0;
385       unsigned long one = 1;
386       struct trap_mapping_header *hdr = getStaticTrapMap((unsigned long) orig_ip);
387       assert(hdr);
388       volatile trapMapping_t *mapping = &(hdr->traps[0]);
389       trap_to = dyninstTrapTranslate(orig_ip,
390                                      (unsigned long *) &hdr->num_entries,
391                                      &zero,
392                                      &mapping,
393                                      &one);
394    }
395    else {
396       trap_to = dyninstTrapTranslate(orig_ip,
397                                      &dyninstTrapTableUsed,
398                                      &dyninstTrapTableVersion,
399                                      &dyninstTrapTable,
400                                      &dyninstTrapTableIsSorted);
401
402    }
403    UC_PC(context) = (long) trap_to;
404 }
405
406 #if defined(cap_binary_rewriter)
407
408 extern struct r_debug _r_debug;
409 DLLEXPORT struct r_debug _r_debug __attribute__ ((weak));
410
411 /* Verify that the r_debug variable is visible */
412 void r_debugCheck() { assert(_r_debug.r_map); }
413
414 #define NUM_LIBRARIES 512 //Important, max number of rewritten libraries
415
416 #define WORD_SIZE (8 * sizeof(unsigned))
417 #define NUM_LIBRARIES_BITMASK_SIZE (1 + NUM_LIBRARIES / WORD_SIZE)
418 struct trap_mapping_header *all_headers[NUM_LIBRARIES];
419
420 static unsigned all_headers_current[NUM_LIBRARIES_BITMASK_SIZE];
421 static unsigned all_headers_last[NUM_LIBRARIES_BITMASK_SIZE];
422
423 #if !defined(arch_x86_64) || defined(MUTATEE_32)
424 typedef Elf32_Dyn ElfX_Dyn;
425 #else
426 typedef Elf64_Dyn ElfX_Dyn;
427 #endif
428
429 struct trap_mapping_header *getStaticTrapMap(unsigned long addr);
430
431 static int parse_libs();
432 static int parse_link_map(struct link_map *l);
433 static void clear_unloaded_libs();
434
435 static void set_bit(unsigned *bit_mask, int bit, char value);
436 //static char get_bit(unsigned *bit_mask, int bit);
437 static void clear_bitmask(unsigned *bit_mask);
438 static unsigned get_next_free_bitmask(unsigned *bit_mask, int last_pos);
439 static unsigned get_next_set_bitmask(unsigned *bit_mask, int last_pos);
440
441 static tc_lock_t trap_mapping_lock;
442
443 static struct trap_mapping_header *getStaticTrapMap(unsigned long addr)
444 {
445 #if !defined (arch_aarch64)
446    struct trap_mapping_header *header;
447    int i;
448
449    tc_lock_lock(&trap_mapping_lock);
450    parse_libs();
451
452    i = -1;
453    for (;;) {
454       i = get_next_set_bitmask(all_headers_current, i);
455       assert(i >= 0 && i <= NUM_LIBRARIES);
456       if (i == NUM_LIBRARIES) {
457          header = NULL;
458          rtdebug_printf("%s[%d]:  getStaticTrapMap: returning NULL\n", __FILE__, __LINE__);
459          goto done;
460       }
461       header = all_headers[i];
462       if (addr >= header->low_entry && addr <= header->high_entry) {
463          goto done;
464       }
465    }
466  done:
467    tc_lock_unlock(&trap_mapping_lock);
468    return header;
469 #else
470         assert(0);
471         return NULL;
472 #endif
473 }
474
475 static int parse_libs()
476 {
477    struct link_map *l_current;
478
479    l_current = _r_debug.r_map;
480    if (!l_current) {
481         rtdebug_printf("%s[%d]:  parse_libs: _r_debug.r_map was not set\n", __FILE__, __LINE__);
482        return -1;
483    }
484
485    clear_bitmask(all_headers_current);
486    while (l_current) {
487       parse_link_map(l_current);
488       l_current = l_current->l_next;
489    }
490    clear_unloaded_libs();
491
492    return 0;
493 }
494
495 //parse_link_map return values
496 #define PARSED 0
497 #define NOT_REWRITTEN 1
498 #define ALREADY_PARSED 2
499 #define ERROR_INTERNAL -1
500 #define ERROR_FULL -2
501 static int parse_link_map(struct link_map *l)
502 {
503    ElfX_Dyn *dynamic_ptr;
504    struct trap_mapping_header *header;
505    unsigned int i, new_pos;
506
507    dynamic_ptr = (ElfX_Dyn *) l->l_ld;
508    if (!dynamic_ptr)
509       return -1;
510
511    assert(sizeof(dynamic_ptr->d_un.d_ptr) == sizeof(void *));
512    for (; dynamic_ptr->d_tag != DT_NULL && dynamic_ptr->d_tag != DT_DYNINST; dynamic_ptr++);
513    if (dynamic_ptr->d_tag == DT_NULL) {
514       return NOT_REWRITTEN;
515    }
516
517    header = (struct trap_mapping_header *) (dynamic_ptr->d_un.d_val + l->l_addr);
518
519    if (header->signature != TRAP_HEADER_SIG)
520       return ERROR_INTERNAL;
521    if (header->pos != -1) {
522       set_bit(all_headers_current, header->pos, 1);
523       assert(all_headers[header->pos] == header);
524       return ALREADY_PARSED;
525    }
526
527    for (i = 0; i < header->num_entries; i++)
528    {
529       header->traps[i].source = (void *) (((unsigned long) header->traps[i].source) + l->l_addr);
530       header->traps[i].target = (void *) (((unsigned long) header->traps[i].target) + l->l_addr);
531       if (!header->low_entry || header->low_entry > (unsigned long) header->traps[i].source)
532          header->low_entry = (unsigned long) header->traps[i].source;
533       if (!header->high_entry || header->high_entry < (unsigned long) header->traps[i].source)
534          header->high_entry = (unsigned long) header->traps[i].source;
535    }
536
537    new_pos = get_next_free_bitmask(all_headers_last, -1);
538    assert(new_pos < NUM_LIBRARIES);
539    if (new_pos == NUM_LIBRARIES)
540       return ERROR_FULL;
541
542    header->pos = new_pos;
543    all_headers[new_pos] = header;
544    set_bit(all_headers_current, new_pos, 1);
545    set_bit(all_headers_last, new_pos, 1);
546
547    return PARSED;
548 }
549
550 static void clear_unloaded_libs()
551 {
552    unsigned i;
553    for (i = 0; i<NUM_LIBRARIES_BITMASK_SIZE; i++)
554    {
555       all_headers_last[i] = all_headers_current[i];
556    }
557 }
558
559 static void set_bit(unsigned *bit_mask, int bit, char value) {
560    assert(bit < NUM_LIBRARIES);
561    unsigned *word = bit_mask + bit / WORD_SIZE;
562    unsigned shift = bit % WORD_SIZE;
563    if (value) {
564       *word |= (1 << shift);
565    }
566    else {
567       *word &= ~(1 << shift);
568    }
569 }
570
571 //Wasn't actually needed
572 /*
573 static char get_bit(unsigned *bit_mask, int bit) {
574    assert(bit < NUM_LIBRARIES);
575    unsigned *word = bit_mask + bit / WORD_SIZE;
576    unsigned shift = bit % WORD_SIZE;
577    return (*word & (1 << shift)) ? 1 : 0;
578 }
579 */
580
581 static void clear_bitmask(unsigned *bit_mask) {
582    unsigned i;
583    for (i = 0; i < NUM_LIBRARIES_BITMASK_SIZE; i++) {
584       bit_mask[i] = 0;
585    }
586 }
587
588 static unsigned get_next_free_bitmask(unsigned *bit_mask, int last_pos) {
589    unsigned i, j;
590    j = last_pos+1;
591    i = j / WORD_SIZE;
592    for (; j < NUM_LIBRARIES; i++) {
593       if (bit_mask[i] == (unsigned) -1) {
594          j += WORD_SIZE;
595          continue;
596       }
597       for (;;) {
598          if (!((1 << (j % WORD_SIZE) & bit_mask[i]))) {
599             return j;
600          }
601          j++;
602          if (j % WORD_SIZE == 0) {
603             break;
604          }
605       }
606    }
607    return NUM_LIBRARIES;
608 }
609
610 static unsigned get_next_set_bitmask(unsigned *bit_mask, int last_pos) {
611    unsigned i, j;
612    j = last_pos+1;
613    i = j / WORD_SIZE;
614    for (; j < NUM_LIBRARIES; i++) {
615       if (bit_mask[i] == (unsigned) 0) {
616          j += WORD_SIZE;
617          continue;
618       }
619       for (;;) {
620          if ((1 << (j % WORD_SIZE) & bit_mask[i])) {
621             return j;
622          }
623          j++;
624          if (j % WORD_SIZE == 0) {
625             break;
626          }
627       }
628    }
629    return NUM_LIBRARIES;
630 }
631
632 #endif
633
634
635
636 #endif /* cap_mutatee_traps */
637
638 #if defined(cap_binary_rewriter) && !defined(DYNINST_RT_STATIC_LIB)
639 /* For a static binary, all global constructors are combined in an undefined
640  * order. Also, DYNINSTBaseInit must be run after all global constructors have
641  * been run. Since the order of global constructors is undefined, DYNINSTBaseInit
642  * cannot be run as a constructor in static binaries. Instead, it is run from a
643  * special constructor handler that processes all the global constructors in
644  * the binary. Leaving this code in would create a global constructor for the
645  * function runDYNINSTBaseInit(). See DYNINSTglobal_ctors_handler.
646  */
647 extern void r_debugCheck();
648 extern void DYNINSTBaseInit();
649 void runDYNINSTBaseInit() __attribute__((constructor));
650 void runDYNINSTBaseInit()
651 {
652     r_debugCheck();
653    DYNINSTBaseInit();
654 }
655 #endif
656
657
658 /*
659 //Small program for finding the correct values to fill in pos_in_pthreadt
660 // above
661 #include <pthread.h>
662 #include <stdio.h>
663 #include <sys/syscall.h>
664 #include <sys/types.h>
665 #include <unistd.h>
666
667 #define gettid() syscall(SYS_gettid)
668
669 pthread_attr_t attr;
670
671 void *foo(void *f) {
672   pid_t pid, tid;
673   unsigned stack_addr;
674   unsigned best_stack = 0xffffffff;
675   int best_stack_pos = 0;
676   void *start_func;
677   int *p;
678   int i = 0;
679   pid = getpid();
680   tid = gettid();
681   start_func = foo;
682   //x86 only.
683   asm("movl %%ebp,%0" : "=r" (stack_addr));
684   p = (int *) pthread_self();
685   while (i < 1000)
686   {
687     if (*p == (unsigned) pid)
688       printf("pid @ %d\n", i);
689     if (*p == (unsigned) tid)
690       printf("lwp @ %d\n", i);
691     if (*p > stack_addr && *p < best_stack)
692     {
693       best_stack = *p;
694       best_stack_pos = i;
695     }
696     if (*p == (unsigned) start_func)
697       printf("func @ %d\n", i);
698     i += sizeof(int);
699     p++;
700   }
701   printf("stack @ %d\n", best_stack_pos);
702   return NULL;
703 }
704
705 int main(int argc, char *argv[])
706 {
707   pthread_t t;
708   void *result;
709   pthread_attr_init(&attr);
710   pthread_create(&t, &attr, foo, NULL);
711   pthread_join(t, &result);
712   return 0;
713 }
714 */
715