Source file: /~heha/hs/gputils64-210929.zip/gputils/gpvo.cpp

/* GNU PIC view object
   Copyright 2001-2005	Craig Franklin
   Copyright 2016	Molnár Károly
*/
#include "gpvo.h"

gpvo_state state;

static const char longopts[]=
  "bbinary\0"		// first character is short option, following long option (if any)
  "cmnemonics\0"
  "ffile\0"
  "hhelp\0"
  "nno-names\0"
  "ssection\0"
  "\1strict-options\0"	// Non-printable first character = no short option but return value
  "tsymbol\0"
  "vversion\0"
  "xfexport\1FILE\0"	// \1 = required argument, name id for usage formatting
  "yextended\0";	// Entire string is double-zero terminated

static const char longdesc[]=
  "Print binary data.\0"
  "Decode special mnemonics.\0"
  "File header.\0"
  "Show this usage message.\0"
  "Suppress filenames.\0"
  "Section data.\0"
  "If this is set, then an option may not be parameter"
	" of an another option. For example: -x --symbol\0"
  "Symbol table.\0"
  "Show version.\0"
  "Export symbols to include file.\0"
  "Enable 18xx extended mode.\0";

/*------------------------------------------------------------------------------------------------*/

__attribute__((noreturn)) static void _show_usage(const char*argv0) {
  gp_usage(argv0,longopts,longdesc);
  exit(0);
}

/*------------------------------------------------------------------------------------------------*/

static void _print_header(const gp_object_t*Object) {
  static struct magic_s {
    uint16_t    magic_num;
    const char *magic_name;
  } magic[] = {
    { 0x1234, "MICROCHIP_MAGIC_v1" },
    { 0x1240, "MICROCHIP_MAGIC_v2" }
  };

  time_t      time;
  const char *processor_name;
  int         i;
#ifdef HAVE_LOCALE_H
  char        time_str[256];
#else
  char       *time_str;
#endif

  time = (time_t)Object->time;

#ifdef HAVE_LOCALE_H
  setlocale(LC_ALL, "");
  strftime(time_str, sizeof(time_str), "%c", localtime(&time));
  setlocale(LC_ALL, "C");
#else
  time_str = ctime(&time);
  /* strip the newline from time */
  time_str[strlen(time_str) - 1] = '\0';
#endif

  processor_name = gp_processor_name(Object->processor, 2);

  printf("COFF File and Optional Headers\n");

  for (i = 0; i < (int)ARRAY_SIZE(magic); ++i) {
    if (magic[i].magic_num == Object->version) {
      break;
    }
  }

  printf("COFF version         %#x: %s\n", Object->version,
         (i < (int)ARRAY_SIZE(magic)) ? magic[i].magic_name : "unknown");
  printf("Processor Type       %s\n",  processor_name);
  printf("Time Stamp           %s\n",  time_str);
  printf("Number of Sections   %" SIZE_FMTu "\n", Object->section_list.num_nodes);
  printf("Number of Symbols    %u\n",  Object->num_symbols);
  printf("Characteristics      %#x\n", Object->flags);

  if (Object->flags & F_RELFLG) {
    printf("  Relocation info has been stripped.\n");
  }

  if (Object->flags & F_EXEC) {
    printf("  File is executable.\n");
  }

  if (Object->flags & F_LINENO) {
    printf("  Line numbers have been stripped.\n");
  }

  if (Object->flags & F_ABSOLUTE) {
    printf("  The MPASM assembler object file is from absolute assembly code.\n");
  }

  if (Object->flags & L_SYMS) {
    printf("  Local symbols have been stripped.\n");
  }

  if (Object->flags & F_EXTENDED18) {
    printf("  The COFF file produced utilizing the Extended mode.\n");
  }

  if (Object->flags & F_GENERIC) {
    printf("  Processor independent file for a core.\n");
  }

  printf("\n");
}

/*------------------------------------------------------------------------------------------------*/

static const char* _format_reloc_type(uint16_t Type, char *Buffer, size_t Sizeof_buffer) {
  snprintf(Buffer, Sizeof_buffer, "0x%04x %-20s", Type, gp_coffgen_reloc_type_to_str(Type));
  return Buffer;
}

/*------------------------------------------------------------------------------------------------*/

static void _print_relocation_list(proc_class_t Class, const gp_reloc_t *Relocation, const char *Column_gap) {
  char buffer[32];
  int  addr_digits;

  addr_digits = Class->addr_digits;

  printf("Relocations Table\n"
         "Address     Offset      Offset       Type                        Symbol\n"
         "            (hex)       (dec)\n");

  while (Relocation) {
    printf("0x%0*x%s    0x%08x  %11d  %-25s %-s\n",
           addr_digits, gp_processor_insn_from_byte_c(Class, (int)Relocation->address), Column_gap,
           Relocation->offset, Relocation->offset,
           _format_reloc_type(Relocation->type, buffer, sizeof(buffer)),
           Relocation->symbol->name);

    Relocation = Relocation->next;
  }

  printf("\n");
}

/*------------------------------------------------------------------------------------------------*/

static void _print_linenum_list(proc_class_t Class, const gp_linenum_t *Linenumber, const char *Column_gap) {
  const char *filename;
  int         addr_digits;

  addr_digits = Class->addr_digits;

  printf("Line Number Table\n"
         "Line      Address     Symbol\n");

  while (Linenumber) {
    if (state.suppress_names) {
      filename = Linenumber->symbol->name;
    }
    else {
      filename = Linenumber->symbol->aux_list.first->_aux_symbol._aux_file.filename;
    }

    printf("%-8i  0x%0*x%s    %s\n",
           Linenumber->line_number,
           addr_digits, gp_processor_insn_from_byte_c(Class, (int)Linenumber->address), Column_gap,
           filename);

    Linenumber = Linenumber->next;
  }

  printf("\n");
}

/*------------------------------------------------------------------------------------------------*/

static void _print_data(pic_processor_t Processor, const gp_section_t *Section) {
  proc_class_t pclass;
  char         buffer[BUFSIZ];
  unsigned address;
  int          num_words;
  int          addr_digits;
  unsigned bsr_boundary;
  uint16_t     word;
  uint8_t      byte;

  pclass        = Processor->pclass;
  address      = Section->address;
  bsr_boundary = gp_processor_bsr_boundary(Processor);
  addr_digits  = pclass->addr_digits;

  buffer[0] = '\0';

  printf("Data\n");
  while (true) {
    if ((Section->flags & STYP_TEXT) && (pclass->find_insn)) {
      if (pclass->i_memory_get(Section->data, address, &word, NULL, NULL) != W_USED_ALL) {
        break;
      }

      num_words = (int)gp_disassemble(Section->data, address, pclass, bsr_boundary, 0,
                                      GPDIS_SHOW_ALL_BRANCH, buffer, sizeof(buffer), 0);
      printf("%0*x:  %04x  %s\n",
             addr_digits, gp_processor_insn_from_byte_c(pclass, (int)address), word, buffer);

      if (num_words != 1) {
        if (pclass->i_memory_get(Section->data, address + WORD_SIZE, &word, NULL, NULL) != W_USED_ALL) {
          break;
        }

        printf("%0*x:  %04x\n",
               addr_digits, gp_processor_insn_from_byte_c(pclass, (int)(address + WORD_SIZE)), word);
      }

      address += (size_t)num_words * WORD_SIZE;
    }
    else if ((Section->flags & STYP_DATA_ROM) || (pclass == PROC_CLASS_EEPROM16)) {
      if (pclass->i_memory_get(Section->data, address, &word, NULL, NULL) != 0) {
        printf("%0*x:  %04x\n", addr_digits, gp_processor_insn_from_byte_c(pclass, (int)address), word);
        address += WORD_SIZE;
      }
      else {
        if (gp_mem_b_get(Section->data, address, &byte, NULL, NULL)) {
          printf("%0*x:  %02x\n", addr_digits, gp_processor_insn_from_byte_c(pclass, (int)address), byte);
        }

        break;
      }
    }
    else {
      /* STYP_DATA or STYP_ACTREC, or EEPROM8 */
      if (!gp_mem_b_get(Section->data, address, &byte, NULL, NULL)) {
        break;
      }

      printf("%0*x:  %02x\n", addr_digits, address, byte);
      ++address;
    }
  }

  printf("\n");
}

/*------------------------------------------------------------------------------------------------*/

static void _print_section_header(proc_class_t Class, const gp_section_t *Section) {
  unsigned org_to_byte_shift;

  org_to_byte_shift = (Section->flags & STYP_ROM_AREA) ? Class->org_to_byte_shift : 0;

  printf("Section Header\n");
  printf("Name                    %s\n",  Section->name);
  printf("Physical address        %#x\n", gp_insn_from_byte(org_to_byte_shift, (int)Section->address));
  printf("Virtual address         %#x\n", gp_insn_from_byte(org_to_byte_shift, (int)Section->virtual_address));
  printf("Size of Section         %u\n",  Section->size);
  printf("Number of Relocations   %" SIZE_FMTu "\n", Section->relocation_list.num_nodes);
  printf("Number of Line Numbers  %" SIZE_FMTu "\n", Section->line_number_list.num_nodes);
  printf("Flags                   %#x\n", Section->flags);

  if (Section->flags & STYP_TEXT) {
    printf("  Executable code.\n");
  }

  if (Section->flags & STYP_DATA) {
    printf("  Initialized data.\n");
  }

  if (Section->flags & STYP_BSS) {
    printf("  Uninitialized data.\n");
  }

  if (Section->flags & STYP_DATA_ROM) {
    printf("  Initialized data for ROM.\n");
  }

  if (Section->flags & STYP_ABS) {
    printf("  Absolute.\n");
  }

  if (Section->flags & STYP_SHARED) {
    printf("  Shared across banks.\n");
  }

  if (Section->flags & STYP_OVERLAY) {
    printf("  Overlaid with other sections from different objects modules.\n");
  }

  if (Section->flags & STYP_ACCESS) {
    printf("  Available using access bit.\n");
  }

  if (Section->flags & STYP_ACTREC) {
    printf("  Contains the activation record for a function.\n");
  }

  printf("\n");
}

/*------------------------------------------------------------------------------------------------*/

static void _print_section_list(const gp_object_t *Object) {
  proc_class_t        pclass;
  const gp_section_t *section;
  char                column_gap[16];
  unsigned        i;

  pclass = Object->pclass;
  i     = (unsigned)pclass->addr_digits;

  if (i > 6) {
    i = 6;
  }

  i = 6 - i;

  if (i >= (sizeof(column_gap) - 1)) {
    i = (sizeof(column_gap) - 1);
  }

  if (i > 0) {
    memset(column_gap, ' ', i);
  }

  column_gap[i] = '\0';

  section = Object->section_list.first;
  while (section) {
    _print_section_header(pclass, section);

    if ((section->size > 0) && (section->data_ptr > 0)) {
      _print_data(Object->processor, section);
    }

    if (section->relocation_list.num_nodes > 0) {
      _print_relocation_list(pclass, section->relocation_list.first, column_gap);
    }

    if (section->line_number_list.num_nodes > 0) {
      _print_linenum_list(pclass, section->line_number_list.first, column_gap);
    }

    section = section->next;
  }
}

/*------------------------------------------------------------------------------------------------*/

static void _coff_type(unsigned Type, char *Buffer, size_t Sizeof_buffer) {
  const char *str;

  switch (Type) {
    case T_NULL:   str = "NULL";                break; /* null */
    case T_VOID:   str = "void";                break; /* void */
    case T_CHAR:   str = "char";                break; /* character */
    case T_SHORT:  str = "short";               break; /* short integer */
    case T_INT:    str = "int";                 break; /* integer */
    case T_LONG:   str = "long int";            break; /* long integer */
    case T_FLOAT:  str = "float";               break; /* floating point */
    case T_DOUBLE: str = "double";              break; /* double length floating point */
    case T_STRUCT: str = "struct";              break; /* structure */
    case T_UNION:  str = "union";               break; /* union */
    case T_ENUM:   str = "enum";                break; /* enumeration */
    case T_MOE:    str = "enum member";         break; /* member of enumeration */
    case T_UCHAR:  str = "unsigned char";       break; /* unsigned character */
    case T_USHORT: str = "unsigned short";      break; /* unsigned short */
    case T_UINT:   str = "unsigned int";        break; /* unsigned integer */
    case T_ULONG:  str = "unsigned long";       break; /* unsigned long */
    case T_LNGDBL: str = "long double";         break; /* long double floating point */
    case T_SLONG:  str = "short long";          break; /* short long */
    case T_USLONG: str = "unsigned short long"; break; /* unsigned short long */
    default:       str = NULL;                  break;
  }

  if (str) {
    snprintf(Buffer, Sizeof_buffer, "%s", str);
  }
  else {
    snprintf(Buffer, Sizeof_buffer, "unknown(%u)", Type);
  }
}

/*------------------------------------------------------------------------------------------------*/

static const char* _format_sym_type(unsigned Type, char *Buffer, size_t Sizeof_buffer) {
  const char *str = gp_coffgen_symbol_type_to_str((uint8_t)Type);
  if (str) return str;
  snprintf(Buffer, Sizeof_buffer, "%u", Type);
  return Buffer;
}

/*------------------------------------------------------------------------------------------------*/

static const char* _format_sym_derived_type(unsigned Type, char *Buffer, size_t Sizeof_buffer) {
  const char *str = gp_coffgen_symbol_derived_type_to_str(Type);
  if (str) return str;
  snprintf(Buffer, Sizeof_buffer, "%u", Type);
  return Buffer;
}

/*------------------------------------------------------------------------------------------------*/

static const char* _format_sym_class(unsigned Class, char *Buffer, size_t Sizeof_buffer) {
  const char *str = gp_coffgen_symbol_class_to_str((uint8_t)Class);
  if (str) return str;
  snprintf(Buffer, Sizeof_buffer, "%u", Class);
  return Buffer;
}

/*------------------------------------------------------------------------------------------------*/

#define AUX_INDENT              "       "

static void _print_symbol_table(const gp_object_t *Object) {
  static char buf[64];	// igitt!!

  printf("Symbol Table\n");
  printf("Idx  Name                     Section          Value      Type     DT           Class     NumAux\n");

  unsigned idx = 1;
  FORC(gp_symbol_list_t,symbol,Object->symbol_list) {
    const char*section;
    if (symbol->section_number == N_DEBUG) {
      section = "DEBUG";
    }else if (symbol->section_number == N_ABS) {
      section = "ABSOLUTE";
    }else if (symbol->section_number == N_UNDEF) {
      section = "UNDEFINED";
    }else{
      if (symbol->section) {
        section = symbol->section->name;
      }else{
        snprintf(buf, sizeof(buf), "Bad num.: %u", symbol->section_number);
        section = buf;
      }
    }

    char          buffer_type[8];
    char          buffer_derived_type[8];
    char          buffer_class[8];
    printf("%04u %-24s %-16s 0x%08lx %-8s %-12s %-9s %" SIZE_FMTu "\n",
           idx,
           symbol->name,
           section,
           symbol->value,
           _format_sym_type(symbol->type, buffer_type, sizeof(buffer_type)),
           _format_sym_derived_type(symbol->derived_type, buffer_derived_type, sizeof(buffer_derived_type)),
           _format_sym_class(symbol->pclass, buffer_class, sizeof(buffer_class)),
           symbol->aux_list.num_nodes);

    gp_aux_t*aux = symbol->aux_list.first;
    while (aux) {
      switch (aux->type) {
        case AUX_DIRECT:
          printf(AUX_INDENT "command = '%c'\n", aux->_aux_symbol._aux_direct.command);
          printf(AUX_INDENT "string  = \"%s\"\n", aux->_aux_symbol._aux_direct.string);
          break;

        case AUX_FILE: {
          if (!state.suppress_names) {
            printf(AUX_INDENT "file          = %s\n", aux->_aux_symbol._aux_file.filename);
          }
          printf(AUX_INDENT "line included = %u\n", aux->_aux_symbol._aux_file.line_number);
          printf(AUX_INDENT "flags         = 0x%08x\n", aux->_aux_symbol._aux_file.flags);
          break;
        }

        case AUX_IDENT:
          printf(AUX_INDENT "string = \"%s\"\n", aux->_aux_symbol._aux_ident.string);
          break;

        case AUX_SECTION:
          printf(AUX_INDENT "length                 = %u\n", aux->_aux_symbol._aux_scn.length);
          printf(AUX_INDENT "number of relocations  = %u\n", aux->_aux_symbol._aux_scn.nreloc);
          printf(AUX_INDENT "number of line numbers = %u\n", aux->_aux_symbol._aux_scn.nlineno);
          break;

        case AUX_FCN_CALLS: {
          gp_symbol_t*callee = aux->_aux_symbol._aux_fcn_calls.callee;
          printf(AUX_INDENT "callee       = %s\n", (callee) ? callee->name : "higher order");
          printf(AUX_INDENT "is_interrupt = %u\n", aux->_aux_symbol._aux_fcn_calls.is_interrupt);
          break;
        }

        default: {
          printf("%u  ", aux->type);
          size_t i;
          for (i = 0; i < Object->symbol_size; i++) {
            printf("%02x", aux->_aux_symbol.data[i] & 0xFF);

            if (i & 1) {
              putchar(' ');
            }
          }
          for (i = 0; i < Object->symbol_size; i++) {
            char c = aux->_aux_symbol.data[i] & 0xFF;
            putchar(isprint(c) ? c : '.');
          }
          putchar('\n');
        }
      } /* switch (aux->type) */

      aux = aux->next;
      ++idx;
    }

    ++idx;
  }

  putchar('\n');
}

/*------------------------------------------------------------------------------------------------*/

static void _export_symbol_table(const gp_object_t *Object) {
  FORC(gp_symbol_list_t,symbol,Object->symbol_list)
   if (state.fexport.enabled && symbol->pclass == C_EXT && symbol->section_number > N_UNDEF) {
    char buffer[BUFSIZ];
    _coff_type(symbol->type, buffer, sizeof(buffer));
    fprintf(state.fexport.f, "  extern %s ; %s\n", symbol->name, buffer);
  }
}

/*------------------------------------------------------------------------------------------------*/

#define BIN_DATA_LINE_SIZE    16

static void _print_binary(const uint8_t *Data, long File_size) {
  long         i;
  long         j;
  unsigned memory;
  int          c;

  printf("\nObject file size = %li bytes\n", File_size);

  printf("\nBinary object file contents:");
  for (i = 0; i < File_size; i += BIN_DATA_LINE_SIZE) {
    printf("\n%06lx", i);

    for (j = 0; j < BIN_DATA_LINE_SIZE; j += 2) {
      memory = (Data[i + j] << 8) | Data[i + j + 1];

      if ((i + j) >= File_size) {
        printf("     ");
      }
      else {
        printf(" %04x", memory);
      }
    }

    putchar(' ');

    for (j = 0; j < BIN_DATA_LINE_SIZE; j += 2) {
      if ((i + j) < File_size) {
        c = Data[i + j];
        putchar((isprint(c)) ? c : '.');

        c = Data[i + j + 1];
        putchar((isprint(c)) ? c : '.');
      }
    }
  }

  printf("\n\n");
}

static bool strict_options;
static bool usage;

static void _stdcall onOption(void*, char c, const char*arg) {
  switch (c) {
    case 1: gp_checkarg(state.fexport.filename,longopts);
	      strict_options = true;		break;
    case '?':
    case 'h': usage = true; break;
    case 'b': state.dump_flags |= PRINT_BINARY;	break;
    case 'c': gp_decode_mnemonics = true;	break;
    case 'f': state.dump_flags |= PRINT_HEADER;	break;
    case 'n': state.suppress_names = true;	break;
    case 's': state.dump_flags |= PRINT_SECTIONS; break;
    case 't': state.dump_flags |= PRINT_SYMTBL;	break;
    case 'y': gp_decode_extended = true;	break;
    case 'x': state.fexport.enabled = true;
	      if (strict_options) gp_checkarg(arg,longopts);
	      state.fexport.filename = arg;	break;
    case 'v': fprintf(stderr, "%s\n", GPVO_VERSION_STRING);
              exit(0);
    case 0:   state.filename = arg;		break;
  }
}

/*------------------------------------------------------------------------------------------------*/

int main(int argc, char *argv[]) {
  gp_init();
  /* Scan through the options — but only once! */
  gp_getopt(argv,longopts,onOption,0);

  if (usage || !state.filename) _show_usage(*argv);

  if (!state.dump_flags) {
    /* no command line flags were set so print everything */
    state.dump_flags = PRINT_HEADER | PRINT_SECTIONS | PRINT_SYMTBL;
  }

  if ((gp_identify_coff_file(state.filename) != GP_COFF_OBJECT_V2) &&
      (gp_identify_coff_file(state.filename) != GP_COFF_OBJECT)) {
    gp_error("The \"%s\" is not a valid object file.", state.filename);
    exit(1);
  }

  state.object = gp_read_coff(state.filename);
  state.file   = gp_read_file(state.filename);

  if (state.fexport.enabled) {
    state.fexport.f = fopen(state.fexport.filename, "w");

    if (!state.fexport.f) {
      perror(state.fexport.filename);
      exit(1);
    }

    char buffer[BUFSIZ];
    gp_date_string(buffer, sizeof(buffer));

    fprintf(state.fexport.f, "; %s\n", state.fexport.filename);
    fprintf(state.fexport.f, "; generated by %s on %s\n", GPVO_VERSION_STRING, buffer);
    fprintf(state.fexport.f, "; from %s\n\n", state.filename);

    _export_symbol_table(state.object);

    fclose(state.fexport.f);

    /* suppress normal output */
    state.dump_flags = 0;
  }

  if (state.dump_flags & PRINT_HEADER) {
    _print_header(state.object);
  }

  if (state.dump_flags & PRINT_SECTIONS) {
    _print_section_list(state.object);
  }

  if (state.dump_flags & PRINT_SYMTBL) {
    _print_symbol_table(state.object);
  }

  if (state.dump_flags & PRINT_BINARY) {
    _print_binary(state.file->file, state.file->size);
  }

  return 0;
}
Detected encoding: UTF-80