New files:
  - vg_cachesim.c
  - vg_cachesim_{I1,D1,L2}.c
  - vg_annotate.in
  - vg_cachegen.in

Changes to existing files:

  - valgrind/valgrind.in, added option:

        --cachesim=no|yes       [no]

  - Makefile/Makefile.am:
        * added vg_cachesim.c to valgrind_so_SOURCES var
        * added vg_cachesim_I1.c, vg_cachesim_D1.c, vg_cachesim_L2.c to
          noinst_HEADERS var
        * added vg_annotate, vg_cachegen to 'bin_SCRIPTS' var, and added empty
          targets for them

  - vg_main.c:
        * added two offsets for cache sim functions (put in positions 17a,17b)
        * added option handling (detection of --cachesim=yes which turns off of
          --instrument);
        * added calls to cachesim initialisation/finalisation functions

  - vg_mylibc: added some system call wrappers (for chmod, open_write, etc) for
    file writing

  - vg_symtab2.c:
        * allow it to read symbols if either of --instrument or --cachesim is
          used
        * made vg_symtab2.c:vg_what_{line,fn}_is_this extern, renaming it as
          VG_(what_line_is_this) (and added to vg_include.h)
        * completely rewrote the read loop in vg_read_lib_symbols, fixing
          several bugs.  Much better now, although probably not perfect.  It's
          also relatively fragile -- I'm using the "die immediately if anything
          unexpected happens" approach.

  - vg_to_ucode.c:
        * in VG_(disBB), patching in x86 instruction size into extra4b field of
          JMP instructions at the end of basic blocks if --cachesim=yes.
          Shifted things around to do this;  also had to fiddle around with
          single-step stuff to get this to work, by not sticking extra JMPs on
          the end of the single-instruction block if there was already one
          there (to avoid breaking an assertion in vg_cachesim.c).  Did a
          similar thing to avoid an extra JMP on huge basic blocks that are
          split.

  - vg_translate.c:
        * if --cachesim=yes call the cachesim instrumentation phase
        * made some functions extern and renamed:
                allocCodeBlock() --> VG_(allocCodeBlock)()
                freeCodeBlock()  --> VG_(freeCodeBlock)()
                copyUInstr()     --> VG_(copyUInstr)()
          (added to vg_include.h too)

  - vg_include.c: declared
        * cachesim offsets
        * exports of vg_cachesim.c
        * added four new profiling events (increasing VGP_M_CCS to 24 -- I kept
          the spare ones)
        * added comment about UInstr.extra4b field being used for instr size in
          JMPs for cache simulation

  - docs/manual.html:
        * Added --cachesim option to section 2.5.
        * Added cache profiling stuff as section 7.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@168 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c
index 74cada4..d9da8ff 100644
--- a/coregrind/vg_symtab2.c
+++ b/coregrind/vg_symtab2.c
@@ -1,4 +1,3 @@
-
 /*--------------------------------------------------------------------*/
 /*--- Management of symbols and debugging information.             ---*/
 /*---                                                 vg_symtab2.c ---*/
@@ -50,6 +49,23 @@
 /*--- Structs n stuff                                      ---*/
 /*------------------------------------------------------------*/
 
+/* Stabs entry types, from:
+ *   The "stabs" debug format
+ *   Menapace, Kingdon and MacKenzie
+ *   Cygnus Support
+ */
+typedef enum { N_FUN   = 36,    /* Function start or end            */
+               N_STSYM = 38,    /* Data segment file-scope variable */
+               N_LCSYM = 40,    /* BSS segment file-scope variable  */
+               N_RSYM  = 64,    /* Register variable                */
+               N_SLINE = 68,    /* Source line number               */
+               N_SO    = 100,   /* Source file path and name        */
+               N_LSYM  = 128,   /* Stack variable or type           */
+               N_SOL   = 132,   /* Include file name                */
+               N_LBRAC = 192,   /* Start of lexical block           */
+               N_RBRAC = 224    /* End   of lexical block           */
+             } stab_types;
+      
 /* A structure to hold an ELF symbol (very crudely). */
 typedef 
    struct { 
@@ -535,12 +551,7 @@
 {
    RiLoc loc;
    UInt size = end - start + 1;
-#  if 0
-   if (size > 10000)
-   VG_(printf)( "line %4d: %p .. %p, in %s\n",
-                lineno, start, end, 
-                &si->strtab[fnmoff] );
-#  endif
+
    /* Sanity ... */
    if (size > 10000) return;
 
@@ -577,8 +588,8 @@
    /* for the .stabs reader */
    Int    curr_filenmoff;
    Addr   curr_fnbaseaddr;
-   Addr   range_startAddr;
-   Int    range_lineno;
+   Char*  curr_file_name;
+   Int    n_stab_entries;
 
    oimage = (Addr)NULL;
    if (VG_(clo_verbosity) > 1)
@@ -880,25 +891,23 @@
    /* Ok.  It all looks plausible.  Go on and read debug data. 
          stab kinds: 100   N_SO     a source file name
                       68   N_SLINE  a source line number
-                      36   N_FUN ?  start of a function
+                      36   N_FUN    start of a function
 
-      In this loop, we maintain a current file name, updated
-      as N_SOs appear, and a current function base address,
-      updated as N_FUNs appear.  Based on that, address ranges
-      for N_SLINEs are calculated, and stuffed into the 
-      line info table.
+      In this loop, we maintain a current file name, updated as 
+      N_SO/N_SOLs appear, and a current function base address, 
+      updated as N_FUNs appear.  Based on that, address ranges for 
+      N_SLINEs are calculated, and stuffed into the line info table.
 
-      N_SLINE indicates the start of a source line.  Functions are
-      delimited by N_FUNS, at the start with a non-empty string and at
-      the end with an empty string.  The latter facilitates detecting
-      where to close the last N_SLINE for a function. 
+      Finding the instruction address range covered by an N_SLINE is
+      complicated;  see the N_SLINE case below.
    */
    curr_filenmoff  = addStr(si,"???");
    curr_fnbaseaddr = (Addr)NULL;
-   range_startAddr = 0;
-   range_lineno    = 0;
+   curr_file_name  = (Char*)NULL;
 
-   for (i = 0; i < stab_sz/(int)sizeof(struct nlist); i++) {
+   n_stab_entries = stab_sz/(int)sizeof(struct nlist);
+
+   for (i = 0; i < n_stab_entries; i++) {
 #     if 0
       VG_(printf) ( "   %2d  ", i );
       VG_(printf) ( "type=0x%x   othr=%d   desc=%d   value=0x%x   strx=%d  %s",
@@ -910,61 +919,95 @@
 #     endif
 
       switch (stab[i].n_type) {
+         UInt next_addr;
 
-         case 68: { /* N_SLINE */
-            /* flush the current line, if any, and start a new one */
-            Addr range_endAddr 
-               = curr_fnbaseaddr 
-                    + (UInt)stab[i].n_value - 1;
-            if (range_startAddr != 0) {
-               addLineInfo ( si,
-                             curr_filenmoff,
-                             range_startAddr,
-                             range_endAddr,
-                             range_lineno );
+         /* To compute the instr address range covered by a single line, find
+          * the address of the next thing and compute the difference.  The
+          * approach used depends on what kind of entry/entries follow... */
+         case N_SLINE: {
+            Int lineno = stab[i].n_desc;              
+            Int this_addr = (UInt)stab[i].n_value;
+
+            LOOP:
+            vg_assert(i+1 < n_stab_entries);    /* Haven't reached end */
+            switch (stab[i+1].n_type) {
+               /* Easy, common case: use address of next entry */
+               case N_SLINE: case N_SO:
+                  next_addr = (UInt)stab[i+1].n_value;
+                  break;
+
+               /* Boring one: skip, look for something more useful. */
+               case N_RSYM: case N_LSYM: case N_LBRAC: case N_RBRAC: 
+               case N_STSYM: case N_LCSYM:
+                  i++;
+                  goto LOOP;
+                  
+               /* Should be an end of fun entry, use its address */
+               case N_FUN: 
+                  if ('\0' == * (stabstr + stab[i+1].n_un.n_strx) ) {
+                     next_addr = (UInt)stab[i+1].n_value;
+                  } else {
+                     VG_(printf)("unhandled stabs case: N_FUN start %d %s\n",
+                                i, (stabstr + stab[i+1].n_un.n_strx) );
+                     VG_(panic)("argh");
+                  }
+                  break;
+
+               /* N_SOL should be followed by an N_SLINE which can be used */
+               case N_SOL:
+                  if (i+2 < n_stab_entries && N_SLINE == stab[i+2].n_type) {
+                     next_addr = (UInt)stab[i+2].n_value;
+                     break;
+                  } else {
+                     VG_(printf)("unhandled N_SOL stabs case: %d %d %d", 
+                                 stab[i+1].n_type, i, n_stab_entries);
+                     VG_(panic)("argh");
+                  }
+
+               default:
+                  VG_(printf)("unhandled stabs case: %d %d", 
+                              stab[i+1].n_type,i);
+                  VG_(panic)("argh");
             }
-            range_startAddr = range_endAddr + 1;
-            range_lineno = stab[i].n_desc;              
+            
+            //Int offset2 = (i+1 < n_stab_entries && 68 == stab[i+1].n_type
+            //              ? (UInt)stab[i+1].n_value - 1
+            //              : offset + 1);
+            //if (i+1 < n_stab_entries) {
+            //    int x;
+            //    if (68 != (x = stab[i+1].n_type)) {
+            //        VG_(printf)("%d  ", x);
+            //    }
+            //}
+
+            addLineInfo ( si, curr_filenmoff, curr_fnbaseaddr + this_addr, 
+                          curr_fnbaseaddr + next_addr - 1, lineno );
             break;
          }
 
-         case 36: { /* N_FUN */
-            if ('\0' == * (stabstr + stab[i].n_un.n_strx) ) {
-               /* N_FUN with no name -- indicates the end of a fn.
-                  Flush the current line, if any, but don't start a
-                  new one. */
-               Addr range_endAddr 
-                  = curr_fnbaseaddr 
-                       + (UInt)stab[i].n_value - 1;
-               if (range_startAddr != 0) {
-                  addLineInfo ( si,
-                                curr_filenmoff,
-                                range_startAddr,
-                                range_endAddr,
-                                range_lineno );
-               }
-               range_startAddr = 0;
-            } else {
+         case N_FUN: {
+            if ('\0' != (stabstr + stab[i].n_un.n_strx)[0] ) {
                /* N_FUN with a name -- indicates the start of a fn.  */
-               curr_fnbaseaddr = si->offset
-                                 + (Addr)stab[i].n_value;
-               range_startAddr = curr_fnbaseaddr;
+               curr_fnbaseaddr = si->offset + (Addr)stab[i].n_value;
             }
             break;
          }
 
-         case 100: /* N_SO */
-         case 132: /* N_SOL */
+         case N_SO: case N_SOL:
          /* seems to give lots of locations in header files */
          /* case 130: */ /* BINCL */
          { 
             UChar* nm = stabstr + stab[i].n_un.n_strx;
             UInt len = VG_(strlen)(nm);
-            if (len > 0 && nm[len-1] != '/')
+            
+            if (len > 0 && nm[len-1] != '/') {
                curr_filenmoff = addStr ( si, nm );
+               curr_file_name = stabstr + stab[i].n_un.n_strx;
+            }
             else
                if (len == 0)
                   curr_filenmoff = addStr ( si, "?1\0" );
+
             break;
          }
 
@@ -1071,8 +1114,8 @@
    which happen to correspond to the munmap()d area.  */
 void VG_(read_symbols) ( void )
 {
-   if (! VG_(clo_instrument)) 
-     return;
+   if (! VG_(clo_instrument) && ! VG_(clo_cachesim)) 
+      return;
 
    VG_(read_procselfmaps) ( read_symtab_callback );
 
@@ -1251,9 +1294,8 @@
    Caller supplies buf and nbuf.  If no_demangle is True, don't do
    demangling, regardless of vg_clo_demangle -- probably because the
    call has come from vg_what_fn_or_object_is_this. */
-static
-Bool vg_what_fn_is_this ( Bool no_demangle, Addr a, 
-                          Char* buf, Int nbuf )
+Bool VG_(what_fn_is_this) ( Bool no_demangle, Addr a, 
+                            Char* buf, Int nbuf )
 {
    SegInfo* si;
    Int      sno;
@@ -1297,17 +1339,16 @@
                                      Char* fun_buf, Int n_fun_buf )
 {
    (void)vg_what_object_is_this ( a, obj_buf, n_obj_buf );
-   (void)vg_what_fn_is_this ( True, a, fun_buf, n_fun_buf );
+   (void)VG_(what_fn_is_this) ( True, a, fun_buf, n_fun_buf );
 }
 
 
 /* Map a code address to a (filename, line number) pair.  
    Returns True if successful.
 */
-static
-Bool vg_what_line_is_this ( Addr a, 
-                            UChar* filename, Int n_filename, 
-                            UInt* lineno )
+Bool VG_(what_line_is_this)( Addr a, 
+                             UChar* filename, Int n_filename, 
+                             UInt* lineno )
 {
    SegInfo* si;
    Int      locno;
@@ -1317,6 +1358,7 @@
    VG_(strncpy_safely)(filename, & si->strtab[si->loctab[locno].fnmoff], 
                        n_filename);
    *lineno = si->loctab[locno].lineno;
+
    return True;
 }
 
@@ -1348,11 +1390,11 @@
 
    n = 0;
 
-   know_fnname  = vg_what_fn_is_this(False,ec->eips[0], buf_fn, M_VG_ERRTXT);
+   know_fnname  = VG_(what_fn_is_this)(False,ec->eips[0], buf_fn, M_VG_ERRTXT);
    know_objname = vg_what_object_is_this(ec->eips[0], buf_obj, M_VG_ERRTXT);
-   know_srcloc  = vg_what_line_is_this(ec->eips[0], 
-                                       buf_srcloc, M_VG_ERRTXT, 
-                                       &lineno);
+   know_srcloc  = VG_(what_line_is_this)(ec->eips[0], 
+                                         buf_srcloc, M_VG_ERRTXT, 
+                                         &lineno);
 
    APPEND("   at ");
    VG_(sprintf)(ibuf,"0x%x: ", ec->eips[0]);
@@ -1383,9 +1425,9 @@
 
    clueless = 0;
    for (i = 1; i < stop_at; i++) {
-      know_fnname  = vg_what_fn_is_this(False,ec->eips[i], buf_fn, M_VG_ERRTXT);
+      know_fnname  = VG_(what_fn_is_this)(False,ec->eips[i], buf_fn, M_VG_ERRTXT);
       know_objname = vg_what_object_is_this(ec->eips[i],buf_obj, M_VG_ERRTXT);
-      know_srcloc  = vg_what_line_is_this(ec->eips[i], 
+      know_srcloc  = VG_(what_line_is_this)(ec->eips[i], 
                                           buf_srcloc, M_VG_ERRTXT, 
                                           &lineno);
       n = 0;