/* * Copyright (C) 1985, 1991 by the University of Waterloo, * Computer Systems Group. All rights reserved. No part * of this software may be reproduced in any form or by * any means - graphic, electronic or mechanical, * including photocopying, recording, taping or * information storage and retrieval systems - except * with the written permission of the copyright owner. */ /* * listtxt -- create a readable version of a System/370 object file */ #include #include #include #include #include #include #include #include #include #include #include #include /* option_code -- order must match optiontable and optionexpl below */ typedef enum { OPT__ERROR, OPT_LOWER, OPT_TXTDUMP } option_code; static const char optiontable[] = { "Lower\0" "Txtdump\0" }; static const char * const optionexpl[] = { "access CMS files with lower case file names", "format TXT record data" }; extern sys_entry *_findfd( int fd ); static char *proc_cmdline( char *cmdline, int *tdptr ); static void usage( void ); static void processdeck( char *ipbuff, int norecs, int txtdump ); static void esdproc( esd_record *esdptr ); static void txtproc( txt_record *txtptr, int txtdump ); static void rldproc( rld_record *rldptr ); static void endproc( end_record *endptr ); static void *symproc( sym_record *symptr ); static void symfmt( sym_entry *septr, int symsize ); static void *lmalloc( size_t size ); const int _parms = UNTOKENIZED; int main( int argc, char **argv ) { char *fnbuff, *ipbuff; int objfd, txtdump, buflen, retval; struct stat stbuff; fnbuff = proc_cmdline( argv[ 0 ], &txtdump ); objfd = open( fnbuff, O_RDONLY | O_BINARY ); *strchr( fnbuff, '(' ) = '\0'; strrtrm( fnbuff ); if( objfd < 0 ) { fprintf( stderr, "Unable to open file \"%s\" for input\n %s\n", fnbuff, strerror( errno ) ); return( 28 ); } if( fstat( objfd, &stbuff ) ) { fprintf( stderr, "Unable to access file attributes for \"%s\"\n", fnbuff ); close( objfd ); return( 34 ); } if( ( stbuff.st_lrecl != 80 ) || ( stbuff.st_recfm != 'F' ) ) { fprintf( stderr, "File \"%s\" is not RECFM F LRECL 80\n", fnbuff ); close( objfd ); return( 34 ); } /* MM/DD/YY HH:MM:SS... */ fnbuff = stbuff.st_mtime; printf( "File: %8.8s %8.8s %2.2s (%02X/%02X/%02X %02X:%02X:%02X)\n", stbuff.st_fname, stbuff.st_ftype, stbuff.st_fmode, fnbuff[ 1 ], fnbuff[ 2 ], fnbuff[ 0 ], fnbuff[ 3 ], fnbuff[ 4 ], fnbuff[ 5 ] ); buflen = stbuff.st_size * 80; ipbuff = lmalloc( buflen ); retval = _fsread( &( _findfd( objfd )->se_fdbarea ), ipbuff, buflen, stbuff.st_size, &buflen ); close( objfd ); if( retval ) fprintf( stderr, "Error reading file \"%s\"\n %s\n", fnbuff, strerror( _fserrno( 'r', retval ) ) ); else processdeck( ipbuff, stbuff.st_size, txtdump ); return( 0 ); } static char *proc_cmdline( char *cmdline, int *tdptr ) { char *optptr, *optend, *fnbuff; cmdline = strchr( cmdline, ' ' ); if( cmdline == NULL ) usage(); cmdline = strskip( cmdline, ' ' ); if( ( *cmdline == '?' ) || ( *cmdline == '\0' ) ) usage(); *tdptr = 0; optptr = strchr( cmdline, '(' ); if( optptr != NULL ) { *optptr = '\0'; ++optptr; strrtrm( optptr ); while( *optptr != '\0' ) { optptr = strskip( optptr, ' ' ); optend = strchr( optptr, ' ' ); if( optend == NULL ) optend = optptr + strlen( optptr ); switch( tblookup( optiontable, optptr, optend - optptr ) ) { case OPT__ERROR: fprintf( stderr, "Unknown option \"%.*s\"\n", optend - optptr, optptr ); exit( 24 ); case OPT_TXTDUMP: *tdptr = 1; break; case OPT_LOWER: setmcase( 1 ); break; } optptr = optend; } } strrtrm( cmdline ); fnbuff = lmalloc( strlen( cmdline ) + 12 ); strcpy( fnbuff, cmdline ); if( ( strchr( fnbuff, ' ' ) == NULL ) && ( strchr( fnbuff, '.' ) == NULL ) ) strcat( fnbuff, " TEXT" ); strcat( fnbuff, " ( RAW" ); return( fnbuff ); } static void usage( void ) { char **optexplptr, *opttblptr; fprintf( stderr, "Usage: file-specifier" " { ( options } { redirection }\noptions:\n" ); optexplptr = optionexpl; for( opttblptr = optiontable; *opttblptr != '\0'; opttblptr += ( 1 + strlen( opttblptr ) ) ) fprintf( stderr, " %-8s %s\n", opttblptr, *optexplptr++ ); exit( 1 ); } static void processdeck( char *ipbuff, int norecs, int txtdump ) { for( ; norecs > 0; --norecs ) { if( ipbuff[ 0 ] == PUNCH_12_2_9 ) { if( memcmp( &ipbuff[ 1 ], "ESD", 3 ) == 0 ) esdproc( (esd_record *) ipbuff ); else if( memcmp( &ipbuff[ 1 ], "TXT", 3 ) == 0 ) txtproc( (txt_record *) ipbuff, txtdump ); else if( memcmp( &ipbuff[ 1 ], "RLD", 3 ) == 0 ) rldproc( (rld_record *) ipbuff ); else if( memcmp( &ipbuff[ 1 ], "END", 3 ) == 0 ) endproc( (end_record *) ipbuff ); else if( memcmp( &ipbuff[ 1 ], "SYM", 3 ) == 0 ) { /* "SYM" records are packed together; symproc handles */ /* all consecutive SYM records before returning... */ ipbuff = symproc( (sym_record *) ipbuff ); continue; } else fprintf( stderr, "Unknown label \"%.3s\"\n", ipbuff + 1); } ipbuff += 80; } } static void esdproc( esd_record *esdptr ) { esd_item *esditptr; int esd_item_cnt, esdtype, esd_flag; char *esdstr; esd_item_cnt = ( esdptr->esd_itemcnt ) / sizeof( esd_item ); printf( "ESD %04X %d", esdptr->esd_esdid, esd_item_cnt ); if( esd_item_cnt == 0 ) { printf( " entries\n" ); return; } if( esd_item_cnt == 1 ) printf( " entry: " ); else printf( " entries:" ); esditptr = esdptr->esd_items; for(;;) { esdtype = esditptr->esd__ta.esd_type; if( esdtype == ESDT_SD ) esdstr = "SD"; else if( esdtype == ESDT_LD ) esdstr = "LD"; else if( esdtype == ESDT_ER ) esdstr = "ER"; else if( esdtype == ESDT_PC ) esdstr = "PC"; else if( esdtype == ESDT_CM ) esdstr = "CM"; else if( esdtype == ESDT_XD ) esdstr = "XD"; else if( esdtype == ESDT_WX ) esdstr = "WX"; else esdstr = "??"; esd_flag = esditptr->esd__ae.esd_align; printf( " %8.8s %s %06X %02X %06X ", esditptr->esd_name, esdstr, esditptr->esd__ta.esd_addr, esd_flag, esditptr->esd__ae.esd_extra ); if( ( esdtype == ESDT_CM ) || ( esdtype == ESDT_PC ) || ( esdtype == ESDT_SD ) ) { if( esd_flag == 0x40 ) printf( "(No AMODE/RMODE)" ); else { if( esd_flag & ESDA_RMODE_ANY ) printf( "(RMODE ANY/" ); else printf( "(RMODE 24/" ); esd_flag &= 0x03; if( esd_flag == ESDA_AMODE_24D ) printf( "AMODE 24 default)" ); else if( esd_flag == ESDA_AMODE_24 ) printf( "AMODE 24)" ); else if( esd_flag == ESDA_AMODE_31 ) printf( "AMODE 31)" ); else printf( "AMODE ANY)" ); } } printf( "\n" ); if( --esd_item_cnt == 0 ) return; printf( " " ); ++esditptr; } } static void txtproc( txt_record *txtptr, int txtdump ) { int *intptr; char *bufptr, *bufend; if( txtdump == 0 ) { printf( "TXT Addr %06X Size %02X ESDID %04X\n", txtptr->txt__f.txt_faddr, txtptr->txt_size, txtptr->txt_esdid ); return; } intptr = (int *) ( txtptr->txt_info ); printf( "TXT %06X %04X %08X %08X %08X %08X %08X %08X %08X\n", txtptr->txt__f.txt_faddr, txtptr->txt_esdid, intptr[ 0 ], intptr[ 1 ], intptr[ 2 ], intptr[ 3 ], intptr[ 4 ], intptr[ 5 ], intptr[ 6 ] ); printf( " %02X %08X %08X %08X %08X %08X %08X %08X\n", txtptr->txt_size, intptr[ 7 ], intptr[ 8 ], intptr[ 9 ], intptr[ 10 ], intptr[ 11 ], intptr[ 12 ], intptr[ 13 ] ); bufptr = txtptr->txt_info; bufend = &bufptr[ 56 ]; for( ; bufptr < bufend; ++bufptr ) if( isprint( *bufptr ) == 0 ) *bufptr = '.'; *bufptr = '\0'; printf( " >%s<\n", txtptr->txt_info ); } static void rldproc( rld_record *rldptr ) { int same_esdids, rldoffset, relesdid, posesdid, rldflag; rld_entry *rldentptr; rld_faddr *rldfaptr; char fdstr[ 8 ]; printf( "RLD" ); same_esdids = 0; rldentptr = rldptr->rld_data; for( rldoffset = 0; rldoffset < rldptr->rld_size; rldoffset += 4 ) { if( rldoffset ) printf( "\n " ); if( same_esdids == 0 ) { relesdid = rldentptr->rld_relesdid; posesdid = rldentptr->rld_posesdid; rldfaptr = &rldentptr->rld__fa; rldoffset += 4; } rldflag = rldfaptr->rld_flag; same_esdids = ( ( rldflag & 0x01 ) != 0 ); strcpy( fdstr, " +" ); switch( rldflag >> 4 ) { case 0: memcpy( fdstr, "A/Y", 3 ); break; case 1: fdstr[ 0 ] = 'V'; break; case 2: fdstr[ 0 ] = 'Q'; break; case 3: memcpy( fdstr, "CXD", 3 ); } fdstr[ 4 ] = "1234"[ ( rldflag & 0x0c ) >> 2 ]; if( ( rldflag & 0x02 ) == 0x02 ) fdstr[ 6 ] = '-'; printf( " %04X %04X %02X(%s) %06X", relesdid, posesdid, rldflag, fdstr, rldfaptr->rld_addr ); ++rldfaptr; rldentptr = (rld_entry *) rldfaptr; } printf( "\n" ); } static void endproc( end_record *endptr ) { printf( "END Entry" ); if( endptr->end__e.end_entpt == 0x404040 ) printf( " (none)" ); else printf( " %06X", endptr->end__e.end_entpt ); printf( " ESDID" ); if( endptr->end_esdid == 0x4040 ) printf( " (none)" ); else printf( " %04X ", endptr->end_esdid ); printf( " %c pgmid=\"%19.19s\" deckid=\"%8.8s\"\n", endptr->end_12, endptr->end_pgmid, endptr->end_deckid ); } static void *symproc( sym_record *symptr ) { sym_entry *septr; char *bufptr; int bufsize, symsize; septr = (sym_entry *) ( symptr->sym_info ); bufptr = symptr->sym_deckid; bufsize = symptr->sym_size; for(;;) { ++symptr; if( memcmp( symptr->sym_label, "SYM", 3 ) ) break; symsize = symptr->sym_size; memcpy( bufptr, symptr->sym_info, symsize ); bufptr += symsize; bufsize += symsize; } symfmt( septr, bufsize ); return( symptr ); } static void symfmt( sym_entry *septr, int symsize ) { int symoffset, dtyplen, dtypmf, dtypsc, sesize,namelen; char *dtypstr, *lmsptr; printf( "SYM" ); for( symoffset = 0; symoffset < symsize; symoffset += sesize ) { if( symoffset ) printf( "\n " ); sesize = 4; printf( " %06X ", septr->se__oa.se_addr ); if( ( (septr->se__oa.se_org) & 0x08 ) == 0 ) { /* name present... */ namelen = ( septr->se__oa.se_org & 0x07 ) + 1; printf( "%.*s", namelen, septr->se_name ); sesize += namelen; } if( ( septr->se__oa.se_org) & 0x80 ) { /* data type... */ dtypstr = ((char *) septr) + sesize; sesize += 2; lmsptr = dtypstr + 1; dtyplen = *lmsptr; ++lmsptr; if( ( *dtypstr == SYMDT_C ) || ( *dtypstr == SYMDT_X ) || ( *dtypstr == SYMDT_B ) ) { dtyplen <<= 8; dtyplen += *lmsptr; ++lmsptr; ++sesize; } ++dtyplen; dtypmf = 1; if( ( septr->se__oa.se_org) & 0x40 ) { /* multiplicity specified... */ dtypmf = *lmsptr; dtypmf <<= 8; ++lmsptr; dtypmf += *lmsptr; dtypmf <<= 8; ++lmsptr; dtypmf += *lmsptr; ++lmsptr; sesize += 3; } dtypsc = 1; if( ( septr->se__oa.se_org) & 0x10 ) { /* scale specified... */ dtypsc = *(short int *) lmsptr; sesize += 2; } switch( *dtypstr ) { case SYMDT_C: dtypstr = "C"; break; case SYMDT_X: dtypstr = "X"; break; case SYMDT_B: dtypstr = "B"; break; case SYMDT_F: dtypstr = "F"; break; case SYMDT_H: dtypstr = "H"; break; case SYMDT_E: dtypstr = "E"; break; case SYMDT_D: dtypstr = "D"; break; case SYMDT_AQ: dtypstr = "A/Q"; break; case SYMDT_Y: dtypstr = "Y"; break; case SYMDT_S: dtypstr = "S"; break; case SYMDT_V: dtypstr = "V"; break; case SYMDT_P: dtypstr = "P"; break; case SYMDT_Z: dtypstr = "Z"; break; case SYMDT_L: dtypstr = "L"; break; default: dtypstr = "(unknown data type)"; } printf( " %d%sL%d:%d ", dtypmf, dtypstr, dtyplen, dtypsc ); if( ( septr->se__oa.se_org) & 0x20 ) printf( "(cluster)" ); else printf( "(independent)" ); } else { /* non-data type... */ switch( ( septr->se__oa.se_org ) >> 4 ) { case 0: dtypstr = "space"; dtyplen = ((char *) septr)[ sesize ]; ++sesize; break; case 1: dtypstr = "CSECT"; break; case 2: dtypstr = "DSECT"; break; case 3: dtypstr = "COMMON"; break; case 4: dtypstr = "instr"; break; case 5: dtypstr = "CCW"; break; case 6: dtypstr = "EQU/ORG"; break; case 7: dtypstr = "(unknown)"; break; } printf( " %s", dtypstr ); if( ( ( septr->se__oa.se_org ) >> 4 ) == 0 ) printf( "(%d)", dtyplen ); } septr = (sym_entry *) ( ((char *) septr) + sesize ); } printf( "\n" ); } static void *lmalloc( size_t size ) { void *ptr; ptr = malloc( size ); if( ptr == NULL ) { fprintf( stderr, "Insufficient memory\n" ); exit( 41 ); } return( ptr ); }