Back to index

cell-binutils  2.17cvs20070401
tahoe.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1983, 1993, 2001
00003  *      The Regents of the University of California.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 #include "gprof.h"
00030 #include "search_list.h"
00031 #include "source.h"
00032 #include "symtab.h"
00033 #include "cg_arcs.h"
00034 #include "corefile.h"
00035 #include "hist.h"
00036 
00037     /*
00038      *        opcode of the `callf' instruction
00039      */
00040 #define       CALLF  0xfe
00041 
00042     /*
00043      *        register for pc relative addressing
00044      */
00045 #define       PC     0xf
00046 
00047 enum tahoe_opermodes
00048   {
00049     literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
00050     bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
00051     immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
00052     longrel, longreldef
00053   };
00054 typedef enum tahoe_opermodes tahoe_operandenum;
00055 
00056 /*
00057  * A symbol to be the child of indirect callf:
00058  */
00059 static Sym indirectchild;
00060 
00061 static tahoe_operandenum tahoe_operandmode (unsigned char *);
00062 static char *tahoe_operandname (tahoe_operandenum);
00063 static long tahoe_operandlength (unsigned char *);
00064 static bfd_signed_vma tahoe_offset (unsigned char *);
00065 void tahoe_find_call (Sym *, bfd_vma, bfd_vma);
00066 
00067 static tahoe_operandenum
00068 tahoe_operandmode (unsigned char *modep)
00069 {
00070   long usesreg = *modep & 0xf;
00071 
00072   switch ((*modep >> 4) & 0xf)
00073     {
00074     case 0:
00075     case 1:
00076     case 2:
00077     case 3:
00078       return literal;
00079     case 4:
00080       return indexed;
00081     case 5:
00082       return reg;
00083     case 6:
00084       return regdef;
00085     case 7:
00086       return autodec;
00087     case 8:
00088       return usesreg != 0xe ? autoinc : immediate;
00089     case 9:
00090       return usesreg != PC ? autoincdef : absolute;
00091     case 10:
00092       return usesreg != PC ? bytedisp : byterel;
00093     case 11:
00094       return usesreg != PC ? bytedispdef : bytereldef;
00095     case 12:
00096       return usesreg != PC ? worddisp : wordrel;
00097     case 13:
00098       return usesreg != PC ? worddispdef : wordreldef;
00099     case 14:
00100       return usesreg != PC ? longdisp : longrel;
00101     case 15:
00102       return usesreg != PC ? longdispdef : longreldef;
00103     }
00104   /* NOTREACHED */
00105   abort ();
00106 }
00107 
00108 static char *
00109 tahoe_operandname (tahoe_operandenum mode)
00110 {
00111 
00112   switch (mode)
00113     {
00114     case literal:
00115       return "literal";
00116     case indexed:
00117       return "indexed";
00118     case reg:
00119       return "register";
00120     case regdef:
00121       return "register deferred";
00122     case autodec:
00123       return "autodecrement";
00124     case autoinc:
00125       return "autoincrement";
00126     case autoincdef:
00127       return "autoincrement deferred";
00128     case bytedisp:
00129       return "byte displacement";
00130     case bytedispdef:
00131       return "byte displacement deferred";
00132     case byterel:
00133       return "byte relative";
00134     case bytereldef:
00135       return "byte relative deferred";
00136     case worddisp:
00137       return "word displacement";
00138     case worddispdef:
00139       return "word displacement deferred";
00140     case wordrel:
00141       return "word relative";
00142     case wordreldef:
00143       return "word relative deferred";
00144     case immediate:
00145       return "immediate";
00146     case absolute:
00147       return "absolute";
00148     case longdisp:
00149       return "long displacement";
00150     case longdispdef:
00151       return "long displacement deferred";
00152     case longrel:
00153       return "long relative";
00154     case longreldef:
00155       return "long relative deferred";
00156     }
00157   /* NOTREACHED */
00158   abort ();
00159 }
00160 
00161 static long
00162 tahoe_operandlength (unsigned char *modep
00163 )
00164 {
00165 
00166   switch (tahoe_operandmode (modep))
00167     {
00168     case literal:
00169     case reg:
00170     case regdef:
00171     case autodec:
00172     case autoinc:
00173     case autoincdef:
00174       return 1;
00175     case bytedisp:
00176     case bytedispdef:
00177     case byterel:
00178     case bytereldef:
00179       return 2;
00180     case worddisp:
00181     case worddispdef:
00182     case wordrel:
00183     case wordreldef:
00184       return 3;
00185     case immediate:
00186     case absolute:
00187     case longdisp:
00188     case longdispdef:
00189     case longrel:
00190     case longreldef:
00191       return 5;
00192     case indexed:
00193       return 1 + tahoe_operandlength (modep + 1);
00194     }
00195   /* NOTREACHED */
00196   abort ();
00197 }
00198 
00199 static bfd_signed_vma
00200 tahoe_offset (unsigned char *modep)
00201 {
00202   tahoe_operandenum mode = tahoe_operandmode (modep);
00203 
00204   ++modep;                         /* skip over the mode */
00205   switch (mode)
00206     {
00207     default:
00208       fprintf (stderr, "[reladdr] not relative address\n");
00209       return 0;
00210     case byterel:
00211       return 1 + bfd_get_signed_8 (core_bfd, modep);
00212     case wordrel:
00213       return 2 + bfd_get_signed_16 (core_bfd, modep);
00214     case longrel:
00215       return 4 + bfd_get_signed_32 (core_bfd, modep);
00216     }
00217 }
00218 
00219 void
00220 tahoe_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
00221 {
00222   unsigned char *instructp;
00223   long length;
00224   Sym *child;
00225   tahoe_operandenum mode;
00226   tahoe_operandenum firstmode;
00227   bfd_vma pc, destpc;
00228   static bfd_boolean inited = FALSE;
00229 
00230   if (!inited)
00231     {
00232       inited = TRUE;
00233       sym_init (&indirectchild);
00234       indirectchild.cg.prop.fract = 1.0;
00235       indirectchild.cg.cyc.head = &indirectchild;
00236     }
00237 
00238   if (core_text_space == 0)
00239     {
00240       return;
00241     }
00242   if (p_lowpc < s_lowpc)
00243     {
00244       p_lowpc = s_lowpc;
00245     }
00246   if (p_highpc > s_highpc)
00247     {
00248       p_highpc = s_highpc;
00249     }
00250   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
00251                        parent->name, (unsigned long) p_lowpc,
00252                        (unsigned long) p_highpc));
00253   for (pc = p_lowpc; pc < p_highpc; pc += length)
00254     {
00255       length = 1;
00256       instructp = ((unsigned char *) core_text_space
00257                  + pc - core_text_sect->vma);
00258       if ((*instructp & 0xff) == CALLF)
00259        {
00260          /*
00261           *    maybe a callf, better check it out.
00262           *      skip the count of the number of arguments.
00263           */
00264          DBG (CALLDEBUG, printf ("[findcall]\t0x%lx:callf",
00265                               (unsigned long) pc));
00266          firstmode = tahoe_operandmode (instructp + length);
00267          switch (firstmode)
00268            {
00269            case literal:
00270            case immediate:
00271              break;
00272            default:
00273              goto botched;
00274            }
00275          length += tahoe_operandlength (instructp + length);
00276          mode = tahoe_operandmode (instructp + length);
00277          DBG (CALLDEBUG,
00278               printf ("\tfirst operand is %s", tahoe_operandname (firstmode));
00279               printf ("\tsecond operand is %s\n", tahoe_operandname (mode));
00280            );
00281          switch (mode)
00282            {
00283            case regdef:
00284            case bytedispdef:
00285            case worddispdef:
00286            case longdispdef:
00287            case bytereldef:
00288            case wordreldef:
00289            case longreldef:
00290              /*
00291               *    indirect call: call through pointer
00292               *      either  *d(r)   as a parameter or local
00293               *              (r)     as a return value
00294               *              *f      as a global pointer
00295               *      [are there others that we miss?,
00296               *       e.g. arrays of pointers to functions???]
00297               */
00298              arc_add (parent, &indirectchild, (unsigned long) 0);
00299              length += tahoe_operandlength (instructp + length);
00300              continue;
00301            case byterel:
00302            case wordrel:
00303            case longrel:
00304              /*
00305               *    regular pc relative addressing
00306               *      check that this is the address of
00307               *      a function.
00308               */
00309              destpc = pc + tahoe_offset (instructp + length);
00310              if (destpc >= s_lowpc && destpc <= s_highpc)
00311               {
00312                 child = sym_lookup (&symtab, destpc);
00313                 DBG (CALLDEBUG,
00314                      printf ("[findcall]\tdestpc 0x%lx",
00315                             (unsigned long) destpc);
00316                      printf (" child->name %s", child->name);
00317                      printf (" child->addr 0x%lx\n",
00318                             (unsigned long) child->addr);
00319                   );
00320                 if (child->addr == destpc)
00321                   {
00322                     /*
00323                      *    a hit
00324                      */
00325                     arc_add (parent, child, (unsigned long) 0);
00326                     length += tahoe_operandlength (instructp + length);
00327                     continue;
00328                   }
00329                 goto botched;
00330               }
00331              /*
00332               *    else:
00333               *      it looked like a callf,
00334               *      but it wasn't to anywhere.
00335               */
00336              goto botched;
00337            default:
00338            botched:
00339              /*
00340               *    something funny going on.
00341               */
00342              DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
00343              length = 1;
00344              continue;
00345            }
00346        }
00347     }
00348 }