|  | /* Sysroff object format dumper. | 
|  | Copyright (C) 1994-2022 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GNU Binutils. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | 
|  | 02110-1301, USA.  */ | 
|  |  | 
|  |  | 
|  | /* Written by Steve Chamberlain <sac@cygnus.com>. | 
|  |  | 
|  | This program reads a SYSROFF object file and prints it in an | 
|  | almost human readable form to stdout.  */ | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "bfd.h" | 
|  | #include "safe-ctype.h" | 
|  | #include "libiberty.h" | 
|  | #include "getopt.h" | 
|  | #include "bucomm.h" | 
|  | #include "sysroff.h" | 
|  |  | 
|  | static int dump = 1; | 
|  | static int segmented_p; | 
|  | static int code; | 
|  | static int addrsize = 4; | 
|  | static FILE *file; | 
|  |  | 
|  | static void derived_type (void); | 
|  |  | 
|  | static char * | 
|  | getCHARS (unsigned char *ptr, int *idx, int size, int max) | 
|  | { | 
|  | int oc = *idx / 8; | 
|  | char *r; | 
|  | int b = size; | 
|  |  | 
|  | if (b >= max) | 
|  | return _("*undefined*"); | 
|  |  | 
|  | if (b == 0) | 
|  | { | 
|  | /* PR 17512: file: 13caced2.  */ | 
|  | if (oc >= max) | 
|  | return _("*corrupt*"); | 
|  | /* Got to work out the length of the string from self.  */ | 
|  | b = ptr[oc++]; | 
|  | (*idx) += 8; | 
|  | } | 
|  |  | 
|  | if (oc + b > size) | 
|  | { | 
|  | /* PR 28564  */ | 
|  | return _("*corrupt*"); | 
|  | } | 
|  |  | 
|  | *idx += b * 8; | 
|  | r = xcalloc (b + 1, 1); | 
|  | memcpy (r, ptr + oc, b); | 
|  | r[b] = 0; | 
|  |  | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static void | 
|  | dh (unsigned char *ptr, int size) | 
|  | { | 
|  | int i; | 
|  | int j; | 
|  | int span = 16; | 
|  |  | 
|  | printf ("\n************************************************************\n"); | 
|  |  | 
|  | for (i = 0; i < size; i += span) | 
|  | { | 
|  | for (j = 0; j < span; j++) | 
|  | { | 
|  | if (j + i < size) | 
|  | printf ("%02x ", ptr[i + j]); | 
|  | else | 
|  | printf ("   "); | 
|  | } | 
|  |  | 
|  | for (j = 0; j < span && j + i < size; j++) | 
|  | { | 
|  | int c = ptr[i + j]; | 
|  |  | 
|  | if (c < 32 || c > 127) | 
|  | c = '.'; | 
|  | printf ("%c", c); | 
|  | } | 
|  |  | 
|  | printf ("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int | 
|  | fillup (unsigned char *ptr) | 
|  | { | 
|  | int size; | 
|  | int sum; | 
|  | int i; | 
|  |  | 
|  | size = getc (file); | 
|  | if (size == EOF | 
|  | || size <= 2) | 
|  | return 0; | 
|  |  | 
|  | size -= 2; | 
|  | if (fread (ptr, size, 1, file) != 1) | 
|  | return 0; | 
|  |  | 
|  | sum = code + size + 2; | 
|  |  | 
|  | for (i = 0; i < size; i++) | 
|  | sum += ptr[i]; | 
|  |  | 
|  | if ((sum & 0xff) != 0xff) | 
|  | printf (_("SUM IS %x\n"), sum); | 
|  |  | 
|  | if (dump) | 
|  | dh (ptr, size); | 
|  |  | 
|  | return size; | 
|  | } | 
|  |  | 
|  | static barray | 
|  | getBARRAY (unsigned char *ptr, int *idx, int dsize ATTRIBUTE_UNUSED, int max) | 
|  | { | 
|  | barray res; | 
|  | int i; | 
|  | int byte = *idx / 8; | 
|  | int size = 0; | 
|  |  | 
|  | if (byte < max) | 
|  | size = ptr[byte++]; | 
|  |  | 
|  | res.len = size; | 
|  | res.data = (unsigned char *) xmalloc (size); | 
|  |  | 
|  | for (i = 0; i < size; i++) | 
|  | res.data[i] = byte < max ? ptr[byte++] : 0; | 
|  |  | 
|  | return res; | 
|  | } | 
|  |  | 
|  | static int | 
|  | getINT (unsigned char *ptr, int *idx, int size, int max) | 
|  | { | 
|  | int n = 0; | 
|  | int byte = *idx / 8; | 
|  |  | 
|  | if (byte >= max) | 
|  | { | 
|  | /* PR 17512: file: id:000001,src:000002,op:flip1,pos:45.  */ | 
|  | /* Prevent infinite loops re-reading beyond the end of the buffer.  */ | 
|  | fatal (_("ICE: getINT: Out of buffer space")); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (size == -2) | 
|  | size = addrsize; | 
|  |  | 
|  | if (size == -1) | 
|  | size = 0; | 
|  |  | 
|  | switch (size) | 
|  | { | 
|  | case 0: | 
|  | return 0; | 
|  | case 1: | 
|  | n = (ptr[byte]); | 
|  | break; | 
|  | case 2: | 
|  | n = (ptr[byte + 0] << 8) + ptr[byte + 1]; | 
|  | break; | 
|  | case 4: | 
|  | n = (((unsigned) ptr[byte + 0] << 24) + (ptr[byte + 1] << 16) | 
|  | + (ptr[byte + 2] << 8) + (ptr[byte + 3])); | 
|  | break; | 
|  | default: | 
|  | fatal (_("Unsupported read size: %d"), size); | 
|  | } | 
|  |  | 
|  | *idx += size * 8; | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static int | 
|  | getBITS (unsigned char *ptr, int *idx, int size, int max) | 
|  | { | 
|  | int byte = *idx / 8; | 
|  | int bit = *idx % 8; | 
|  |  | 
|  | if (byte >= max) | 
|  | return 0; | 
|  |  | 
|  | *idx += size; | 
|  |  | 
|  | return (ptr[byte] >> (8 - bit - size)) & ((1 << size) - 1); | 
|  | } | 
|  |  | 
|  | static void | 
|  | itheader (char *name, int icode) | 
|  | { | 
|  | printf ("\n%s 0x%02x\n", name, icode); | 
|  | } | 
|  |  | 
|  | static int indent; | 
|  |  | 
|  | static void | 
|  | p (void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < indent; i++) | 
|  | printf ("| "); | 
|  |  | 
|  | printf ("> "); | 
|  | } | 
|  |  | 
|  | static void | 
|  | tabout (void) | 
|  | { | 
|  | p (); | 
|  | } | 
|  |  | 
|  | static void | 
|  | pbarray (barray *y) | 
|  | { | 
|  | int x; | 
|  |  | 
|  | printf ("%d (", y->len); | 
|  |  | 
|  | for (x = 0; x < y->len; x++) | 
|  | printf ("(%02x %c)", y->data[x], | 
|  | ISPRINT (y->data[x]) ? y->data[x] : '.'); | 
|  |  | 
|  | printf (")\n"); | 
|  | } | 
|  |  | 
|  | #define SYSROFF_PRINT | 
|  | #define SYSROFF_SWAP_IN | 
|  |  | 
|  | #include "sysroff.c" | 
|  |  | 
|  | /* FIXME: sysinfo, which generates sysroff.[ch] from sysroff.info, can't | 
|  | hack the special case of the tr block, which has no contents.  So we | 
|  | implement our own functions for reading in and printing out the tr | 
|  | block.  */ | 
|  |  | 
|  | #define IT_tr_CODE	0x7f | 
|  |  | 
|  | static void | 
|  | sysroff_swap_tr_in (void) | 
|  | { | 
|  | unsigned char raw[255]; | 
|  |  | 
|  | memset (raw, 0, 255); | 
|  | fillup (raw); | 
|  | } | 
|  |  | 
|  | static void | 
|  | sysroff_print_tr_out (void) | 
|  | { | 
|  | itheader ("tr", IT_tr_CODE); | 
|  | } | 
|  |  | 
|  | static int | 
|  | getone (int type) | 
|  | { | 
|  | int c = getc (file); | 
|  |  | 
|  | code = c; | 
|  |  | 
|  | if ((c & 0x7f) != type) | 
|  | { | 
|  | ungetc (c, file); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | switch (c & 0x7f) | 
|  | { | 
|  | case IT_cs_CODE: | 
|  | { | 
|  | struct IT_cs dummy; | 
|  | sysroff_swap_cs_in (&dummy); | 
|  | sysroff_print_cs_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dln_CODE: | 
|  | { | 
|  | struct IT_dln dummy; | 
|  | sysroff_swap_dln_in (&dummy); | 
|  | sysroff_print_dln_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_hd_CODE: | 
|  | { | 
|  | struct IT_hd dummy; | 
|  | sysroff_swap_hd_in (&dummy); | 
|  | addrsize = dummy.afl; | 
|  | sysroff_print_hd_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dar_CODE: | 
|  | { | 
|  | struct IT_dar dummy; | 
|  | sysroff_swap_dar_in (&dummy); | 
|  | sysroff_print_dar_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dsy_CODE: | 
|  | { | 
|  | struct IT_dsy dummy; | 
|  | sysroff_swap_dsy_in (&dummy); | 
|  | sysroff_print_dsy_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dfp_CODE: | 
|  | { | 
|  | struct IT_dfp dummy; | 
|  | sysroff_swap_dfp_in (&dummy); | 
|  | sysroff_print_dfp_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dso_CODE: | 
|  | { | 
|  | struct IT_dso dummy; | 
|  | sysroff_swap_dso_in (&dummy); | 
|  | sysroff_print_dso_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dpt_CODE: | 
|  | { | 
|  | struct IT_dpt dummy; | 
|  | sysroff_swap_dpt_in (&dummy); | 
|  | sysroff_print_dpt_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_den_CODE: | 
|  | { | 
|  | struct IT_den dummy; | 
|  | sysroff_swap_den_in (&dummy); | 
|  | sysroff_print_den_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dbt_CODE: | 
|  | { | 
|  | struct IT_dbt dummy; | 
|  | sysroff_swap_dbt_in (&dummy); | 
|  | sysroff_print_dbt_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dty_CODE: | 
|  | { | 
|  | struct IT_dty dummy; | 
|  | sysroff_swap_dty_in (&dummy); | 
|  | sysroff_print_dty_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_un_CODE: | 
|  | { | 
|  | struct IT_un dummy; | 
|  | sysroff_swap_un_in (&dummy); | 
|  | sysroff_print_un_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_sc_CODE: | 
|  | { | 
|  | struct IT_sc dummy; | 
|  | sysroff_swap_sc_in (&dummy); | 
|  | sysroff_print_sc_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_er_CODE: | 
|  | { | 
|  | struct IT_er dummy; | 
|  | sysroff_swap_er_in (&dummy); | 
|  | sysroff_print_er_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_ed_CODE: | 
|  | { | 
|  | struct IT_ed dummy; | 
|  | sysroff_swap_ed_in (&dummy); | 
|  | sysroff_print_ed_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_sh_CODE: | 
|  | { | 
|  | struct IT_sh dummy; | 
|  | sysroff_swap_sh_in (&dummy); | 
|  | sysroff_print_sh_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_ob_CODE: | 
|  | { | 
|  | struct IT_ob dummy; | 
|  | sysroff_swap_ob_in (&dummy); | 
|  | sysroff_print_ob_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_rl_CODE: | 
|  | { | 
|  | struct IT_rl dummy; | 
|  | sysroff_swap_rl_in (&dummy); | 
|  | sysroff_print_rl_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_du_CODE: | 
|  | { | 
|  | struct IT_du dummy; | 
|  | sysroff_swap_du_in (&dummy); | 
|  |  | 
|  | sysroff_print_du_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dus_CODE: | 
|  | { | 
|  | struct IT_dus dummy; | 
|  | sysroff_swap_dus_in (&dummy); | 
|  | sysroff_print_dus_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dul_CODE: | 
|  | { | 
|  | struct IT_dul dummy; | 
|  | sysroff_swap_dul_in (&dummy); | 
|  | sysroff_print_dul_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dss_CODE: | 
|  | { | 
|  | struct IT_dss dummy; | 
|  | sysroff_swap_dss_in (&dummy); | 
|  | sysroff_print_dss_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_hs_CODE: | 
|  | { | 
|  | struct IT_hs dummy; | 
|  | sysroff_swap_hs_in (&dummy); | 
|  | sysroff_print_hs_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_dps_CODE: | 
|  | { | 
|  | struct IT_dps dummy; | 
|  | sysroff_swap_dps_in (&dummy); | 
|  | sysroff_print_dps_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case IT_tr_CODE: | 
|  | sysroff_swap_tr_in (); | 
|  | sysroff_print_tr_out (); | 
|  | break; | 
|  |  | 
|  | case IT_dds_CODE: | 
|  | { | 
|  | struct IT_dds dummy; | 
|  |  | 
|  | sysroff_swap_dds_in (&dummy); | 
|  | sysroff_print_dds_out (&dummy); | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | printf (_("GOT A %x\n"), c); | 
|  | return 0; | 
|  | break; | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int | 
|  | opt (int x) | 
|  | { | 
|  | return getone (x); | 
|  | } | 
|  |  | 
|  | static void | 
|  | must (int x) | 
|  | { | 
|  | if (!getone (x)) | 
|  | printf (_("WANTED %x!!\n"), x); | 
|  | } | 
|  |  | 
|  | static void | 
|  | tab (int i, char *s) | 
|  | { | 
|  | indent += i; | 
|  |  | 
|  | if (s) | 
|  | { | 
|  | p (); | 
|  | puts (s); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | dump_symbol_info (void) | 
|  | { | 
|  | tab (1, _("SYMBOL INFO")); | 
|  |  | 
|  | while (opt (IT_dsy_CODE)) | 
|  | { | 
|  | if (opt (IT_dty_CODE)) | 
|  | { | 
|  | must (IT_dbt_CODE); | 
|  | derived_type (); | 
|  | must (IT_dty_CODE); | 
|  | } | 
|  | } | 
|  |  | 
|  | tab (-1, ""); | 
|  | } | 
|  |  | 
|  | static void | 
|  | derived_type (void) | 
|  | { | 
|  | tab (1, _("DERIVED TYPE")); | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | if (opt (IT_dpp_CODE)) | 
|  | { | 
|  | dump_symbol_info (); | 
|  | must (IT_dpp_CODE); | 
|  | } | 
|  | else if (opt (IT_dfp_CODE)) | 
|  | { | 
|  | dump_symbol_info (); | 
|  | must (IT_dfp_CODE); | 
|  | } | 
|  | else if (opt (IT_den_CODE)) | 
|  | { | 
|  | dump_symbol_info (); | 
|  | must (IT_den_CODE); | 
|  | } | 
|  | else if (opt (IT_den_CODE)) | 
|  | { | 
|  | dump_symbol_info (); | 
|  | must (IT_den_CODE); | 
|  | } | 
|  | else if (opt (IT_dds_CODE)) | 
|  | { | 
|  | dump_symbol_info (); | 
|  | must (IT_dds_CODE); | 
|  | } | 
|  | else if (opt (IT_dar_CODE)) | 
|  | { | 
|  | } | 
|  | else if (opt (IT_dpt_CODE)) | 
|  | { | 
|  | } | 
|  | else if (opt (IT_dul_CODE)) | 
|  | { | 
|  | } | 
|  | else if (opt (IT_dse_CODE)) | 
|  | { | 
|  | } | 
|  | else if (opt (IT_dot_CODE)) | 
|  | { | 
|  | } | 
|  | else | 
|  | break; | 
|  | } | 
|  |  | 
|  | tab (-1, ""); | 
|  | } | 
|  |  | 
|  | static void | 
|  | module (void) | 
|  | { | 
|  | int c = 0; | 
|  | int l = 0; | 
|  |  | 
|  | tab (1, _("MODULE***\n")); | 
|  |  | 
|  | do | 
|  | { | 
|  | c = getc (file); | 
|  | if (c == EOF) | 
|  | break; | 
|  | ungetc (c, file); | 
|  |  | 
|  | c &= 0x7f; | 
|  | } | 
|  | while (getone (c) && c != IT_tr_CODE); | 
|  |  | 
|  | tab (-1, ""); | 
|  |  | 
|  | c = getc (file); | 
|  | while (c != EOF) | 
|  | { | 
|  | printf ("%02x ", c); | 
|  | l++; | 
|  | if (l == 32) | 
|  | { | 
|  | printf ("\n"); | 
|  | l = 0; | 
|  | } | 
|  | c = getc (file); | 
|  | } | 
|  | } | 
|  |  | 
|  | ATTRIBUTE_NORETURN static void | 
|  | show_usage (FILE *ffile, int status) | 
|  | { | 
|  | fprintf (ffile, _("Usage: %s [option(s)] in-file\n"), program_name); | 
|  | fprintf (ffile, _("Print a human readable interpretation of a SYSROFF object file\n")); | 
|  | fprintf (ffile, _(" The options are:\n\ | 
|  | -h --help        Display this information\n\ | 
|  | -v --version     Print the program's version number\n")); | 
|  |  | 
|  | if (REPORT_BUGS_TO[0] && status == 0) | 
|  | fprintf (ffile, _("Report bugs to %s\n"), REPORT_BUGS_TO); | 
|  | exit (status); | 
|  | } | 
|  |  | 
|  | int | 
|  | main (int ac, char **av) | 
|  | { | 
|  | char *input_file = NULL; | 
|  | int option; | 
|  | static struct option long_options[] = | 
|  | { | 
|  | {"help", no_argument, 0, 'h'}, | 
|  | {"version", no_argument, 0, 'V'}, | 
|  | {NULL, no_argument, 0, 0} | 
|  | }; | 
|  |  | 
|  | #ifdef HAVE_LC_MESSAGES | 
|  | setlocale (LC_MESSAGES, ""); | 
|  | #endif | 
|  | setlocale (LC_CTYPE, ""); | 
|  | bindtextdomain (PACKAGE, LOCALEDIR); | 
|  | textdomain (PACKAGE); | 
|  |  | 
|  | program_name = av[0]; | 
|  | xmalloc_set_program_name (program_name); | 
|  | bfd_set_error_program_name (program_name); | 
|  |  | 
|  | expandargv (&ac, &av); | 
|  |  | 
|  | while ((option = getopt_long (ac, av, "HhVv", long_options, (int *) NULL)) != EOF) | 
|  | { | 
|  | switch (option) | 
|  | { | 
|  | case 'H': | 
|  | case 'h': | 
|  | show_usage (stdout, 0); | 
|  | /*NOTREACHED*/ | 
|  | case 'v': | 
|  | case 'V': | 
|  | print_version ("sysdump"); | 
|  | exit (0); | 
|  | /*NOTREACHED*/ | 
|  | case 0: | 
|  | break; | 
|  | default: | 
|  | show_usage (stderr, 1); | 
|  | /*NOTREACHED*/ | 
|  | } | 
|  | } | 
|  |  | 
|  | /* The input and output files may be named on the command line.  */ | 
|  |  | 
|  | if (optind < ac) | 
|  | input_file = av[optind]; | 
|  |  | 
|  | if (!input_file) | 
|  | fatal (_("no input file specified")); | 
|  |  | 
|  | file = fopen (input_file, FOPEN_RB); | 
|  |  | 
|  | if (!file) | 
|  | fatal (_("cannot open input file %s"), input_file); | 
|  |  | 
|  | module (); | 
|  | return 0; | 
|  | } |