add prof2 profiler
authorGood Guy <[email protected]>
Wed, 3 Jul 2019 17:11:05 +0000 (11:11 -0600)
committerGood Guy <[email protected]>
Wed, 3 Jul 2019 17:11:05 +0000 (11:11 -0600)
cinelerra-5.1/cinelerra/performanceprefs.C
cinelerra-5.1/plugins/histeq/.gdb_history [deleted file]
cinelerra-5.1/prof2/Makefile [new file with mode: 0644]
cinelerra-5.1/prof2/mksignalent [new file with mode: 0755]
cinelerra-5.1/prof2/mksyscallent [new file with mode: 0755]
cinelerra-5.1/prof2/prof.c [new file with mode: 0644]
cinelerra-5.1/prof2/profile.c [new file with mode: 0644]
cinelerra-5.1/prof2/smap.C [new file with mode: 0644]
cinelerra-5.1/prof2/tst.c [new file with mode: 0644]

index c00ca7324229154137a65d500027cc5744e04a42..dbeee00423c53e83f48f7b296f2e91a7c526eade 100644 (file)
@@ -332,8 +332,8 @@ PrefsUseHWDev::PrefsUseHWDev(PreferencesWindow *pwindow,
 void PrefsUseHWDev::create_objects()
 {
        BC_PopupTextBox::create_objects();
-       set_tooltip(_("vdpau - Nvidia, Nouveau, Amdgpu\n"
-               "vaapi - Broadcom, Intel HD graphics, Radeon\n"
+       set_tooltip(_("vdpau - Nvidia, Nouveau\n"
+               "vaapi - Broadcom, Intel HD graphics, Amdgup, Radeon\n"
                "cuda  - Nvidia + Cuda SDK"));
        hw_dev_names.append(new BC_ListBoxItem(_("none")));
 #ifdef HAVE_VAAPI
diff --git a/cinelerra-5.1/plugins/histeq/.gdb_history b/cinelerra-5.1/plugins/histeq/.gdb_history
deleted file mode 100644 (file)
index ee24cbc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-p /x 0xff*3
-p /x 0xff*3 * 0x55
-p /x 0xff*3 * 0x57
-p /x 0xff*3 * 0x56
-p /x 0x5555*3
-p /x 0xff*3 * 0x5555
-p /x 0xff*3 * 0x5555 /257
-p /x 0xff*3 * 0x5555 /256
-p /x 0xff*3 * 0x5555 /254
-p /x 0xff*3 * 0x5555 /253
-p /x 0xff*3 * 0x5555 /254
-p /x 0xff*3 * 0x5555 /255
-p (766*0x5555)/255
-p /x (766*0x5555)/255
-p /x (0x2fd*0x5555)/255
-0xffff/0x5555
-p (double)0xffff/0x5555
-r
-y
-r
-y
-r
-q
diff --git a/cinelerra-5.1/prof2/Makefile b/cinelerra-5.1/prof2/Makefile
new file mode 100644 (file)
index 0000000..b7e0247
--- /dev/null
@@ -0,0 +1,47 @@
+TARGETS = libprofile.so prof smap
+BITS=64
+#CFLAGS += -O
+CFLAGS += -g -Wall
+BIN_PATH ?= /usr/bin
+LIB_PATH ?= $(dir $(lastword $(wildcard /lib*/ld-*.so /lib*/*-linux-gnu/ld-*.so)))
+$(if $(LIB_PATH),,$(error cant find ld-.so))
+CFLAGS += -DLIB='"$(LIB_PATH)"'
+ASM_PATH ?= $(dir $(lastword $(wildcard /usr/include/asm/signal.h /usr/include/x86_64-linux-gnu/asm/signal.h)))
+
+.PHONY: all
+all:   $(TARGETS)
+
+.PHONY: install
+install:
+       cp -a libprofile.so $(DESTDIR)$(LIB_PATH)/.
+       cp -a prof smap $(DESTDIR)$(BIN_PATH)/.
+
+.PHONY: uninstall
+uninstall:
+       rm -f $(DESTDIR)$(LIB_PATH)/libprofile.so
+       rm -f $(DESTDIR)$(BIN_PATH)/prof
+       rm -f $(DESTDIR)$(BIN_PATH)/smap
+
+libprofile.so: profile.c
+       $(CC) $(CFLAGS) -fPIC -shared -o $@ $<
+
+prof:  prof.c sys.h
+       $(CC) $(CFLAGS) -o $@ $<
+
+smap:  smap.C
+       $(CXX) $(CFLAGS) -o $@ $< \
+        -Wall -I/usr/include/libiberty -llzma -liberty
+
+tst:   tst.c
+
+sys.h: $(ASM_PATH/signal.h $(ASM_PATH)/unistd.h
+       echo "char *sysreq_name[] = {" > sys.h
+       ./mksyscallent < $(ASM_PATH)/unistd_$(BITS).h >> sys.h
+       echo "};" >> sys.h
+       echo "char *signal_name[] = {" >> sys.h
+       ./mksignalent < $(ASM_PATH)/signal.h >> sys.h
+       echo "};" >> sys.h
+
+.PHONY: clean
+clean:
+       rm -f $(TARGETS) tst sys.h
diff --git a/cinelerra-5.1/prof2/mksignalent b/cinelerra-5.1/prof2/mksignalent
new file mode 100755 (executable)
index 0000000..316d81f
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch/signalent.h from <asm/signal.h>
+# It reads from stdin and writes to stdout
+
+BEGIN {
+       max=0;
+}
+
+{
+       if (($1 ~ /^#define$/) && (!SIGNAL[$3]) && ($2 ~ /^SIG[A-Z]/) \
+           && ($2 !~ /^SIGRTMIN$/) && ($2 !~ /^SIGRTMAX$/) && ($2 !~ /^SIGSTKSZ$/) \
+           && ($3>=0) && ($3<=1000)) {
+               SIGNAL[$3]=$2;
+               if ($3 > max) {
+                       max=$3;
+               }
+       }
+}
+
+END {
+       for(i=0; i<=max; i++) {
+               if (!SIGNAL[i]) {
+                       SIGNAL[i] = "SIG_" i;
+               }
+               pad = 16 - length(SIGNAL[i]);
+               if (pad<1) {
+                       pad=1;
+               }
+               printf("\t\"%s\",%*s/* %d */\n", SIGNAL[i], pad, "", i);
+       }
+}
+
diff --git a/cinelerra-5.1/prof2/mksyscallent b/cinelerra-5.1/prof2/mksyscallent
new file mode 100755 (executable)
index 0000000..e3d919f
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch/syscallent.h from <asm/unistd.h>
+# It reads from stdin and writes to stdout
+# Currently (linux-2.2.3), it works OK on i386,m68k,arm
+# It does NOT work in mips
+# It is untested in other architectures
+
+BEGIN {
+       max=0;
+       FS="[ \t\n()+]+";
+}
+
+{
+#      printf("/%s/%s/%s/%s/\n", $1, $2, $3, $4);
+       if (($1 ~ /^#define$/) && ($2 ~ /^__NR_/)) {
+               if (($3>=0) && ($3<=1000)) {
+                       SYSCALL[$3]=substr($2,6);
+                       if ($3 > max) {
+                               max=$3;
+                       }
+               } else if (($3 ~ /^__NR_SYSCALL_BASE$/) && ($4>=0) && ($4<=1000)) {
+                       SYSCALL[$4]=substr($2,6);
+                       if ($4 > max) {
+                               max=$4;
+                       }
+               }
+       }
+}
+
+END {
+       for(i=0; i<=max; i++) {
+               if (!SYSCALL[i]) {
+                       SYSCALL[i] = i;
+               }
+               pad = 32 - length(SYSCALL[i]);
+               if (pad<1) {
+                       pad=1;
+               }
+               printf("\t\"%s\",%*s/* %d */\n", SYSCALL[i], pad, "", i);
+       }
+}
+
diff --git a/cinelerra-5.1/prof2/prof.c b/cinelerra-5.1/prof2/prof.c
new file mode 100644 (file)
index 0000000..35af381
--- /dev/null
@@ -0,0 +1,782 @@
+/* prof.c - initialize sampling profiler
+    load user executable in ptrace mode
+    at exec catchpoint, set breakpoint at main
+    add LD_PRELOAD = libprofile
+    run ld-linux to map libraries, stop at main
+    add ptr to main as argument, start profileStart
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <link.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <sys/user.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "sys.h"
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#define dprintf(s...) do { if( unlikely(debug!=0) ) fprintf(s); } while(0)
+
+#ifdef __i386__
+#define nmAddr 0
+#define nmType 9
+#define nmName 11
+#define _LX "%08lx"
+#ifndef LIB
+#define LIB "/lib/"
+#endif
+#endif
+#ifdef __x86_64__
+#define nmAddr 0
+#define nmType 17
+#define nmName 19
+#define _LX "%016lx"
+#ifndef LIB
+#define LIB "/lib64/"
+#endif
+#endif
+
+#define SYM2MAX 1024*256
+#define SYMINCR 1024
+
+#define DEBUG 0
+#define PROF_DEBUG 0
+#define PROF_OUTPUT "--"
+#define PROF_TMR_TYPE 0
+#define PROF_TMR_USEC 10000
+
+static int debug = DEBUG;
+static int prof_debug = PROF_DEBUG;
+static int prof_type = PROF_TMR_TYPE;
+static int prof_tmrval = PROF_TMR_USEC;
+static long prof_stkptr = 0;
+static char *prof_output = NULL;
+static const int max_signals = sizeof(signal_name)/sizeof(signal_name[0]);
+static const int max_sysreqs = sizeof(sysreq_name)/sizeof(sysreq_name[0]);
+
+#define LIBPROFILE_NAME "libprofile.so"
+#define LIBPROFILE_PATH LIB LIBPROFILE_NAME
+
+#ifdef __i386__
+#define LD_LINUX_SO LIB "ld-linux.so.2"
+#endif
+#ifdef __x86_64__
+#define LD_LINUX_SO LIB "ld-linux-x86-64.so.2"
+#endif
+
+char *libprofile_path = NULL;
+
+typedef struct {
+   pid_t pid;
+   unsigned long addr;
+   long orig_value;
+   int enabled;
+} breakpoint;
+
+typedef struct {
+  char *nm;
+  unsigned long adr;
+} tSym;
+
+typedef struct {
+  int n, m;
+  tSym sym[SYMINCR];
+} tSymTbl;
+
+static tSymTbl *
+newSymTbl(void)
+{
+   tSymTbl *tp;
+   if( (tp=malloc(sizeof(*tp))) != NULL ) {
+      tp->n = 0;
+      tp->m = sizeof(tp->sym)/sizeof(tp->sym[0]);
+   }
+   return tp;
+}
+
+static int
+symCmpr(const void *a, const void *b)
+{
+   const char *anm = ((tSym const*)a)->nm;
+   const char *bnm = ((tSym const*)b)->nm;
+   return strcmp(anm,bnm);
+}
+
+static int
+newSym(tSymTbl **ptp, const char *nm, unsigned long adr)
+{
+   tSym *sp;
+   tSymTbl *tp = *ptp;
+   int n = tp->n;
+   int m = tp->m;
+   if( n >= m ) {
+      tSymTbl *rp;  int l;
+      m = m < SYM2MAX ? m*2 : m+SYMINCR;
+      l = sizeof(*tp)-sizeof(tp->sym)+m*sizeof(tp->sym[0]);
+      rp = (tSymTbl*) realloc(tp,l);
+      if( rp == NULL ) return -1;
+      tp = rp;
+      tp->m = m;
+      *ptp = tp;
+   }
+   sp = &tp->sym[n++];
+   tp->n = n;
+   sp->nm = strdup(nm);
+   sp->adr = adr;
+   return 0;
+}
+static void
+delSymTbl(tSymTbl **ptp)
+{
+   int i;  char *nm;
+   tSymTbl *tp = *ptp;
+   tSym *sp = &tp->sym[0];
+   for( i=tp->n; --i>=0; ++sp ) {
+      if( (nm=sp->nm) != NULL )
+         free(nm);
+   }
+   free(tp);
+   *ptp = NULL;
+}
+
+static int
+isSymNm(char *cp, char *bp)
+{
+   if( !*cp || *cp=='\n' ) return 0;
+   int ch;
+   while( (ch=*cp++) != 0 ) {
+      if( ch == '\n' ) break;
+      *bp++ = ch;
+      if( ch == '#' || ch == '$' || ch == '.' ) return 0;
+   }
+   *bp = 0;
+   return 1;
+}
+
+static int
+mapObj(char *fn,tSymTbl **ptp,const char *typs)
+{
+   char nmLine[512], nmCmd[512], *lp, *rp;
+   unsigned long adr;
+   FILE *fp;
+   if( access(fn,R_OK) < 0 ) return -1;
+   strcpy(&nmCmd[0],"smap 2> /dev/null < ");
+   strcat(&nmCmd[0],fn);
+   if( (fp=popen(&nmCmd[0],"r")) == NULL ) return -1;
+   while((lp=fgets(&nmLine[0],sizeof nmLine,fp)) != NULL ) {
+      int t = nmLine[nmType];
+      if( t != 'T' && t != 't' && (!typs || !strchr(typs,t)) ) continue;
+      if( isSymNm(&nmLine[nmName],&nmCmd[0]) == 0 ) continue;
+      adr = strtoul(&nmLine[nmAddr],&rp,16);
+      if( (rp-&nmLine[nmAddr]) != nmType-1 ) continue;
+      if( newSym(ptp,&nmCmd[0],adr) != 0 ) break;
+   }
+   pclose(fp);
+   return lp != NULL ? -1 : 0;
+}
+
+
+static tSymTbl *
+mapFile(char *fn,const char *typs)
+{
+   tSymTbl *tp = newSymTbl();
+   if( tp && mapObj(fn,&tp,typs) != 0 )
+     delSymTbl(&tp);
+   if( tp )
+     qsort(&tp->sym,tp->n,sizeof(tp->sym[0]),symCmpr);
+   return tp;
+}
+
+static tSym *
+symLkup(tSymTbl *tp,const char *nm)
+{
+   int l, m, n, r;
+   tSym *mp = NULL;
+   tSym *sp = &tp->sym[0];
+   l = n = -1;  r = tp->n;
+   while( (r-l) > 1 ) {
+      m = (r+l) >> 1;
+      mp = &sp[m];
+      n = strcmp(mp->nm,nm);
+      if( n == 0 ) break;
+      if( n < 0 ) l = m;
+      else r = m;
+   }
+   return n == 0 ? mp : NULL;
+}
+
+static void
+findSym(tSymTbl *tp,char *nm,tSym **psp)
+{
+   tSym *sp = symLkup(tp,nm);
+   if( sp == NULL ) {
+      fprintf(stderr,"cant find symbol '%s'\n",nm);
+      exit(1);
+   }
+   *psp = sp;
+}
+
+int
+execute_program(char *fn,char **argv)
+{
+   pid_t pid = fork();
+   if( pid < 0 ) {
+      perror("fork");
+      return -1;
+   }
+   if( pid != 0 )
+      return pid;
+   if (ptrace(PTRACE_TRACEME, 0, 1, 0)<0) {
+      perror("PTRACE_TRACEME");
+      exit(1);
+   }
+   setenv("LD_PRELOAD",libprofile_path,1);
+   //setenv("LD_DEBUG","files",1);
+   execvp(fn,argv);
+   fprintf(stderr, "Can't execute `%s': %s\n", fn, strerror(errno));
+   exit(1);
+}
+
+#ifdef __i386__
+static long
+peek_text(pid_t pid,long addr)
+{
+   return ptrace(PTRACE_PEEKTEXT,pid,addr,0);
+}
+
+static void
+poke_text(pid_t pid,long addr,long value)
+{
+   ptrace(PTRACE_POKETEXT,pid,addr,value);
+}
+
+static long
+get_eip(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.eip;
+}
+
+static void
+set_eip(pid_t pid,long addr)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   regs.eip = addr;
+   ptrace(PTRACE_SETREGS,pid,0,&regs);
+}
+
+static long
+get_sysreq(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.orig_eax;
+}
+
+static long
+get_sysret(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.eax;
+}
+
+static long
+get_esp(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.esp;
+}
+
+static long
+peek_stk(pid_t pid,long addr)
+{
+   return ptrace(PTRACE_PEEKDATA,pid,addr,0);
+}
+
+static void
+poke_stk(pid_t pid,long addr,long value)
+{
+   ptrace(PTRACE_POKEDATA,pid,addr,value);
+}
+
+#endif
+
+#ifdef __x86_64__
+static long
+peek_text(pid_t pid,long addr)
+{
+   long ret = ptrace(PTRACE_PEEKTEXT,pid,addr,0);
+   return ret;
+}
+
+static void
+poke_text(pid_t pid,long addr,long value)
+{
+   ptrace(PTRACE_POKETEXT,pid,addr,value);
+}
+
+static long
+get_eip(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.rip;
+}
+
+static void
+set_eip(pid_t pid,long addr)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   regs.rip = addr;
+   ptrace(PTRACE_SETREGS,pid,0,&regs);
+}
+
+static long
+get_sysreq(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.orig_rax;
+}
+
+static long
+get_sysret(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.rax;
+}
+
+static long
+get_esp(pid_t pid)
+{
+   struct user_regs_struct regs;
+   ptrace(PTRACE_GETREGS,pid,0,&regs);
+   return regs.rsp;
+}
+
+static long
+peek_stk(pid_t pid,long addr)
+{
+   errno = 0;
+   long ret = ptrace(PTRACE_PEEKDATA,pid,addr,0);
+   if( ret == -1 && errno )
+      dprintf(stderr,"peek_stk failed @ "_LX" = %d:%s",
+         addr, errno, strerror(errno));
+   return ret;
+}
+
+static void
+poke_stk(pid_t pid,long addr,long value)
+{
+   ptrace(PTRACE_POKEDATA,pid,addr,value);
+}
+#endif
+
+static int
+pstrcmp(pid_t pid,long addr,char *cp)
+{
+   int n, v;  long w, adr;
+   adr = addr & ~(sizeof(w)-1);
+   n = addr & (sizeof(w)-1);
+   w = peek_stk(pid,adr);
+   adr += sizeof(long);
+   w >>= n*8;
+   n = sizeof(w) - n;
+   for(;;) {
+      if( (v=(w&0xff)-*cp) != 0 ) break;
+      if( *cp == 0 ) break;
+      if( --n <= 0 ) {
+         w = peek_stk(pid,adr);
+         adr += sizeof(w);
+         n = sizeof(w);
+      }
+      else
+         w >>= 8;
+      ++cp;
+   }
+   return v;
+}
+
+static char *
+pstrcpy(pid_t pid,long addr,char *cp)
+{
+   long w, by;
+   unsigned char *bp = (unsigned char *)cp;
+   long adr = addr & ~(sizeof(w)-1);
+   int n = 8*(addr & (sizeof(w)-1));
+   w = peek_stk(pid,adr);
+   do {
+      by = *bp++;
+      w &= ~(0xffUL << n);
+      w |= by << n;
+      if( (n+=8) >= sizeof(w)*8 ) {
+         poke_stk(pid,adr,w);
+         adr += sizeof(w);
+         w = peek_stk(pid,adr);
+         n = 0;
+      }
+   } while( by );
+   if( n )
+     poke_stk(pid,adr,w);
+   return cp;
+}
+
+/* instruction = int 3 */
+#define BREAKPOINT_VALUE 0xcc
+#define BREAKPOINT_LENGTH 1
+#define DECR_PC_AFTER_BREAK 1
+
+void
+enable_breakpoint(breakpoint *bp)
+{
+   if( bp->enabled == 0 ) {
+      int shft;  long word, mask;
+      pid_t pid = bp->pid;
+      unsigned long addr = bp->addr & ~(sizeof(long)-1);
+      word = peek_text(pid,addr);
+      bp->orig_value = word;
+      shft = 8 * (bp->addr&(sizeof(long)-1));
+      mask = 0xffUL << shft;
+      word = (word & ~mask) | ((unsigned long)BREAKPOINT_VALUE << shft);
+      poke_text(pid,addr,word);
+      bp->enabled = 1;
+      dprintf(stderr,"set bp "_LX"\n",bp->addr);
+   }
+}
+
+void
+disable_breakpoint(breakpoint *bp)
+{
+   if( bp->enabled != 0 ) {
+      int shft;  long word, mask;
+      pid_t pid = bp->pid;
+      unsigned long addr = bp->addr & ~(sizeof(long)-1);
+      word = peek_text(pid,addr);
+      shft = 8 * (bp->addr&(sizeof(long)-1));
+      mask = 0xffUL << shft;
+      word = (word & ~mask) | (bp->orig_value & mask);
+      poke_text(pid,addr,word);
+      bp->enabled = 0;
+   }
+}
+
+breakpoint *newBrkpt(pid_t pid,unsigned long addr)
+{
+   breakpoint *bp;
+   bp = (breakpoint *)malloc(sizeof(*bp));
+   memset(bp,0,sizeof(*bp));
+   bp->pid = pid;
+   bp->addr = addr;
+   return bp;
+}
+
+static long
+get_map_fwa(pid_t pid,char *pfx1, char *pfx2)
+{
+   FILE *fp; int n, len1, len2;
+   long fwa, lwa1, pgoff;
+   unsigned long inode;
+   int major, minor;
+   char f1, f2, f3, f4, path[512], bfr[512];
+   sprintf(&bfr[0],"/proc/%d/maps",(int)pid);
+   if( (fp=fopen(&bfr[0],"r")) == NULL ) {
+      perror(&bfr[0]);  exit(1);
+   }
+   len1 = pfx1 ? strlen(pfx1) : 0;
+   len2 = pfx2 ? strlen(pfx2) : 0;
+   for(;;) {
+      if( fgets(&bfr[0],sizeof(bfr),fp) == NULL ) {
+         fprintf(stderr,"cant find process %d '%s' maps\n",(int)pid,pfx1);
+         exit(1);
+      }
+      n = sscanf(&bfr[0],"%lx-%lx %c%c%c%c %lx %x:%x %lu %s",
+            &fwa,&lwa1,&f1,&f2,&f3,&f4,&pgoff,&major,&minor,&inode,&path[0]); 
+      if( n != 11 ) continue;
+      // if( f3 != 'x' ) continue;
+      if( !pfx1 && !pfx2 ) break;
+      if( pfx1 && strncmp(pfx1,&path[0],len1) == 0 ) break;
+      if( pfx2 && strncmp(pfx2,&path[0],len2) == 0 ) break;
+   }
+   fclose(fp);
+   return fwa;
+}
+#ifdef __i386__
+#define CHILD(v) (peek_stk(pid,(long)(v)))
+#define ACHILD(v) CHILD(v)
+#endif
+#ifdef __x86_64__
+#define CHILD(v) (peek_stk(pid,(long)(v)&0x7fffffffffffL))
+#define ACHILD(v) (CHILD(v)&0x7fffffffffffL)
+#endif
+#define VCHILD(v) ((void*)CHILD(v))
+
+static void
+set_parm(pid_t pid,tSymTbl *tprof,long ofs,char *nm,long val)
+{
+   tSym *var;
+   dprintf(stderr,"set %s = %#lx\n",nm,val);
+   findSym(tprof,nm,&var);
+   var->adr += ofs;
+   poke_stk(pid,var->adr,val);
+}
+
+static void
+usage(char *av0)
+{
+   fprintf(stderr,"usage: %s [-o path] [-d] [-e] [-p libpath] [-012] [-u #] cmd args...\n",av0);
+   fprintf(stderr,"  -o  profile output pathname, -=stdout, --=stderr\n");
+   fprintf(stderr,"  -d  debug output enabled\n");
+   fprintf(stderr,"  -e  child debug output enabled\n");
+   fprintf(stderr,"  -p  specify path for libprofile.so\n");
+   fprintf(stderr,"  -0  usr+sys cpu timer intervals (sigprof)\n");
+   fprintf(stderr,"  -1  usr only cpu timer intervals (sigvtalrm)\n");
+   fprintf(stderr,"  -2  real time timer intervals (sigalrm)\n");
+   fprintf(stderr,"  -u  profile timer interval in usecs\n");
+}
+
+long run_to_breakpoint(pid_t ppid, int init_syscall)
+{
+   int in_syscall = init_syscall;
+   if( in_syscall < 0 )
+     ptrace(PTRACE_SYSCALL,ppid,0,0);
+   for(;;) {
+      int status;
+      pid_t pid = wait(&status);    /* wait for ptrace status */
+      if( ppid != pid ) continue;
+      if( WIFSTOPPED(status) ) {
+         int stopsig = WSTOPSIG(status);
+         if( stopsig == SIGTRAP ) {
+            long eip = get_eip(pid);
+            int sysnum = get_sysreq(pid);
+            if( in_syscall < 0 ) {  /* starting syscall */
+               if( sysnum < 0 ) {   /* hit breakpoint */
+                  dprintf(stderr,"hit bp at 0x"_LX"\n",eip);
+                  return eip;
+               }
+               dprintf(stderr,"syscall %3d "_LX" - %s",sysnum,eip,
+                 sysnum >= max_sysreqs ? "unknown" : sysreq_name[sysnum]);
+               in_syscall = sysnum;
+            }
+            else {     /* finishing syscall */
+               long ret = get_sysret(pid);
+               if( in_syscall != sysnum )
+                  dprintf(stderr,"(%d!)",sysnum);
+               dprintf(stderr," = %#lx\n",ret);
+               if( init_syscall >= 0 )
+                 return eip;
+               in_syscall = -1;
+            }
+         }
+         /* resume execution */
+         ptrace(PTRACE_SYSCALL,pid,0,0);
+      }
+      else {      /* unexepected status returned */
+         if( WIFEXITED(status) ) {
+            int exit_code = WEXITSTATUS(status);
+            fprintf(stderr,"exit %d\n",exit_code);
+         }
+         else if( WIFSIGNALED(status) ) {
+            int signum = WTERMSIG(status);
+            fprintf(stderr,"killed %d - %s\n", signum,
+               signum < 0 || signum >= max_signals ?
+                 "unknown" : signal_name[signum]);
+         }
+         else {
+            fprintf(stderr,"unknown status %d\n",status);
+         }
+         exit(1);
+      }
+   }
+}
+
+static void
+setup_profile(pid_t pid,long r_debug,long bp_main)
+{
+   tSymTbl *tprof;
+   tSym *sym;
+   struct link_map *so;
+   long absOffset = get_map_fwa(pid, LIB "ld-", "/usr" LIB "ld-");
+   struct r_debug *rdebug = (struct r_debug *)(r_debug+absOffset);
+   /* look through maps - find libprofile image, save absOffset */
+   dprintf(stderr,"rdebug "_LX"\n",(long)rdebug);
+   for( so=VCHILD(&rdebug->r_map); so!=NULL; so=VCHILD(&so->l_next) ) {
+      absOffset = CHILD(&so->l_addr);
+      if( absOffset == 0 ) continue;
+      if( pstrcmp(pid,ACHILD(&so->l_name),libprofile_path) == 0 ) break;
+   }
+   if( so == NULL ) {
+      fprintf(stderr,"%s did not preload\n",libprofile_path);
+      exit(1);
+   }
+   dprintf(stderr,"libprofile "_LX"\n",absOffset);
+   /* map libprofile with nm */
+   tprof = mapFile(libprofile_path,"bd");
+   prof_stkptr = get_esp(pid);
+   dprintf(stderr,"orig esp "_LX"\n",prof_stkptr);
+   set_parm(pid,tprof,absOffset,"prof_stkptr",prof_stkptr);
+   set_parm(pid,tprof,absOffset,"prof_debug",prof_debug);
+   set_parm(pid,tprof,absOffset,"prof_type",prof_type);
+   set_parm(pid,tprof,absOffset,"prof_tmrval",prof_tmrval);
+   findSym(tprof,"prof_output",&sym);
+   sym->adr += absOffset;
+   pstrcpy(pid,sym->adr,&prof_output[0]);
+   findSym(tprof,"profileMain",&sym);
+   sym->adr += absOffset;
+   dprintf(stderr,"set eip = %#lx\n",sym->adr);
+   /* resume execution in profileStart */
+   set_eip(pid,sym->adr);
+}
+
+int main(int ac, char **av)
+{
+   char *cp;
+   tSymTbl *tpath, *tld_linux;
+   tSym *sym_main, *sym__r_debug;
+   int pid, status, execve;
+   breakpoint *main_bp = NULL;
+   char *lib_path = NULL, *lib_argv = NULL;
+
+
+   /* decode cmdline params */
+   while( ac > 1 && *(cp=av[1]) == '-' ) {
+      switch( cp[1] ) {
+      case 'd':  /* enable debug output */
+         debug = 1;
+         break;
+      case 'e':  /* enable child debug output */
+         prof_debug = 1;
+         break;
+      case '0':  /* use sigprof */
+         prof_type = 0;
+         break;
+      case '1':  /* use sigvtalrm */
+         prof_type = 1;
+         break;
+      case '2':  /* use sigalrm */
+         prof_type = 2;
+         break;
+      case 'u':  /* use timer interval usec */
+         prof_tmrval = strtoul(av[2],NULL,0);
+         --ac;  ++av;
+         break;
+      case 'o':  /* specify output path */
+         prof_output = av[2];
+         --ac;  ++av;
+         break;
+      case 'p':  /* specify libprofile */
+         lib_argv = av[2];
+         --ac;  ++av;
+         break;
+      default:
+         fprintf(stderr,"unknown parameter - '%s'\n",cp);
+      case 'h':  /* help */
+         ac = 0;
+         break;
+      }
+      --ac;  ++av;
+   }
+
+   if( ac < 2 ) {
+      usage(av[0]);
+      exit(1);
+   }
+
+   if( lib_argv != NULL ) {
+      if( access(&lib_argv[0],R_OK) == 0 )
+         lib_path = strdup(lib_argv);
+   }
+   if( lib_path == NULL ) {
+      cp = "./" LIBPROFILE_NAME;
+      if( access(cp,R_OK) == 0 )
+         lib_path = strdup(cp);
+   }
+   if( lib_path == NULL && (cp=getenv("HOME")) != NULL ) {
+      char libpath[PATH_MAX];
+      snprintf(&libpath[0],sizeof(libpath),"%s/bin/%s",
+               cp,LIBPROFILE_NAME);
+      if( access(&libpath[0],R_OK) == 0 )
+         lib_path = strdup(&libpath[0]);
+   }
+   if( lib_path == NULL ) {
+      if( access(cp=LIBPROFILE_PATH,R_OK) == 0 )
+         lib_path = strdup(cp);
+   }
+   if( lib_path == NULL ) {
+      fprintf(stderr,"cant find %s\n",LIBPROFILE_NAME);
+      exit(1);
+   }
+   libprofile_path = lib_path;
+
+   if( prof_output == NULL )
+      prof_output = PROF_OUTPUT;
+
+   /* read nm output for executable */
+   tpath = mapFile(av[1],0);
+   if( tpath == NULL ) {
+      fprintf(stderr,"cant map %s\n",av[1]);
+      exit(1);
+   }
+   /* read nm output for ld-linux */
+   tld_linux = mapFile(LD_LINUX_SO,"BD");
+   if( tld_linux == NULL ) {
+      fprintf(stderr,"cant map %s\n",LD_LINUX_SO);
+      exit(1);
+   }
+
+   /* lookup main, _r_debug */
+   findSym(tpath,"main",&sym_main);
+   findSym(tld_linux,"_r_debug",&sym__r_debug);
+   /* fork child with executable */
+   pid = execute_program(av[1],&av[1]);
+   if( pid < 0 ) {
+      perror(av[1]);
+      exit(1);
+   }
+
+   execve = sizeof(sysreq_name)/sizeof(sysreq_name[0]);
+   while( --execve >= 0 && strcmp("execve",sysreq_name[execve]) );
+   if( execve < 0 ) {
+      fprintf(stderr,"cant find execve sysreq\n");
+      exit(1);
+   }
+   main_bp = newBrkpt(pid,sym_main->adr);
+   run_to_breakpoint(pid, execve);
+   /* add offset of main module */
+   main_bp->addr += get_map_fwa(pid,0,0);
+   enable_breakpoint(main_bp);
+   run_to_breakpoint(pid, -1);
+   /* hit breakpoint at 'main', setup profiler */
+   setup_profile(pid,sym__r_debug->adr,main_bp->addr);
+   disable_breakpoint(main_bp);
+   ptrace(PTRACE_DETACH,pid,0,0);  /* turn off ptrace */
+   pid = wait(&status);            /* wait for child status */
+   if( WIFEXITED(status) ) {
+      status = WEXITSTATUS(status);
+      dprintf(stderr,"exit %d\n",status);
+   }
+   else if( WIFSIGNALED(status) ) {
+      int signum = WTERMSIG(status);
+      fprintf(stderr,"killed %d - %s\n", signum,
+         signum < 0 || signum >= max_signals ?
+            "unknown" : signal_name[signum]);
+   }
+   else {
+      fprintf(stderr,"unknown status %d\n",status);
+      status = 1;
+   }
+   return status;
+}
+
diff --git a/cinelerra-5.1/prof2/profile.c b/cinelerra-5.1/prof2/profile.c
new file mode 100644 (file)
index 0000000..6103b53
--- /dev/null
@@ -0,0 +1,843 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <pthread.h>
+#include <link.h>
+
+#define smCommand "smap 2> /dev/null < "
+#ifdef __i386__
+#define nmAddr 0
+#define nmType 9
+#define nmName 11
+#define _LX "%08lx"
+#ifndef LIB
+#define LIB "/lib"
+#endif
+#endif
+#ifdef __x86_64__
+#define nmAddr 0
+#define nmType 17
+#define nmName 19
+#define _LX "%016lx"
+#ifndef LIB
+#define LIB "/lib64"
+#endif
+#endif
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#define dprintf(s...) do { if( unlikely(prof_debug!=0) ) fprintf(s); } while(0)
+
+int profileMain(int ac,char **av,char **ev);
+void profileStart(void);
+void profileStop(void);
+void profileClear(void);
+void profileShow(void);
+void profileDone(void);
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#define MAP2MAX 256
+#define MAPINCR 64
+#define MOD2MAX 256
+#define MODINCR 64
+#define SYM2MAX 1024*256
+#define SYMINCR 1024*16
+#if 0
+static volatile long prof_debug = 1;
+static volatile long prof_type = 0;
+static volatile long prof_tmrval = 10000;
+static volatile unsigned long prof_stkptr = INT_MAX-0x1000;
+static volatile char prof_output[256] = { "-" };
+#else
+static volatile long prof_debug; /* enable debug output */
+static volatile long prof_type; /* 0=usr+sys, 1=usr only, 2=real time */
+static volatile long prof_tmrval; /* profile timer interval in usecs */
+static volatile unsigned long prof_stkptr; /* top of stack at profileStart */
+static volatile char prof_output[256]; /* profile output file name */
+#endif
+
+static FILE *prof_fp = NULL;
+
+typedef struct {
+   char *name;
+   unsigned long offs;
+} tMap;
+
+typedef struct {
+   int n, m;
+   tMap map[MAPINCR];
+} tMapTbl;
+
+typedef struct {
+   char *name;
+   unsigned long offs;
+   int count;
+   int calls;
+} tMod;
+
+typedef struct {
+   int n, m;
+   tMod mod[MODINCR];
+} tModTbl;
+
+typedef struct {
+   char *name;
+   unsigned long adr;
+   int count;
+   int calls;
+   int tick;
+   int tcalls;
+   int mod;
+} tSym;
+
+typedef struct {
+   int n, m;
+   tSym sym[SYMINCR];
+} tSymTbl;
+
+static tSymTbl *tsym = NULL;
+static tModTbl *tmod = NULL;
+static tMapTbl *tmap = NULL;
+static int nTicks;               /* profile timer tick count */
+static struct tms start_cpu;     /* cpu time at profile_start */
+static struct tms stop_cpu;      /* cpu time at profile_stop */
+static struct timeval start_clk; /* real time at profile_start */
+static struct timeval stop_clk;  /* real time at profile_stop */
+
+int profileActive = 0;           /* flag, true if profile handler active */
+static struct sigaction oldSig;  /* orignal profile handler data */
+static struct sigaction oldSegv; /* orignal segv handler data */
+
+static tMapTbl *
+newMapTbl(void)
+{
+   tMapTbl *tp;
+   if( (tp=malloc(sizeof(*tp))) != NULL ) {
+      tp->n = 0;
+      tp->m = sizeof(tp->map)/sizeof(tp->map[0]);
+   }
+   return tp;
+}
+
+static tModTbl *
+newModTbl(void)
+{
+   tModTbl *tp;
+   if( (tp=malloc(sizeof(*tp))) != NULL ) {
+      tp->n = 0;
+      tp->m = sizeof(tp->mod)/sizeof(tp->mod[0]);
+   }
+   return tp;
+}
+
+static tSymTbl *
+newSymTbl(void)
+{
+   tSymTbl *tp;
+   if( (tp=malloc(sizeof(*tp))) != NULL ) {
+      tp->n = 0;
+      tp->m = sizeof(tp->sym)/sizeof(tp->sym[0]);
+   }
+   return tp;
+}
+
+static tSym *
+newSym(tSymTbl **ptp,const char *name,unsigned long adr,int mod)
+{
+   tSym *sp;
+   tSymTbl *tp = *ptp;
+   int n = tp->n;
+   int m = tp->m;
+   if( n >= m ) {
+      tSymTbl *rp;  int l;
+      m = m < SYM2MAX ? m*2 : m+SYMINCR;
+      l = sizeof(*tp)-sizeof(tp->sym)+m*sizeof(tp->sym[0]);
+      rp = (tSymTbl*) realloc(tp,l);
+      if( rp == NULL ) return NULL;
+      tp = rp;
+      tp->m = m;
+      *ptp = tp;
+   }
+   sp = &tp->sym[n++];
+   tp->n = n;
+   sp->name = strdup(name);
+   sp->adr = adr;
+   sp->mod = mod;
+   sp->count = sp->calls = 0;
+   sp->tick = sp->tcalls = 0;
+   return sp;
+}
+
+static int
+newMod(tModTbl **ptp, const char *name, unsigned long offs)
+{
+   tMod *mp;
+   tModTbl *tp = *ptp;
+   int n = tp->n;
+   int m = tp->m;
+   if( n >= m ) {
+      tModTbl *rp;  int l;
+      m = m < MOD2MAX ? m*2 : m+MODINCR;
+      l = sizeof(*tp)-sizeof(tp->mod)+m*sizeof(tp->mod[0]);
+      rp = (tModTbl*) realloc(tp,l);
+      if( !rp ) return -1;
+      tp = rp;
+      *ptp = tp;
+   }
+   int ret = n++;
+   mp = &tp->mod[ret];
+   tp->n = n;
+   mp->name = strdup(name);
+   mp->offs = offs;
+   mp->count = mp->calls = 0;
+   return ret;
+}
+
+int
+findMod(tModTbl *tp, const char *nm)
+{
+   int n = tp->n;
+   while( --n >= 0 && strcmp(nm,tp->mod[n].name) );
+   return n;
+}
+
+static int
+newMap(tMapTbl **ptp, const char *name, unsigned long offs)
+{
+   tMap *mp;
+   tMapTbl *tp = *ptp;
+   int n = tp->n;
+   int m = tp->m;
+   if( n >= m ) {
+      tMapTbl *rp;  int l;
+      m = m < MAP2MAX ? m*2 : m+MAPINCR;
+      l = sizeof(*tp)-sizeof(tp->map)+m*sizeof(tp->map[0]);
+      rp = (tMapTbl*) realloc(tp,l);
+      if( !rp ) return -1;
+      tp = rp;
+      *ptp = tp;
+   }
+   int ret = n++;
+   mp = &tp->map[ret];
+   tp->n = n;
+   mp->name = strdup(name);
+   mp->offs = offs;
+   return ret;
+}
+
+static void
+delMapTbl(tMapTbl **ptp)
+{
+   int i;  char *name;
+   tMapTbl *tp;  tMap *mp;
+   if( (tp=*ptp) == NULL ) return;
+   mp = &tp->map[0];
+   for( i=tp->n; --i>=0; ++mp ) {
+      if( (name=mp->name) != NULL )
+         free(name);
+   }
+   free(tp);
+   *ptp = NULL;
+}
+
+static void
+delModTbl(tModTbl **ptp)
+{
+   int i;  char *name;
+   tModTbl *tp;  tMod *mp;
+   if( (tp=*ptp) == NULL ) return;
+   mp = &tp->mod[0];
+   for( i=tp->n; --i>=0; ++mp ) {
+      if( (name=mp->name) != NULL )
+         free(name);
+   }
+   free(tp);
+   *ptp = NULL;
+}
+
+static void
+delSymTbl(tSymTbl **ptp)
+{
+   int i;  char *name;
+   tSymTbl *tp;  tSym *sp;
+   if( (tp=*ptp) == NULL ) return;
+   sp = &tp->sym[0];
+   for( i=tp->n; --i>=0; ++sp ) {
+      if( (name=sp->name) != NULL )
+         free(name);
+   }
+   free(tp);
+   *ptp = NULL;
+}
+
+static void
+delAllTbls(void)
+{
+   delMapTbl(&tmap);
+   delModTbl(&tmod);
+   delSymTbl(&tsym);
+}
+
+static int
+mapLkup(tMapTbl *tp,const char *nm)
+{
+   tMap *mp = &tp->map[0];
+   int n = tp->n;
+   while( --n >= 0 && strcmp(nm,mp->name)!=0 )
+     ++mp;
+   return n;
+}
+
+static int
+findMap(tMapTbl *tp,char *nm)
+{
+   int ret = mapLkup(tp,nm);
+   if( ret < 0 )
+      dprintf(stderr,"cant find map '%s'\n",nm);
+   return ret;
+}
+
+static int
+findSymAdr(tSymTbl *tp,const char *nm,unsigned long *adr)
+{
+  int n = tp->n;
+  while( --n >= 0 && strcmp(nm,tp->sym[n].name) );
+  if( n < 0 ) return 1;
+  *adr = tp->sym[n].adr;
+  return 0;
+}
+
+static int
+isSymNm(char *cp, char *bp)
+{
+   int ch;
+   while( (ch=*cp++) != 0 ) {
+      if( ch == '\n' ) break;
+      *bp++ = ch;
+      if( ch == '#' || ch == '$' || ch == '.' ) return 0;
+   }
+   *bp = 0;
+   return 1;
+}
+
+static int
+hex(char *cp, unsigned long *val)
+{
+   char *bp = cp;
+   *val = strtoul(cp,&bp,16);
+   return bp - cp;
+}
+
+static int
+mapMod(char *fn,tSymTbl **ptp, int mod)
+{
+   char nmLine[512], nmCmd[512], *lp;
+   unsigned long adr, ofs;  int typ;
+   FILE *fp;  tMod *mp;
+   if( access(fn, R_OK) < 0 ) return -1;
+   strcpy(&nmCmd[0],smCommand);
+   strcat(&nmCmd[0],fn);
+   lp = NULL;
+   if( (fp=popen(&nmCmd[0],"r")) == NULL ) return -1;
+   mp = &tmod->mod[mod];  ofs = mp->offs;
+   while((lp=fgets(&nmLine[0],sizeof nmLine,fp)) != NULL ) {
+      typ = nmLine[nmType];
+      if( typ != 'T' && typ != 't' ) continue;
+      if( isSymNm(&nmLine[nmName],&nmCmd[0]) == 0 ) continue;
+      if( hex(&nmLine[nmAddr],&adr) != nmType-1 ) continue;
+      adr += ofs;
+      if( newSym(ptp,&nmCmd[0],adr,mod) == NULL ) break;
+   } while((lp=fgets(&nmLine[0],sizeof nmLine,fp)) != NULL );
+   pclose(fp);
+   return lp != NULL ? -1 : 0;
+}
+
+static int
+adrCmpr(const void *a, const void *b)
+{
+   unsigned long aadr = ((tSym*)a)->adr;
+   unsigned long badr = ((tSym*)b)->adr;
+   if( aadr > badr ) return 1;
+   if( aadr < badr ) return -1;
+   return 0;
+}
+
+static int
+cntCmpr(const void *a, const void *b)
+{
+   int acnt = ((tSym*)a)->count;
+   int bcnt = ((tSym*)b)->count;
+   return acnt - bcnt;
+}
+
+static int
+tclCmpr(const void *a, const void *b)
+{
+   int atcl = ((tSym*)a)->tcalls;
+   int btcl = ((tSym*)b)->tcalls;
+   return atcl - btcl;
+}
+
+static int
+modCmpr(const void *a, const void *b)
+{
+   int acnt = ((tMod*)a)->count;
+   int bcnt = ((tMod*)b)->count;
+   return acnt - bcnt;
+}
+
+static int
+profile_tally(unsigned long pc, int cnt)
+{
+   tSym *sp, *tp;
+   int l, m, r;
+   if( tsym == NULL )
+      return -1;
+   sp = tp = &tsym->sym[0];
+   l = -1;  r = tsym->n;
+ /* find function containing pc */
+   while( (r-l) > 1 ) {
+      m = (r+l) >> 1;
+      sp = &tp[m];
+      if( sp->adr == pc ) break;
+      if( sp->adr < pc ) l = m;
+      else r = m;
+   }
+   if( sp->adr != pc ) {
+      if( l < 0 )
+         return -1;
+      sp = &tp[l];
+   }
+   tMod *mp = &tmod->mod[sp->mod];
+/* incr function/module calls/counts */
+   ++sp->calls;
+   ++mp->calls;
+/* only 1 call per unwinding */
+   if( sp->tick < nTicks ) {
+      sp->tick = nTicks;
+      ++sp->tcalls;
+   }
+   if( cnt != 0 ) {
+      ++sp->count;
+      ++mp->count;
+   }
+   return 0;
+}
+
+struct reg_frame {
+   unsigned long rf_fp;        /* frame pointer */
+   unsigned long rf_rtn;       /* return addr */
+};
+
+static int readProcMaps(unsigned long *fwa)
+{
+   int ret, n, m, fd, len;
+   unsigned long vm_start, vm_end, ino;
+   char mr, mw, mx, ms, *bp;
+   off_t pgoff;
+   unsigned int maj, min;
+   char mfn[PATH_MAX], ifn[PATH_MAX];
+   char bfr[65536];
+   pid_t pid = getpid();
+   ret = 1;
+   snprintf(&mfn[0],sizeof mfn,"/proc/%d/maps",pid);
+   fd = open(&mfn[0],O_RDONLY);
+   if( fd >= 0 ) {
+      len = read(fd,bp=&bfr[0],sizeof bfr);
+      close(fd);
+      while( len > 0 ) {
+         m = sscanf(bp, "%lx-%lx %c%c%c%c %lx %x:%x %lu%n",
+            &vm_start,&vm_end,&mr,&mw,&mx,&ms,&pgoff,&maj,&min,&ino,&n);
+         if( m == 10 && fwa ) { *fwa = vm_start;  fwa = 0; }
+         if( m == 10 && mx == 'x' && pgoff == 0 ) {
+            for( bp+=n,len-=n ; len>0 && *bp!='\n' && *bp==' '; ++bp,--len );
+            for( m=0 ; len>0 && *bp!='\n' && m<PATH_MAX-1; ++bp,--len )
+               ifn[m++] = *bp;
+            ifn[m] = 0;
+            if( maj !=0 || min != 0 ) {
+               dprintf(stderr," map "_LX" %s\n",vm_start,&ifn[0]);
+               newMap(&tmap,&ifn[0],vm_start);
+            }
+         }
+         while( --len>=0 && *bp++!='\n' );
+      }
+      ret = 0;
+   }
+   return ret;
+}
+
+static int readNmMaps(unsigned long fwa)
+{
+   unsigned long adr;
+   int i, k;
+   char dfn[PATH_MAX], efn[PATH_MAX], pfn[PATH_MAX];
+   struct link_map *so;
+   struct r_debug *rdebug = &_r_debug;
+   for( so=rdebug->r_map; so!=NULL; so=so->l_next ) {
+      int n = tsym->n;
+      char *nm = &so->l_name[0];
+      if( nm[0] == 0 ) nm = "/proc/self/exe";
+      dprintf(stderr,"resolving %s\n",nm);
+      if( nm[0] == '.' && nm[1] == '/' ) {
+        getcwd(&pfn[0],sizeof(pfn));
+        strcat(&pfn[0],&nm[1]);
+        nm = &pfn[0];
+      }
+      while( (i=readlink(nm,&efn[0],sizeof(efn)-1)) >= 0 ) {
+        efn[i] = 0;
+        dprintf(stderr,"  link %s\n",&efn[0]);
+        if( efn[0] != '/' ) { /* get dirname */
+           for( k=-1,i=0; i<sizeof(dfn)-1 && (dfn[i++]=*nm)!=0; ++nm )
+             if( *nm == '/' ) k = i;
+           if( k >= 0 ) {     /* add link name */
+             for( i=0; k<sizeof(dfn)-1 && (dfn[k++]=efn[i])!=0; ++i );
+           }
+           strncpy(&efn[0],&dfn[0],sizeof(efn));
+        }
+        nm = &efn[0];
+        dprintf(stderr,"  path %s\n",nm);
+      }
+      if( findMod(tmod,nm) >= 0 ) continue;
+      int map = !so->l_name[0] ? -1 : findMap(tmap, nm);
+      tMap *mp = map>=0 ? &tmap->map[map] : 0;
+      adr = mp ? mp->offs : (unsigned long) so->l_addr;
+      if( !adr ) adr = fwa;
+      dprintf(stderr,"  map %s adr = 0x"_LX" ofs = 0x"_LX"\n",
+          nm,adr,(unsigned long)so->l_addr);
+      int mod = newMod(&tmod,nm,adr);
+      if( mod >= 0 ) {
+         if( mapMod(nm,&tsym,mod) < 0 || tsym->n == n ) {
+            char dfn[PATH_MAX];  memset(dfn,0,sizeof(dfn));
+            strcpy(&dfn[0],"/usr/lib/debug");
+            strncat(&dfn[0],nm,sizeof(dfn)-1);
+            strncat(&dfn[0],".debug",sizeof(dfn)-1);
+            dprintf(stderr,", %s",&dfn[0]);
+            if( mapMod(&dfn[0],&tsym,mod) < 0 )
+              mod = -1;
+         }
+      }
+      dprintf(stderr,", %d symbols\n",tsym->n - n);
+      if( mod < 0 ) {
+         fprintf(stderr,"profile - Cannot map module - %s\n",nm);
+//         exit(1);
+//         return -1;
+      }
+   }
+
+   /* sort the symbols by address */
+   qsort(&tsym->sym[0],tsym->n,sizeof(tsym->sym[0]),adrCmpr);
+   if( prof_debug != 0 ) {
+      int i; tSym *sp;
+      sp = &tsym->sym[0];
+      for( i=tsym->n; --i>=0; ++sp ) {
+         tMod *mp = &tmod->mod[sp->mod];
+         fprintf(stdout,_LX" %-24s %s\n",sp->adr,
+            &sp->name[0],&mp->name[0]);
+      }
+   }
+   return 0;
+}
+
+/** profile_handler(sign,c)
+ * profile periodic timer signal handler.
+ * decodes pc/fp from sigcontext, and tallys pc (count)
+ *  and stack trace (calls).
+ */
+#define LOW_TEXT 0x01000UL
+
+static void profile_handler(int n, siginfo_t * info, void *sc)
+{
+  ucontext_t *uc = (ucontext_t *)sc;
+  struct sigcontext *c = (struct sigcontext *)&uc->uc_mcontext;
+   struct reg_frame *fp, *last_fp;
+   unsigned long pc;
+   /* tid marks top of thread stack (currently) */
+   unsigned long tid = (unsigned long)pthread_self();
+   ++nTicks;
+   /* tally pc value */
+#ifdef __i386__
+   pc = (unsigned long)c->eip;
+#define ARCH_OK
+#endif
+#ifdef __x86_64__
+   pc = (unsigned long)c->rip;
+#define ARCH_OK
+#endif
+#ifndef ARCH_OK
+#error unknown arch
+#endif
+   if( pc < LOW_TEXT ) return;
+   if( profile_tally(pc,1) != 0 ) return;
+
+   /* access frame pointer and validate */
+#ifdef __i386__
+   fp = (struct reg_frame *)c->ebp;
+   if( (unsigned long)fp < c->esp ) return;
+#endif
+#ifdef __x86_64__
+   fp = (struct reg_frame *)c->rbp;
+   if( (unsigned long)fp < c->rsp ) return;
+#endif
+   if( (unsigned long)fp > prof_stkptr) return;
+   if( (unsigned long)fp > tid) return;
+   dprintf(stderr,"unwind "_LX"",(unsigned long)pc);
+   /* unwind the stack frames, and tally pc values */
+   while( (last_fp=fp) != 0 ) {
+      pc = fp->rf_rtn;
+      dprintf(stderr," "_LX"",(unsigned long)pc);
+      if( pc < LOW_TEXT ) break;
+      if( profile_tally(pc,0) != 0 ) break;
+      fp = (struct reg_frame *)fp->rf_fp;
+      if( ((long)fp & 3) != 0 ) break;
+      if( fp <= last_fp ) break;
+      if( (unsigned long)fp > prof_stkptr ) break;
+      if( (unsigned long)fp > tid ) break;
+   }
+   dprintf(stderr,"\n");
+
+   return;
+}
+
+void profileExit(void)
+{
+   profileStop();
+   profileShow();
+   profileDone();
+}
+
+static void profile_segv(int n, siginfo_t * info, void *sc)
+{
+  ucontext_t *uc = (ucontext_t *)sc;
+  struct sigcontext *c = (struct sigcontext *)&uc->uc_mcontext;
+  profileExit();
+  fprintf(stderr,"segv at 0x"_LX"\n",
+#if __i386__
+    c->eip
+#endif
+#if __x86_64__
+    c->rip
+#endif
+    );
+}
+
+void profileStart(void)
+{
+   char *fn;
+   int typ, sig;
+   struct itimerval it;
+   struct timezone tz;
+   struct sigaction act;
+   struct sigaction segv;
+   unsigned long fwa;
+
+   if( profileActive != 0 ) return;
+
+   if( tmod == NULL || tsym == NULL || tmap == NULL ) {
+      setbuf(stderr,NULL);
+      dprintf(stderr,"start profile\n");
+      delAllTbls();
+      unsetenv("LD_PRELOAD");
+      profileDone();
+      fn = (char *)&prof_output[0];
+      if( strcmp("-",&fn[0]) == 0 )
+         prof_fp = stdout;
+      else if( strcmp("--",&fn[0]) == 0 )
+         prof_fp = stderr;
+      else
+         prof_fp = fopen(&fn[0],"w");
+      if( prof_fp == NULL ) {
+         perror(&fn[0]);
+         fprintf(stderr,"profile: no output path\n");
+         exit(1);
+      }
+      tmap = newMapTbl();  fwa = 0;
+      if( tmap != NULL && readProcMaps(&fwa) == 0 ) {
+         tmod = newModTbl();  tsym = newSymTbl();
+         if( tmod == NULL || tsym == NULL || readNmMaps(fwa) != 0 ) {
+            fprintf(stderr,"profile: unable to read nm maps\n");
+            delModTbl(&tmod);  delSymTbl(&tsym);
+         }
+      }
+      else {
+         fprintf(stderr,"profile: unable to read proc maps\n");
+         delMapTbl(&tmap);
+      }
+   }
+   if( tmap == NULL || tmod == NULL || tsym == NULL ) {
+      delAllTbls();
+      return;
+   }
+
+   switch( prof_type ) {
+   case 1:  typ = ITIMER_VIRTUAL;  sig = SIGVTALRM;  break;
+   case 2:  typ = ITIMER_REAL;     sig = SIGALRM;    break;
+   default: typ = ITIMER_PROF;     sig = SIGPROF;    break;
+   }
+
+   /* record the start time (cpu/real). */
+   times(&start_cpu);
+   gettimeofday(&start_clk,&tz);
+
+   /* enable the profile timer signal handler. */
+   profileActive = 1;
+   memset(&act,0,sizeof(act));
+   act.sa_sigaction = profile_handler;
+   act.sa_flags = SA_RESTART + SA_SIGINFO;
+   sigaction(sig, &act, &oldSig);
+   memset(&segv,0,sizeof(segv));
+   segv.sa_sigaction = profile_segv;
+   segv.sa_flags = SA_SIGINFO;
+   sigaction(SIGSEGV,&segv,&oldSegv);
+
+   /* start the periodic profile timer signal */
+   if( prof_tmrval == 0 ) prof_tmrval = 1;
+   it.it_value.tv_sec = 
+   it.it_interval.tv_sec = prof_tmrval / 1000000;
+   it.it_value.tv_usec =
+   it.it_interval.tv_usec = prof_tmrval % 1000000;
+   setitimer(typ, &it, NULL);
+   dprintf(stderr,"starting profile.\n");
+}
+
+int profileMain(int ac,char **av,char **ev)
+{
+   int (*fmain)(int ac,char **av,char **ev);
+   unsigned long adr;
+   profileStart();
+   if( findSymAdr(tsym,"main",&adr) != 0 ) {
+     fprintf(stderr,"cant locate sym \"main\"\n");
+     exit(1);
+   }
+   atexit(profileExit);
+   fmain = (int (*)(int,char **,char **))adr;
+   dprintf(stderr,"starting \"main\" at: %p\n",fmain);
+   int ret = fmain(ac,av,ev);
+   dprintf(stderr,"ended \"main\" = %d\n",ret);
+   exit(ret);
+}
+
+void profileStop(void)
+{
+   struct itimerval it;
+   struct timezone tz;
+   struct sigaction act;
+
+   if( profileActive == 0 ) return;
+   dprintf(stderr,"stopping profile.\n");
+
+   /* records the stop time (cpu/real). */
+   times(&stop_cpu);
+   gettimeofday(&stop_clk,&tz);
+
+   /* disables the profile timer signal handler. */
+   it.it_interval.tv_sec = 0;
+   it.it_interval.tv_usec = 0;
+   it.it_value.tv_sec = 0;
+   it.it_value.tv_usec = 0;
+   setitimer(ITIMER_PROF, &it, NULL);
+
+   /* restore the original profile signal handler. */
+   sigaction(SIGPROF, &oldSig, &act);
+   sigaction(SIGSEGV, &oldSegv, &act);
+   profileActive = 0;
+   return;
+}
+
+
+void profileClear(void)
+{
+   int i;
+   nTicks = 0;
+   if( tsym != NULL ) {
+      tSym *sp = &tsym->sym[0];
+      for( i=tsym->n; --i>=0; ++sp ) {
+         sp->count = sp->calls = 0;
+         sp->tick = sp->tcalls = 0;
+      }
+   }
+   if( tmod != NULL ) {
+      tMod *mp = &tmod->mod[0];
+      for( i=tmod->n; --i>=0; ++mp )
+         mp->count = mp->calls = 0;
+   }
+} 
+
+
+void profileShow(void)
+{
+   FILE *fp; int i;
+   double userDt, systDt;
+   double tickDt, realDt;
+   if( tsym == NULL || tmod == NULL ) return;
+   fp = prof_fp;
+   qsort(&tsym->sym[0],tsym->n,sizeof(tsym->sym[0]),cntCmpr);
+   /* outputs sorted (by count) list of functions called. */
+   fprintf(fp,"---- profile start ----\n");
+   fprintf(fp," %d ticks %d modules %d syms\n",nTicks,tmod->n,tsym->n);
+   tSym *sp = &tsym->sym[0];
+   for( i=tsym->n; --i>=0; ++sp ) {
+      if( !sp->count ) continue;
+      tMod *mp = &tmod->mod[sp->mod];
+      fprintf(fp,"%8.3fs %5.1f%% %-24s %s\n",
+        prof_tmrval*sp->count/1000000.0,
+        sp->count*100.0/nTicks,&sp->name[0],
+        &mp->name[0]);
+   }
+
+   qsort(&tsym->sym[0],tsym->n,sizeof(tsym->sym[0]),tclCmpr);
+   /* outputs sorted (by calls) list of functions called. */
+   fprintf(fp,"---- profile calls ----\n");
+   sp = &tsym->sym[0];
+   for( i=tsym->n; --i>=0; ++sp ) {
+      if( !sp->tcalls ) continue;
+      tMod *mp = &tmod->mod[sp->mod];
+      fprintf(fp,"%8.3fs %5.1f%% %-24s %5.1f %s\n",
+        prof_tmrval*sp->tcalls/1000000.0,
+        sp->tcalls*100.0/nTicks,&sp->name[0],
+        (double)sp->calls/sp->tcalls,&mp->name[0]);
+   }
+
+   realDt = ((stop_clk.tv_sec - start_clk.tv_sec) * 1000000.0 +
+               (stop_clk.tv_usec - start_clk.tv_usec) ) / 1000000.0;
+   /* output sorted (by count) list of modules called. */
+   qsort(&tmod->mod[0],tmod->n,sizeof(tmod->mod[0]),modCmpr);
+   fprintf(fp,"----\n");
+   tMod *mp = &tmod->mod[0];
+   for( i=tmod->n; --i>=0; ++mp ) {
+      if( mp->count != 0 && mp->name != NULL ) {
+         double dt = prof_tmrval*mp->count/1000000.0;
+         fprintf(fp,"%8.3fs %5.1f%%/%5.1f%% %s\n",
+            dt,mp->count*100.0/nTicks,dt*100.0/realDt,mp->name);
+      }
+   }
+
+   /* output tick time, cpu user/kernal time, real time. */
+   tickDt = prof_tmrval*nTicks / 1000000.0;
+   userDt = (stop_cpu.tms_utime - start_cpu.tms_utime) / (double)CLOCKS_PER_SEC;
+   systDt = (stop_cpu.tms_stime - start_cpu.tms_stime) / (double)CLOCKS_PER_SEC;
+
+   fprintf(fp,"%8.3ft %0.3fu+%0.3fs %0.3fr %5.1f%%\n",
+      tickDt, userDt, systDt, realDt, tickDt*100.0/realDt);
+   fprintf(fp,"---- profile end ----\n\n");
+   qsort(&tsym->sym[0],tsym->n,sizeof(tsym->sym[0]),adrCmpr);
+}
+
+void profileDone(void)
+{
+   profileStop();
+   delModTbl(&tmod);
+   delSymTbl(&tsym);
+   if( prof_fp != NULL && prof_fp != stdout && prof_fp != stderr ) {
+      fclose(prof_fp);  prof_fp = NULL;
+   }
+}
+
diff --git a/cinelerra-5.1/prof2/smap.C b/cinelerra-5.1/prof2/smap.C
new file mode 100644 (file)
index 0000000..e6887e6
--- /dev/null
@@ -0,0 +1,300 @@
+#include<stdio.h>
+#include<stdint.h>
+#include<stdlib.h>
+#include<string.h>
+#include<unistd.h>
+#include<fcntl.h>
+
+#include<string>
+using namespace std;
+
+#include<elf.h>
+#include<lzma.h>
+#define HAVE_DECL_BASENAME 1
+#include<demangle.h>
+
+// install binutils-dev
+// c++ -Wall -I/usr/include/libiberty -g smap.C -llzma -liberty
+
+typedef uint64_t addr_t;
+
+class smap_t;
+
+class smap_t {
+  static void demangle(const char *cp, char *bp, int n) {
+    const char *dp = cplus_demangle(cp, DMGL_PARAMS+DMGL_ANSI);
+    strncpy(bp, (dp ? dp : cp), n);
+  }
+
+  class chrbfr {
+    char *cp;
+  public:
+    unsigned char *ptr() { return (unsigned char *)cp; }
+    operator char*() { return cp; }
+    chrbfr(int n) { cp = new char[n]; }
+    ~chrbfr() { delete [] cp; }
+  };
+  Elf64_Ehdr elf;
+  FILE *sfp;
+  char *shdrs, *strtbl;
+  addr_t adr_plt;
+  int is_rela;
+  size_t plt_sz;  char *plts;
+  size_t rel_sz;  char *rels;
+  size_t sym_sz, sym_entsize;
+  size_t dyn_sz, dyn_entsize;
+  char *symstr, *symtbl;
+  char *dynstr, *dyntbl;
+  addr_t vofs, pofs;
+  int init();
+  void finit();
+  char *unxz(unsigned char *ibfr, size_t isz, size_t &out);
+  void splt();
+  int sect(int num);
+
+  int rdtbl(char *tbl, off_t ofs, int sz) {
+    if( fseek(sfp, ofs, SEEK_SET) ) return -1;
+    if( fread(tbl, sz, 1, sfp) != 1 ) return -1;
+    return 0;
+  }
+  int ldtbl(char *&tbl, off_t ofs, int sz) {
+    if( !rdtbl(tbl=new char[sz], ofs, sz) ) return 0;
+    delete [] tbl;  tbl = 0;  return -1;
+  }
+public:
+  int symbols();
+
+  smap_t(FILE *fp) {
+    sfp = fp;
+    shdrs = 0;   strtbl = 0;
+    adr_plt = 0; is_rela = -1;
+    plt_sz = 0;  plts = 0;
+    rel_sz = 0;  rels = 0;
+    sym_sz = 0;  sym_entsize = 0;
+    dyn_sz = 0;  dyn_entsize = 0;
+    symstr = 0;  symtbl = 0;
+    dynstr = 0;  dyntbl = 0;
+    vofs = 0;    pofs = 0;
+  }
+  ~smap_t() {
+    delete [] shdrs;  delete [] strtbl;
+    delete [] plts;   delete [] rels;
+    delete [] symstr; delete [] symtbl;
+    delete [] dynstr; delete [] dyntbl;
+  }
+};
+
+
+char *smap_t::
+unxz(unsigned char *ibfr, size_t isz, size_t &out)
+{
+  size_t in = 0, lmt = ~0, osz = 8*isz;
+  unsigned char *obfr = new unsigned char[osz];
+  out = 0;
+  for(;;) {
+    int err = lzma_stream_buffer_decode(&lmt,0,0,
+      ibfr,&in,isz, obfr,&out,osz);
+    if( !err ) return (char *)obfr;
+    if( err != LZMA_BUF_ERROR ) break;
+    size_t nsz = 2*osz;
+    unsigned char *nbfr = new unsigned char[nsz];
+    memcpy(nbfr, obfr, osz);
+    delete [] obfr;  obfr = nbfr;
+    osz = nsz;
+  }
+  delete [] obfr;
+  return 0;
+}
+
+int smap_t::
+sect(int num)
+{
+  Elf64_Shdr *shdr = (Elf64_Shdr *)(shdrs + num * elf.e_shentsize);
+  switch( shdr->sh_type ) {
+  case SHT_REL:
+  case SHT_RELA: {
+    if( !strtbl ) return 0;
+    const char *tp = strtbl + shdr->sh_name;
+    is_rela = shdr->sh_type == SHT_RELA ? 1 : 0;
+    if( strcmp(tp, is_rela ? ".rela.plt" : ".rel.plt") ) return 0;
+    int n = shdr->sh_entsize;
+    int esz = is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel);
+    if( n < esz ) return -1;
+    if( (rel_sz = shdr->sh_size) <= 0 ) return -1;
+    return ldtbl(rels, shdr->sh_offset, rel_sz);
+  }  
+  case SHT_PROGBITS: {
+    if( !strtbl ) return 0;
+    const char *tp = strtbl + shdr->sh_name;
+    if( !strcmp(tp, ".plt") ) {
+      if( (plt_sz = shdr->sh_size) <= 0 ) return -1;
+      adr_plt = shdr->sh_addr;
+      return ldtbl(plts, shdr->sh_offset, plt_sz);
+    }
+    if( !strcmp(tp, ".gnu_debugdata") ) {
+      size_t isz = shdr->sh_size, out = 0;
+      if( !isz ) return -1;
+      chrbfr ibfr(isz);
+      if( rdtbl(ibfr, shdr->sh_offset, isz) ) return -1;
+      char *obfr = unxz(ibfr.ptr(), isz, out);
+      int ret = -1;
+      if( obfr && out > 0 ) {
+        FILE *fp = fmemopen(obfr, out, "r");
+        smap_t dmap(fp);
+        ret = dmap.symbols();
+        fclose(fp);
+      }
+      delete [] obfr;
+      return ret;
+    }
+    return 0;
+  }
+  case SHT_SYMTAB:
+  case SHT_DYNSYM: {
+    size_t &esz = shdr->sh_type == SHT_SYMTAB ? sym_entsize : dyn_entsize;
+    esz = shdr->sh_entsize;
+    if( esz < sizeof(Elf64_Sym) ) return -1;
+    int strtab = shdr->sh_link;
+    if( strtab >= elf.e_shnum ) return -1;
+    Elf64_Shdr *strhdr = (Elf64_Shdr *)(shdrs + strtab * elf.e_shentsize);
+    int ssz = strhdr->sh_size;
+    if( ssz <= 0 ) return -1;
+    char *&str = shdr->sh_type == SHT_SYMTAB ? symstr : dynstr;
+    if( ldtbl(str, strhdr->sh_offset, ssz) ) return -1;
+    size_t &syz = shdr->sh_type == SHT_SYMTAB ? sym_sz : dyn_sz;
+    char *&tbl = shdr->sh_type == SHT_SYMTAB ? symtbl : dyntbl;
+    if( ldtbl(tbl, shdr->sh_offset, syz=shdr->sh_size) ) return -1;
+    int nsy = syz / esz, nsyms = 0;
+    /**/ printf("\n[section %3d] contains [%d] symbols @ 0x%016lx\n", num, nsy, pofs);
+    for( int i=0; i<nsy; ++i ) {
+      Elf64_Sym *sym = (Elf64_Sym *)(tbl + esz*i);
+      char snm[512];
+      demangle(str + sym->st_name, snm, sizeof(snm));
+      int bind = ELF64_ST_BIND(sym->st_info);
+      switch( bind ) {
+      case STB_LOCAL:   break;
+      case STB_GLOBAL:  break;
+      case STB_WEAK:    break;
+      default: continue;
+      }
+      int type = ELF32_ST_TYPE(sym->st_info);
+      switch( type ) {
+      case STT_FUNC:    break;
+/**/  case STT_OBJECT:  break;  // for r_debug
+      default: continue;
+      }
+      int ndx = sym->st_shndx;
+      if( ndx == SHN_UNDEF ) continue;
+      if( ndx >= SHN_LORESERVE ) continue;
+      addr_t adr = sym->st_value - pofs;
+      /**/ int tch = (type == STT_FUNC ? "tTW": "dDW")[bind];
+      /**/ printf("%016lx %c %s\n", adr, tch, snm);
+      ++nsyms;
+    }
+    return nsyms;
+  }
+  default:
+    break;
+  }
+  return 0;
+}
+
+int smap_t::
+init()
+{
+  if( fread(&elf, sizeof(elf), 1, sfp) != 1 ||
+      memcmp(elf.e_ident, ELFMAG, SELFMAG) != 0 ) return -1;
+  // scan region map
+  int psz = elf.e_phentsize, pct = elf.e_phnum;
+  if( psz < (int) sizeof(Elf64_Phdr) || pct < 1 ) return -1;
+  if( fseek(sfp, elf.e_phoff, SEEK_SET) ) return -1;
+  chrbfr pbfr(psz);
+  Elf64_Phdr *phdr = (Elf64_Phdr *) pbfr.ptr();
+  while( --pct >= 0 ) {
+    if( fread(pbfr, psz, 1, sfp) != 1 ) break;
+    if( phdr->p_type == PT_LOAD && phdr->p_offset == 0 ) {
+      vofs = phdr->p_vaddr;
+      pofs = phdr->p_paddr;
+      break;
+    }
+  }
+  // scan sections
+  int n = elf.e_shnum, esz = elf.e_shentsize;
+  if( n <= 0 || esz < (int)sizeof(Elf64_Shdr) ) return -1;
+  if( ldtbl(shdrs, elf.e_shoff, n*esz) ) return -1;
+  // load strtab
+  int sndx = elf.e_shstrndx;
+  if( sndx >= n ) return -1;
+  Elf64_Shdr *stbl = (Elf64_Shdr *)(shdrs + sndx * elf.e_shentsize);
+  return ldtbl(strtbl, stbl->sh_offset, stbl->sh_size);
+}
+
+void smap_t::
+finit()
+{
+  delete [] strtbl; strtbl = 0;
+  delete [] shdrs;  shdrs = 0;
+}
+
+void smap_t::
+splt()
+{
+  if( !plts || !rels ) return;
+  if( !dynstr || !dyntbl ) return;
+  if( is_rela < 0 ) return;
+  int rel_entsize = is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel);
+  int plt_entsize = 0x10;
+  unsigned char *bp = (unsigned char *)plts;
+  for( uint64_t plt_ofs=plt_entsize ; plt_ofs<plt_sz; plt_ofs+=plt_entsize ) {
+    unsigned char *cp = bp + plt_ofs;
+    if( *cp++ != 0xff ) continue;  // opcode jmp rel ind
+    if( *cp++ != 0x25 ) continue;
+    addr_t ofs = 0;
+    for( int k=0; k<32; k+=8 ) { addr_t by=*cp++;  ofs |= by<<k; }
+    ofs += (cp - bp) + adr_plt;
+    uint64_t info = 0;  addr_t addr = 0;  int64_t addend = 0;
+    unsigned char *dp = (unsigned char *)rels;  int found = 0;
+    for( unsigned rel_ofs=0; !found && rel_ofs<rel_sz; rel_ofs+=rel_entsize ) {
+      Elf64_Rel *rp = (Elf64_Rel *)(dp + rel_ofs);
+      Elf64_Rela *rap = (Elf64_Rela *)rp;
+      addr = is_rela ? rap->r_offset : rp->r_offset;
+      info = is_rela ? rap->r_info : rp->r_info;
+      addend = is_rela ? rap->r_addend : 0;
+      if( addr == ofs ) found = 1;
+    }
+    if( !found ) continue;
+    int sndx = ELF64_R_SYM(info);
+    uint64_t dyn_ofs = sndx * dyn_entsize;
+    if( dyn_ofs >= dyn_sz ) continue;
+    Elf64_Sym *sym = (Elf64_Sym *)(dyntbl + dyn_ofs);
+    const char *snm = dynstr + sym->st_name;
+    string pnm(snm);  pnm += "@plt";
+    if( addend ) {
+      char adn[64]; int op = addend>=0 ? '+' : '-';
+      snprintf(adn,sizeof(adn),"%c%ld",op,addend>=0 ? addend : -addend);
+      pnm += adn;
+    }
+    addr_t adr = adr_plt + plt_ofs - pofs;
+    /**/ printf("%016lx %c %s\n", adr, 't', pnm.c_str());
+  }
+}
+
+int smap_t::
+symbols()
+{
+  if( init() >= 0 ) {
+    int n = elf.e_shnum;
+    for( int i=0; i<n; ++i ) sect(i);
+    splt();
+  }
+  return 0;
+}
+
+
+int main(int ac, char **av)
+{
+  smap_t smap(stdin);
+  smap.symbols();
+  return 0;
+}
+
diff --git a/cinelerra-5.1/prof2/tst.c b/cinelerra-5.1/prof2/tst.c
new file mode 100644 (file)
index 0000000..a641ec0
--- /dev/null
@@ -0,0 +1,31 @@
+#include <stdio.h>
+
+void tst0()
+{
+   printf(".");
+}
+
+void tst1()
+{
+   printf("\r");
+}
+
+void tst2(int n)
+{
+   volatile int i = n;
+   while( --i >= 0 );
+   if( (n&1) != 0 ) tst1(); else tst0();
+}
+
+int main(int ac, char **av,char **ev)
+{
+   int i;
+   //profileStart();
+   setbuf(stdout,NULL);
+   printf("ok. %s\n",ev[0]);
+   for( i=30000; --i>=0; ) tst2(i);
+   printf("\n");
+   printf("done\n");
+   return 0;
+}
+