Back to index

cell-binutils  2.17cvs20070401
vax.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 `calls' instruction
00039      */
00040 #define       CALLS  0xfb
00041 
00042     /*
00043      *        register for pc relative addressing
00044      */
00045 #define       PC     0xf
00046 
00047 enum 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 opermodes operandenum;
00055 
00056 /* *INDENT-OFF* */
00057 /* Here to document only.  We can't use this when cross compiling as
00058    the bitfield layout might not be the same as native.
00059 
00060    struct modebyte
00061      {
00062        unsigned int regfield:4;
00063        unsigned int modefield:4;
00064      };
00065 */
00066 /* *INDENT-ON* */
00067 
00068 /*
00069  * A symbol to be the child of indirect calls:
00070  */
00071 static Sym indirectchild;
00072 
00073 static operandenum vax_operandmode (unsigned char *);
00074 static char *vax_operandname (operandenum);
00075 static long vax_operandlength (unsigned char *);
00076 static bfd_signed_vma vax_offset (unsigned char *);
00077 void vax_find_call (Sym *, bfd_vma, bfd_vma);
00078 
00079 static operandenum
00080 vax_operandmode (unsigned char *modep)
00081 {
00082   int usesreg = *modep & 0xf;
00083 
00084   switch ((*modep >> 4) & 0xf)
00085     {
00086     case 0:
00087     case 1:
00088     case 2:
00089     case 3:
00090       return literal;
00091     case 4:
00092       return indexed;
00093     case 5:
00094       return reg;
00095     case 6:
00096       return regdef;
00097     case 7:
00098       return autodec;
00099     case 8:
00100       return usesreg != PC ? autoinc : immediate;
00101     case 9:
00102       return usesreg != PC ? autoincdef : absolute;
00103     case 10:
00104       return usesreg != PC ? bytedisp : byterel;
00105     case 11:
00106       return usesreg != PC ? bytedispdef : bytereldef;
00107     case 12:
00108       return usesreg != PC ? worddisp : wordrel;
00109     case 13:
00110       return usesreg != PC ? worddispdef : wordreldef;
00111     case 14:
00112       return usesreg != PC ? longdisp : longrel;
00113     case 15:
00114       return usesreg != PC ? longdispdef : longreldef;
00115     }
00116   /* NOTREACHED */
00117   abort ();
00118 }
00119 
00120 static char *
00121 vax_operandname (operandenum mode)
00122 {
00123 
00124   switch (mode)
00125     {
00126     case literal:
00127       return "literal";
00128     case indexed:
00129       return "indexed";
00130     case reg:
00131       return "register";
00132     case regdef:
00133       return "register deferred";
00134     case autodec:
00135       return "autodecrement";
00136     case autoinc:
00137       return "autoincrement";
00138     case autoincdef:
00139       return "autoincrement deferred";
00140     case bytedisp:
00141       return "byte displacement";
00142     case bytedispdef:
00143       return "byte displacement deferred";
00144     case byterel:
00145       return "byte relative";
00146     case bytereldef:
00147       return "byte relative deferred";
00148     case worddisp:
00149       return "word displacement";
00150     case worddispdef:
00151       return "word displacement deferred";
00152     case wordrel:
00153       return "word relative";
00154     case wordreldef:
00155       return "word relative deferred";
00156     case immediate:
00157       return "immediate";
00158     case absolute:
00159       return "absolute";
00160     case longdisp:
00161       return "long displacement";
00162     case longdispdef:
00163       return "long displacement deferred";
00164     case longrel:
00165       return "long relative";
00166     case longreldef:
00167       return "long relative deferred";
00168     }
00169   /* NOTREACHED */
00170   abort ();
00171 }
00172 
00173 static long
00174 vax_operandlength (unsigned char *modep)
00175 {
00176 
00177   switch (vax_operandmode (modep))
00178     {
00179     case literal:
00180     case reg:
00181     case regdef:
00182     case autodec:
00183     case autoinc:
00184     case autoincdef:
00185       return 1;
00186     case bytedisp:
00187     case bytedispdef:
00188     case byterel:
00189     case bytereldef:
00190       return 2;
00191     case worddisp:
00192     case worddispdef:
00193     case wordrel:
00194     case wordreldef:
00195       return 3;
00196     case immediate:
00197     case absolute:
00198     case longdisp:
00199     case longdispdef:
00200     case longrel:
00201     case longreldef:
00202       return 5;
00203     case indexed:
00204       return 1 + vax_operandlength (modep + 1);
00205     }
00206   /* NOTREACHED */
00207   abort ();
00208 }
00209 
00210 static bfd_signed_vma
00211 vax_offset (unsigned char *modep)
00212 {
00213   operandenum mode = vax_operandmode (modep);
00214 
00215   ++modep;                         /* skip over the mode */
00216   switch (mode)
00217     {
00218     default:
00219       fprintf (stderr, "[reladdr] not relative address\n");
00220       return 0;
00221     case byterel:
00222       return 1 + bfd_get_signed_8 (core_bfd, modep);
00223     case wordrel:
00224       return 2 + bfd_get_signed_16 (core_bfd, modep);
00225     case longrel:
00226       return 4 + bfd_get_signed_32 (core_bfd, modep);
00227     }
00228 }
00229 
00230 
00231 void
00232 vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
00233 {
00234   unsigned char *instructp;
00235   long length;
00236   Sym *child;
00237   operandenum mode;
00238   operandenum firstmode;
00239   bfd_vma pc, destpc;
00240   static bfd_boolean inited = FALSE;
00241 
00242   if (!inited)
00243     {
00244       inited = TRUE;
00245       sym_init (&indirectchild);
00246       indirectchild.cg.prop.fract = 1.0;
00247       indirectchild.cg.cyc.head = &indirectchild;
00248     }
00249 
00250   if (core_text_space == 0)
00251     {
00252       return;
00253     }
00254   if (p_lowpc < s_lowpc)
00255     {
00256       p_lowpc = s_lowpc;
00257     }
00258   if (p_highpc > s_highpc)
00259     {
00260       p_highpc = s_highpc;
00261     }
00262   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
00263                        parent->name, (unsigned long) p_lowpc,
00264                        (unsigned long) p_highpc));
00265   for (pc = p_lowpc; pc < p_highpc; pc += length)
00266     {
00267       length = 1;
00268       instructp = ((unsigned char *) core_text_space
00269                  + pc - core_text_sect->vma);
00270       if ((*instructp & 0xff) == CALLS)
00271        {
00272          /*
00273           *    maybe a calls, better check it out.
00274           *      skip the count of the number of arguments.
00275           */
00276          DBG (CALLDEBUG,
00277               printf ("[findcall]\t0x%lx:calls", (unsigned long) pc));
00278          firstmode = vax_operandmode (instructp + length);
00279          switch (firstmode)
00280            {
00281            case literal:
00282            case immediate:
00283              break;
00284            default:
00285              goto botched;
00286            }
00287          length += vax_operandlength (instructp + length);
00288          mode = vax_operandmode (instructp + length);
00289          DBG (CALLDEBUG,
00290               printf ("\tfirst operand is %s", vax_operandname (firstmode));
00291               printf ("\tsecond operand is %s\n", vax_operandname (mode)));
00292          switch (mode)
00293            {
00294            case regdef:
00295            case bytedispdef:
00296            case worddispdef:
00297            case longdispdef:
00298            case bytereldef:
00299            case wordreldef:
00300            case longreldef:
00301              /*
00302               *    indirect call: call through pointer
00303               *      either  *d(r)   as a parameter or local
00304               *              (r)     as a return value
00305               *              *f      as a global pointer
00306               *      [are there others that we miss?,
00307               *       e.g. arrays of pointers to functions???]
00308               */
00309              arc_add (parent, &indirectchild, (unsigned long) 0);
00310              length += vax_operandlength (instructp + length);
00311              continue;
00312            case byterel:
00313            case wordrel:
00314            case longrel:
00315              /*
00316               *    regular pc relative addressing
00317               *      check that this is the address of
00318               *      a function.
00319               */
00320              destpc = pc + vax_offset (instructp + length);
00321              if (destpc >= s_lowpc && destpc <= s_highpc)
00322               {
00323                 child = sym_lookup (&symtab, destpc);
00324                 DBG (CALLDEBUG,
00325                      printf ("[findcall]\tdestpc 0x%lx",
00326                             (unsigned long) destpc);
00327                      printf (" child->name %s", child->name);
00328                      printf (" child->addr 0x%lx\n",
00329                             (unsigned long) child->addr);
00330                   );
00331                 if (child->addr == destpc)
00332                   {
00333                     /*
00334                      *    a hit
00335                      */
00336                     arc_add (parent, child, (unsigned long) 0);
00337                     length += vax_operandlength (instructp + length);
00338                     continue;
00339                   }
00340                 goto botched;
00341               }
00342              /*
00343               *    else:
00344               *      it looked like a calls,
00345               *      but it wasn't to anywhere.
00346               */
00347              goto botched;
00348            default:
00349            botched:
00350              /*
00351               *    something funny going on.
00352               */
00353              DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
00354              length = 1;
00355              continue;
00356            }
00357        }
00358     }
00359 }