| /* Sysroff object format dumper. |
| Copyright (C) 1994-2024 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; |
| } |