1 /*
   2  * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *
  23  */
  24 
  25 /* hsdis.c -- dump a range of addresses as native instructions
  26    This implements the plugin protocol required by the
  27    HotSpot PrintAssembly option.
  28 */
  29 
  30 #include "hsdis.h"
  31 #include <libiberty.h>
  32 #include <bfd.h>
  33 #include <dis-asm.h>
  34 #include <inttypes.h>
  35 #include <string.h>
  36 #include <errno.h>
  37 
  38 #ifndef bool
  39 #define bool int
  40 #define true 1
  41 #define false 0
  42 #endif /*bool*/
  43 
  44 /* short names for stuff in hsdis.h */
  45 typedef decode_instructions_event_callback_ftype  event_callback_t;
  46 typedef decode_instructions_printf_callback_ftype printf_callback_t;
  47 
  48 /* disassemble_info.application_data object */
  49 struct hsdis_app_data {
  50   uintptr_t start_va, end_va; /* virtual address of data */
  51   /* the arguments to decode_instructions */
  52   uintptr_t start; uintptr_t end;
  53   event_callback_t  event_callback;  void* event_stream;
  54   printf_callback_t printf_callback; void* printf_stream;
  55   bool losing;
  56 
  57   /* the architecture being disassembled */
  58   const char* arch_name;
  59   const bfd_arch_info_type* arch_info;
  60 
  61   /* the disassembler we are going to use: */
  62   disassembler_ftype      dfn;
  63   struct disassemble_info dinfo; /* the actual struct! */
  64 
  65   char mach_option[64];
  66   char insn_options[256];
  67 };
  68 
  69 #define DECL_APP_DATA(dinfo) \
  70   struct hsdis_app_data* app_data = (struct hsdis_app_data*) (dinfo)->application_data
  71 
  72 #define DECL_EVENT_CALLBACK(app_data) \
  73   event_callback_t  event_callback = (app_data)->event_callback; \
  74   void*             event_stream   = (app_data)->event_stream
  75 
  76 #define DECL_PRINTF_CALLBACK(app_data) \
  77   printf_callback_t  printf_callback = (app_data)->printf_callback; \
  78   void*              printf_stream   = (app_data)->printf_stream
  79 
  80 
  81 static void print_help(struct hsdis_app_data* app_data,
  82                        const char* msg, const char* arg);
  83 static void setup_app_data(struct hsdis_app_data* app_data,
  84                            const char* options);
  85 static const char* format_insn_close(const char* close,
  86                                      disassemble_info* dinfo,
  87                                      char* buf, size_t bufsize);
  88 
  89 void*
  90 #ifdef DLL_ENTRY
  91   DLL_ENTRY
  92 #endif
  93 decode_instructions_virtual(void* start_va,
  94                             void* start_pv, void* end_pv,
  95                             event_callback_t  event_callback_arg,  void* event_stream_arg,
  96                             printf_callback_t printf_callback_arg, void* printf_stream_arg,
  97                             const char* options) {
  98   struct hsdis_app_data app_data;
  99   memset(&app_data, 0, sizeof(app_data));
 100   app_data.start = (uintptr_t) start_pv;
 101   app_data.end   = (uintptr_t) end_pv;
 102   app_data.start_va = (uintptr_t) start_va;
 103   app_data.end_va = app_data.start_va + app_data.end - app_data.start;
 104   app_data.event_callback  = event_callback_arg;
 105   app_data.event_stream    = event_stream_arg;
 106   app_data.printf_callback = printf_callback_arg;
 107   app_data.printf_stream   = printf_stream_arg;
 108 
 109   setup_app_data(&app_data, options);
 110   char buf[128];
 111 
 112   {
 113     /* now reload everything from app_data: */
 114     DECL_EVENT_CALLBACK(&app_data);
 115     DECL_PRINTF_CALLBACK(&app_data);
 116     uintptr_t start = app_data.start_va;
 117     uintptr_t end   = app_data.end_va;
 118     uintptr_t p     = start;
 119 
 120     (*event_callback)(event_stream, "insns", (void*)start);
 121 
 122     (*event_callback)(event_stream, "mach name='%s'",
 123                       (void*) app_data.arch_info->printable_name);
 124     if (app_data.dinfo.bytes_per_line != 0) {
 125       (*event_callback)(event_stream, "format bytes-per-line='%p'/",
 126                         (void*)(intptr_t) app_data.dinfo.bytes_per_line);
 127     }
 128 
 129     while (p < end && !app_data.losing) {
 130       (*event_callback)(event_stream, "insn", (void*) p);
 131 
 132       /* reset certain state, so we can read it with confidence */
 133       app_data.dinfo.insn_info_valid    = 0;
 134       app_data.dinfo.branch_delay_insns = 0;
 135       app_data.dinfo.data_size          = 0;
 136       app_data.dinfo.insn_type          = 0;
 137 
 138       int size = (*app_data.dfn)((bfd_vma) p, &app_data.dinfo);
 139 
 140       if (size > 0)  p += size;
 141       else           app_data.losing = true;
 142 
 143       const char* insn_close = format_insn_close("/insn", &app_data.dinfo,
 144                                                  buf, sizeof(buf));
 145       (*event_callback)(event_stream, insn_close, (void*) p);
 146 
 147       /* follow each complete insn by a nice newline */
 148       (*printf_callback)(printf_stream, "\n");
 149     }
 150 
 151     (*event_callback)(event_stream, "/insns", (void*) p);
 152     return (void*) p;
 153   }
 154 }
 155 
 156 void*
 157 #ifdef DLL_ENTRY
 158   DLL_ENTRY
 159 #endif
 160 decode_instructions(void* start_pv, void* end_pv,
 161                     event_callback_t  event_callback_arg,  void* event_stream_arg,
 162                     printf_callback_t printf_callback_arg, void* printf_stream_arg,
 163                     const char* options) {
 164   return decode_instructions_virtual(start_pv, start_pv, end_pv,
 165                                      event_callback_arg, event_stream_arg,
 166                                      printf_callback_arg, printf_stream_arg,
 167                                      options);
 168 }
 169 
 170 /* take the address of the function, for luck, and also test the typedef: */
 171 const decode_instructions_ftype decode_instructions_address = &decode_instructions;
 172 
 173 static const char* format_insn_close(const char* close,
 174                                      disassemble_info* dinfo,
 175                                      char* buf, size_t bufsize) {
 176   if (!dinfo->insn_info_valid)
 177     return close;
 178   enum dis_insn_type itype = dinfo->insn_type;
 179   int dsize = dinfo->data_size, delays = dinfo->branch_delay_insns;
 180   if ((itype == dis_nonbranch && (dsize | delays) == 0)
 181       || (strlen(close) + 3*20 > bufsize))
 182     return close;
 183 
 184   const char* type = "unknown";
 185   switch (itype) {
 186   case dis_nonbranch:   type = NULL;         break;
 187   case dis_branch:      type = "branch";     break;
 188   case dis_condbranch:  type = "condbranch"; break;
 189   case dis_jsr:         type = "jsr";        break;
 190   case dis_condjsr:     type = "condjsr";    break;
 191   case dis_dref:        type = "dref";       break;
 192   case dis_dref2:       type = "dref2";      break;
 193   }
 194 
 195   strcpy(buf, close);
 196   char* p = buf;
 197   if (type)    sprintf(p += strlen(p), " type='%s'", type);
 198   if (dsize)   sprintf(p += strlen(p), " dsize='%d'", dsize);
 199   if (delays)  sprintf(p += strlen(p), " delay='%d'", delays);
 200   return buf;
 201 }
 202 
 203 /* handler functions */
 204 
 205 static int
 206 hsdis_read_memory_func(bfd_vma memaddr,
 207                        bfd_byte* myaddr,
 208                        unsigned int length,
 209                        struct disassemble_info* dinfo) {
 210   DECL_APP_DATA(dinfo);
 211   // convert the virtual address membar into an address within memory buffer
 212   uintptr_t memaddr_p = ((uintptr_t) memaddr) - app_data->start_va + app_data->start;
 213   if (memaddr_p + length > app_data->end) {
 214     /* read is out of bounds */
 215     return EIO;
 216   } else {
 217     memcpy(myaddr, (bfd_byte*) memaddr_p, length);
 218     return 0;
 219   }
 220 }
 221 
 222 static void
 223 hsdis_print_address_func(bfd_vma vma, struct disassemble_info* dinfo) {
 224   /* the actual value to print: */
 225   void* addr_value = (void*) (uintptr_t) vma;
 226   DECL_APP_DATA(dinfo);
 227   DECL_EVENT_CALLBACK(app_data);
 228 
 229   /* issue the event: */
 230   void* result =
 231     (*event_callback)(event_stream, "addr/", addr_value);
 232   if (result == NULL) {
 233     /* event declined */
 234     generic_print_address(vma, dinfo);
 235   }
 236 }
 237 
 238 
 239 /* configuration */
 240 
 241 static void set_optional_callbacks(struct hsdis_app_data* app_data);
 242 static void parse_caller_options(struct hsdis_app_data* app_data,
 243                                  const char* caller_options);
 244 static const char* native_arch_name();
 245 static enum bfd_endian native_endian();
 246 static const bfd_arch_info_type* find_arch_info(const char* arch_nane);
 247 static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
 248                            /* to avoid malloc: */
 249                            bfd* empty_bfd, bfd_target* empty_xvec);
 250 static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
 251                                            void *stream,
 252                                            fprintf_ftype fprintf_func,
 253                                            bfd* bfd,
 254                                            char* disassembler_options);
 255 static void parse_fake_insn(disassembler_ftype dfn,
 256                             struct disassemble_info* dinfo);
 257 
 258 static void setup_app_data(struct hsdis_app_data* app_data,
 259                            const char* caller_options) {
 260   /* Make reasonable defaults for null callbacks.
 261      A non-null stream for a null callback is assumed to be a FILE* for output.
 262      Events are rendered as XML.
 263   */
 264   set_optional_callbacks(app_data);
 265 
 266   /* Look into caller_options for anything interesting. */
 267   if (caller_options != NULL)
 268     parse_caller_options(app_data, caller_options);
 269 
 270   /* Discover which architecture we are going to disassemble. */
 271   app_data->arch_name = &app_data->mach_option[0];
 272   if (app_data->arch_name[0] == '\0')
 273     app_data->arch_name = native_arch_name();
 274   app_data->arch_info = find_arch_info(app_data->arch_name);
 275 
 276   /* Make a fake bfd to hold the arch. and byteorder info. */
 277   struct {
 278     bfd_target empty_xvec;
 279     bfd        empty_bfd;
 280   } buf;
 281   bfd* native_bfd = get_native_bfd(app_data->arch_info,
 282                                    /* to avoid malloc: */
 283                                    &buf.empty_bfd, &buf.empty_xvec);
 284   init_disassemble_info_from_bfd(&app_data->dinfo,
 285                                  app_data->printf_stream,
 286                                  app_data->printf_callback,
 287                                  native_bfd,
 288                                  app_data->insn_options);
 289 
 290   /* Finish linking together the various callback blocks. */
 291   app_data->dinfo.application_data = (void*) app_data;
 292   app_data->dfn = disassembler(native_bfd);
 293   app_data->dinfo.print_address_func = hsdis_print_address_func;
 294   app_data->dinfo.read_memory_func = hsdis_read_memory_func;
 295 
 296   if (app_data->dfn == NULL) {
 297     const char* bad = app_data->arch_name;
 298     static bool complained;
 299     if (bad == &app_data->mach_option[0])
 300       print_help(app_data, "bad mach=%s", bad);
 301     else if (!complained)
 302       print_help(app_data, "bad native mach=%s; please port hsdis to this platform", bad);
 303     complained = true;
 304     /* must bail out */
 305     app_data->losing = true;
 306     return;
 307   }
 308 
 309   parse_fake_insn(app_data->dfn, &app_data->dinfo);
 310 }
 311 
 312 
 313 /* ignore all events, return a null */
 314 static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) {
 315   return NULL;
 316 }
 317 
 318 /* print all events as XML markup */
 319 static void* xml_event_callback(void* stream, const char* event, void* arg) {
 320   FILE* fp = (FILE*) stream;
 321 #define NS_PFX "dis:"
 322   if (event[0] != '/') {
 323     /* issue the tag, with or without a formatted argument */
 324     fprintf(fp, "<"NS_PFX);
 325     fprintf(fp, event, arg);
 326     fprintf(fp, ">");
 327   } else {
 328     ++event;                    /* skip slash */
 329     const char* argp = strchr(event, ' ');
 330     if (argp == NULL) {
 331       /* no arguments; just issue the closing tag */
 332       fprintf(fp, "</"NS_PFX"%s>", event);
 333     } else {
 334       /* split out the closing attributes as <dis:foo_done attr='val'/> */
 335       int event_prefix = (argp - event);
 336       fprintf(fp, "<"NS_PFX"%.*s_done", event_prefix, event);
 337       fprintf(fp, argp, arg);
 338       fprintf(fp, "/></"NS_PFX"%.*s>", event_prefix, event);
 339     }
 340   }
 341   return NULL;
 342 }
 343 
 344 static void set_optional_callbacks(struct hsdis_app_data* app_data) {
 345   if (app_data->printf_callback == NULL) {
 346     int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf;
 347     FILE* fprintf_stream = stdout;
 348     app_data->printf_callback = (printf_callback_t) fprintf_callback;
 349     if (app_data->printf_stream == NULL)
 350       app_data->printf_stream   = (void*)           fprintf_stream;
 351   }
 352   if (app_data->event_callback == NULL) {
 353     if (app_data->event_stream == NULL)
 354       app_data->event_callback = &null_event_callback;
 355     else
 356       app_data->event_callback = &xml_event_callback;
 357   }
 358 
 359 }
 360 
 361 static void parse_caller_options(struct hsdis_app_data* app_data, const char* caller_options) {
 362   char* iop_base = app_data->insn_options;
 363   char* iop_limit = iop_base + sizeof(app_data->insn_options) - 1;
 364   char* iop = iop_base;
 365   const char* p;
 366   for (p = caller_options; p != NULL; ) {
 367     const char* q = strchr(p, ',');
 368     size_t plen = (q == NULL) ? strlen(p) : ((q++) - p);
 369     if (plen == 4 && strncmp(p, "help", plen) == 0) {
 370       print_help(app_data, NULL, NULL);
 371     } else if (plen >= 5 && strncmp(p, "mach=", 5) == 0) {
 372       char*  mach_option = app_data->mach_option;
 373       size_t mach_size   = sizeof(app_data->mach_option);
 374       mach_size -= 1;           /*leave room for the null*/
 375       if (plen > mach_size)  plen = mach_size;
 376       strncpy(mach_option, p, plen);
 377       mach_option[plen] = '\0';
 378     } else if (plen > 6 && strncmp(p, "hsdis-", 6)) {
 379       // do not pass these to the next level
 380     } else {
 381       /* just copy it; {i386,sparc}-dis.c might like to see it  */
 382       if (iop > iop_base && iop < iop_limit)  (*iop++) = ',';
 383       if (iop + plen > iop_limit)
 384         plen = iop_limit - iop;
 385       strncpy(iop, p, plen);
 386       iop += plen;
 387     }
 388     p = q;
 389   }
 390 }
 391 
 392 static void print_help(struct hsdis_app_data* app_data,
 393                        const char* msg, const char* arg) {
 394   DECL_PRINTF_CALLBACK(app_data);
 395   if (msg != NULL) {
 396     (*printf_callback)(printf_stream, "hsdis: ");
 397     (*printf_callback)(printf_stream, msg, arg);
 398     (*printf_callback)(printf_stream, "\n");
 399   }
 400   (*printf_callback)(printf_stream, "hsdis output options:\n");
 401   if (printf_callback == (printf_callback_t) &fprintf)
 402     disassembler_usage((FILE*) printf_stream);
 403   else
 404     disassembler_usage(stderr); /* better than nothing */
 405   (*printf_callback)(printf_stream, "  mach=<arch>   select disassembly mode\n");
 406 #if defined(LIBARCH_i386) || defined(LIBARCH_amd64)
 407   (*printf_callback)(printf_stream, "  mach=i386     select 32-bit mode\n");
 408   (*printf_callback)(printf_stream, "  mach=x86-64   select 64-bit mode\n");
 409   (*printf_callback)(printf_stream, "  suffix        always print instruction suffix\n");
 410 #endif
 411   (*printf_callback)(printf_stream, "  help          print this message\n");
 412 }
 413 
 414 
 415 /* low-level bfd and arch stuff that binutils doesn't do for us */
 416 
 417 static const bfd_arch_info_type* find_arch_info(const char* arch_name) {
 418   const bfd_arch_info_type* arch_info = bfd_scan_arch(arch_name);
 419   if (arch_info == NULL) {
 420     extern const bfd_arch_info_type bfd_default_arch_struct;
 421     arch_info = &bfd_default_arch_struct;
 422   }
 423   return arch_info;
 424 }
 425 
 426 static const char* native_arch_name() {
 427   const char* res = NULL;
 428 #ifdef LIBARCH_i386
 429     res = "i386";
 430 #endif
 431 #ifdef LIBARCH_amd64
 432     res = "i386:x86-64";
 433 #endif
 434 #ifdef LIBARCH_sparc
 435     res = "sparc:v8plusb";
 436 #endif
 437 #ifdef LIBARCH_sparcv9
 438     res = "sparc:v9b";
 439 #endif
 440   if (res == NULL)
 441     res = "architecture not set in Makefile!";
 442   return res;
 443 }
 444 
 445 static enum bfd_endian native_endian() {
 446   int32_t endian_test = 'x';
 447   if (*(const char*) &endian_test == 'x')
 448     return BFD_ENDIAN_LITTLE;
 449   else
 450     return BFD_ENDIAN_BIG;
 451 }
 452 
 453 static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
 454                            bfd* empty_bfd, bfd_target* empty_xvec) {
 455   memset(empty_bfd,  0, sizeof(*empty_bfd));
 456   memset(empty_xvec, 0, sizeof(*empty_xvec));
 457   empty_xvec->flavour = bfd_target_unknown_flavour;
 458   empty_xvec->byteorder = native_endian();
 459   empty_bfd->xvec = empty_xvec;
 460   empty_bfd->arch_info = arch_info;
 461   return empty_bfd;
 462 }
 463 
 464 static int read_zero_data_only(bfd_vma ignore_p,
 465                                bfd_byte* myaddr, unsigned int length,
 466                                struct disassemble_info *ignore_info) {
 467   memset(myaddr, 0, length);
 468   return 0;
 469 }
 470 static int print_to_dev_null(void* ignore_stream, const char* ignore_format, ...) {
 471   return 0;
 472 }
 473 
 474 /* Prime the pump by running the selected disassembler on a null input.
 475    This forces the machine-specific disassembler to divulge invariant
 476    information like bytes_per_line.
 477  */
 478 static void parse_fake_insn(disassembler_ftype dfn,
 479                             struct disassemble_info* dinfo) {
 480   typedef int (*read_memory_ftype)
 481     (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
 482      struct disassemble_info *info);
 483   read_memory_ftype read_memory_func = dinfo->read_memory_func;
 484   fprintf_ftype     fprintf_func     = dinfo->fprintf_func;
 485 
 486   dinfo->read_memory_func = &read_zero_data_only;
 487   dinfo->fprintf_func     = &print_to_dev_null;
 488   (*dfn)(0, dinfo);
 489 
 490   // put it back:
 491   dinfo->read_memory_func = read_memory_func;
 492   dinfo->fprintf_func     = fprintf_func;
 493 }
 494 
 495 static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
 496                                            void *stream,
 497                                            fprintf_ftype fprintf_func,
 498                                            bfd* abfd,
 499                                            char* disassembler_options) {
 500   init_disassemble_info(dinfo, stream, fprintf_func);
 501 
 502   dinfo->flavour = bfd_get_flavour(abfd);
 503   dinfo->arch = bfd_get_arch(abfd);
 504   dinfo->mach = bfd_get_mach(abfd);
 505   dinfo->disassembler_options = disassembler_options;
 506   dinfo->octets_per_byte = bfd_octets_per_byte (abfd);
 507   dinfo->skip_zeroes = sizeof(void*) * 2;
 508   dinfo->skip_zeroes_at_end = sizeof(void*)-1;
 509   dinfo->disassembler_needs_relocs = FALSE;
 510 
 511   if (bfd_big_endian(abfd))
 512     dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG;
 513   else if (bfd_little_endian(abfd))
 514     dinfo->display_endian = dinfo->endian = BFD_ENDIAN_LITTLE;
 515   else
 516     dinfo->endian = native_endian();
 517 
 518   disassemble_init_for_target(dinfo);
 519 }