mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-06-25 14:29:34 +00:00
lseg 1.1 (beta) as contributed by Dave Tribby. Some files had an RCS
identifier added.
This commit is contained in:
parent
f6efe9ae26
commit
5fd930582d
|
@ -1,5 +1,21 @@
|
|||
lseg.root: lseg.c
|
||||
compile lseg.c keep=lseg
|
||||
#
|
||||
# This makefile is intended for use with dmake(1) on Apple IIGS
|
||||
#
|
||||
# $Id: Makefile,v 1.2 1997/09/21 22:05:58 gdr Exp $
|
||||
#
|
||||
|
||||
lseg: lseg.root
|
||||
link lseg 2/direct256 keep=lseg
|
||||
# Program name
|
||||
PROG = lseg
|
||||
|
||||
# Default stack size and optimization (can be overridden by cmd line)
|
||||
.IF $(STACK) == $(NULL)
|
||||
STACK = 1024
|
||||
.END
|
||||
##.IF $(STACK) == $(NULL)
|
||||
## OPTIMIZE = -1
|
||||
##.END
|
||||
|
||||
# Delivery directory
|
||||
BINDIR = /usr/bin
|
||||
|
||||
.INCLUDE : /src/gno/gno.prog.mk
|
||||
|
|
|
@ -1,27 +1,49 @@
|
|||
LSEG(1) Commands and Applications LESS(1)
|
||||
|
||||
|
||||
|
||||
NAME
|
||||
lseg - list segments in an OMF file
|
||||
|
||||
SYNOPSIS
|
||||
lseg file ...
|
||||
|
||||
DESCRIPTION
|
||||
lseg lists the segments of an OMF executable file. While it can
|
||||
list the segments in an intermediate object file, the information
|
||||
isn't as useful.
|
||||
|
||||
lseg is intended for discovering the location of stack segments in
|
||||
existing applications (for editing to smaller sizes), as an
|
||||
aid in determining how to segment large C files whose segments
|
||||
exceed the bank size, and for deciding which segments to recombine
|
||||
after excessive segmentation.
|
||||
|
||||
AUTHOR
|
||||
Jawaid Bazyar for GNO/ME 1.0.
|
||||
|
||||
BUGS
|
||||
Doesn't detect non-OMF files, and thus can get very confused if you
|
||||
do "lseg *" and one of the files chosen isn't an OMF file.
|
||||
.\" Man page by Dave Tribby, September 1997
|
||||
.\"
|
||||
.\" $Id: lseg.1,v 1.2 1997/09/21 22:05:58 gdr Exp $
|
||||
.\"
|
||||
.TH LSEG 1 "September 1997" "GNO" "Commands and Applications"
|
||||
.SH NAME
|
||||
.BR lseg
|
||||
\- list segments in an Object Module Format file
|
||||
.SH SYNOPSIS
|
||||
.BR lseg " file ..."
|
||||
.SH DESCRIPTION
|
||||
.BR lseg
|
||||
lists segments in an OMF (object module format) file. Four kinds
|
||||
of files use object module format: object files (the output of an
|
||||
assembler or compiler and the input to a linker), library files
|
||||
(segments that a linker can extract to resolve references in
|
||||
other object files), load files (the output of a linker, ready
|
||||
for execution), and run-time library files (segments that can
|
||||
be loaded as needed and purged from memory when no longer needed).
|
||||
A full description of OMF files is provided in Appendix F of
|
||||
.IR "Apple IIGS GS/OS Reference" .
|
||||
.PP
|
||||
.BR lseg
|
||||
prints a report that includes the type and size of each segment
|
||||
of each file. Any file that is not a valid OMF file is so noted.
|
||||
.PP
|
||||
.BR lseg
|
||||
can be used on executable files in the following ways: to help discover
|
||||
the location of stack segments (for later editing to smaller sizes), as an
|
||||
aid in determining how to segment large C files whose segments
|
||||
exceed the bank size, and for deciding which segments to recombine
|
||||
after excessive segmentation.
|
||||
.PP
|
||||
For object and library files,
|
||||
.BR lseg
|
||||
examines each code segment and tries to figure out how
|
||||
many bytes of local storage are allocated from the stack at execution
|
||||
time. This will be determined only if the startup code matches a recognized
|
||||
algorithm, such as those used by ORCA/C. If it can be determined, the
|
||||
value is printed at the end of the line preceeded by
|
||||
string "Stack bytes:".
|
||||
Note that this value does not include parameters passed into the routine,
|
||||
nor does it include any other use of the stack by the routine. If a
|
||||
segment has an unusually large stack allocation, examine its source code
|
||||
and see whether arrays can be made static (if the routine is not
|
||||
recursive) or can be allocated from standard memory by
|
||||
.IR malloc (3).
|
||||
.SH AUTHOR
|
||||
Jawaid Bazyar for GNO/ME 1.0; updated by Dave Tribby for GNO/ME 2.0.6.
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
#pragma optimize -1
|
||||
#pragma stacksize 1024
|
||||
/*
|
||||
* lseg - list segments of an OMF file
|
||||
*
|
||||
* Version 1.0 written by Jawaid Bazyar for GNO/ME 1.0 (June 1992)
|
||||
*
|
||||
* Version 1.1 [v1.1] updated by Dave Tribby (Sept. 1997)
|
||||
* - A few changes for GNO/ME 2.0.6
|
||||
* - Added display of allocated stack bytes for code segments
|
||||
* - Reformatted output to align names and make room for new info
|
||||
* - Sanity check to see whether file is an OMF file
|
||||
* - Use first field as block count for OMF version 1 files
|
||||
* - Continue processing files even if one cannot be opened
|
||||
* - Use standard error reporting interfaces
|
||||
*
|
||||
* $Id: lseg.c,v 1.2 1997/09/21 22:05:59 gdr Exp $
|
||||
*/
|
||||
|
||||
/* Update for 2.0.6: Move optimization and stack size to Makefile
|
||||
/* #pragma optimize -1 /* Doesn't work for ORCA/C 2.1 */
|
||||
/* #pragma stacksize 1024
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -7,6 +26,8 @@
|
|||
#include <gsos.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h> /* GNO 2.0.6: read() and close() moved to here */
|
||||
#include <err.h> /* GNO 2.0.6: use standard error reporting */
|
||||
|
||||
typedef struct OMFhead {
|
||||
longword BYTECNT;
|
||||
|
@ -51,26 +72,138 @@ char *segTypes[] = {
|
|||
"Unknown",
|
||||
"Direct-page/Stack"};
|
||||
|
||||
|
||||
/* --- Start of new routines [v1.1] --- */
|
||||
|
||||
/* Snippit of code to be analyzed for allocated stack size */
|
||||
static char code[8];
|
||||
|
||||
/* Read a segment-body record; return the following values: */
|
||||
/* 0 if stack allocation code not found, but expected to follow */
|
||||
/* -1 if recognized as leading to stack allocation */
|
||||
/* >0 bytes of stack allocation */
|
||||
int readSegRec(int fd)
|
||||
{
|
||||
char rec_type;
|
||||
char *cp=code;
|
||||
int num_bytes;
|
||||
/* Normal preamble code includes phd, which uses 2 bytes */
|
||||
int base_size=2;
|
||||
|
||||
/* Read record type (opcode) */
|
||||
read(fd,&rec_type,1);
|
||||
|
||||
/* Is it executable code? */
|
||||
if (rec_type > 0 && rec_type < 0xDF) {
|
||||
/* Determine size to read: min of rec_type and size of code array */
|
||||
if (rec_type > sizeof(code))
|
||||
num_bytes = sizeof(code);
|
||||
else
|
||||
num_bytes = rec_type;
|
||||
read(fd,code,num_bytes);
|
||||
|
||||
/* Is it the code for no local variables: pha ; tsc ; phd ; tcd ? */
|
||||
if (rec_type > 2) {
|
||||
/* NOTE: pha is included only when code is not optimized */
|
||||
if ( *(cp) == 0x48 ) {
|
||||
/* pha uses 2 additional bytes of stack */
|
||||
base_size = 4;
|
||||
cp++;
|
||||
}
|
||||
if ( *(cp++) == 0x3B && *(cp++) == 0x0B && *cp == 0x5B )
|
||||
return base_size; /* Yes; return base size */
|
||||
/* No; reset pointer and base size before checking further */
|
||||
cp = code;
|
||||
base_size = 2;
|
||||
}
|
||||
|
||||
/* Is this the short preamble code: pea $xxxx ; jsl ~CHECKSTACK ? */
|
||||
if (rec_type == 4) {
|
||||
if ( *(cp) == 0xF4 && code[3] == 0x22)
|
||||
return 0; /* Expect allocation later */
|
||||
else
|
||||
return -1; /* Give up */
|
||||
}
|
||||
|
||||
/* Does it start with tsc ; sec ; sbc #x ? */
|
||||
if (rec_type > 7) {
|
||||
if ( *(cp++) == 0x3B && *(cp++) == 0x38 && *(cp++) == 0xE9 )
|
||||
/* This is the preamble we're looking for! */
|
||||
/* Next two bytes are size of local variables */
|
||||
return *(int*)cp + base_size;
|
||||
else
|
||||
return -1; /* Give up */
|
||||
}
|
||||
} /* End of code cases */
|
||||
|
||||
/* Is it an LEXPR record? (expected as part of jsl ~CHECKSTACK) */
|
||||
if (rec_type == 0xF3) {
|
||||
/* Read the replacement length, op type, string length */
|
||||
read(fd,code,3);
|
||||
if ( *(cp++) == 0x03 && *(cp++) == 0x83 ) {
|
||||
/* Position file beyond the expression string */
|
||||
num_bytes = *cp;
|
||||
lseek(fd, num_bytes, SEEK_CUR);
|
||||
/* Next character should be null byte following string */
|
||||
read(fd,code,1);
|
||||
if (*code == 0)
|
||||
return 0; /* Expect allocation later */
|
||||
}
|
||||
}
|
||||
return -1; /* Give up */
|
||||
}
|
||||
|
||||
|
||||
/* Check code segments for dynamic startup stack allocation */
|
||||
void checkCodeStack(int fd)
|
||||
{
|
||||
int value;
|
||||
|
||||
while ( (value = readSegRec(fd)) == 0 );
|
||||
if (value > 0) printf(" Stack bytes: %d", value);
|
||||
}
|
||||
|
||||
/* Is the file under consideration not an OMF file? */
|
||||
int notOMF(OMFhead *headPnt)
|
||||
{
|
||||
if (headPnt->NUMLEN != 4
|
||||
|| headPnt->VERSION > 2
|
||||
|| headPnt->BANKSIZE > 0x010000
|
||||
|| headPnt->NUMSEX != 0
|
||||
|| headPnt->DISPNAME > headPnt->DISPDATA) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* --- End of new routines [v1.1] --- */
|
||||
|
||||
|
||||
void prntAscii(char *s, int l)
|
||||
{
|
||||
/* Pad with blanks if < 18 chars [v1.1] */
|
||||
int pad;
|
||||
|
||||
pad = 18 - l;
|
||||
putchar('"');
|
||||
while (l--) {
|
||||
*s &= 0x7F;
|
||||
if (*s < ' ') {
|
||||
putchar('^');
|
||||
putchar(*s+'@');
|
||||
pad--;
|
||||
} else putchar(*s);
|
||||
s++;
|
||||
}
|
||||
putchar('"');
|
||||
while (pad-- > 0)
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
char name[256];
|
||||
/*
|
||||
* returns either 0 (no stack segment found) or the size of the stack
|
||||
* segment contained in the application
|
||||
* The caller is responsible for opening the file, passing it's refNum,
|
||||
* The caller is responsible for opening the file, passing its refNum,
|
||||
* and closing it after we're done
|
||||
*/
|
||||
word scanOMF(int fd)
|
||||
void scanOMF(int fd)
|
||||
{
|
||||
OMFhead header;
|
||||
longword off = 0l;
|
||||
|
@ -84,10 +217,15 @@ int stsize = 0;
|
|||
|
||||
while (off < p.position) {
|
||||
/* printf("offset: %ld\t\t",off); */
|
||||
putchar('\t');
|
||||
lseek(fd, off, 0);
|
||||
printf(" ");
|
||||
lseek(fd, off, SEEK_SET);
|
||||
read(fd,&header,sizeof(header));
|
||||
lseek(fd, off+header.DISPNAME+10, 0);
|
||||
/* First time through, check validity of OMF header [v1.1] */
|
||||
if (off == 0 && notOMF(&header)) {
|
||||
printf("Not a recognized OMF file\n");
|
||||
return;
|
||||
}
|
||||
lseek(fd, off+header.DISPNAME+10, SEEK_SET);
|
||||
if (header.LABLEN == 0) {
|
||||
read(fd, name, 1);
|
||||
read(fd, name+1, name[0]);
|
||||
|
@ -95,18 +233,35 @@ int stsize = 0;
|
|||
name[0] = header.LABLEN;
|
||||
read(fd, name+1, header.LABLEN);
|
||||
}
|
||||
putchar('"');
|
||||
prntAscii(name+1,name[0]);
|
||||
putchar('"');
|
||||
kind = header.KIND & 0x1F;
|
||||
if (kind < 0x13)
|
||||
printf("\t%s segment (%02X) %08lX bytes\n",segTypes[kind],kind,
|
||||
header.LENGTH);
|
||||
if (kind < 0x13) {
|
||||
printf(" %s segment (%02X) %06lX bytes",
|
||||
segTypes[kind],kind,header.LENGTH);
|
||||
/* Check code segment for stack allocation [v1.1] */
|
||||
if (kind == 0) {
|
||||
/* Position to beginning of data */
|
||||
lseek(fd, off+header.DISPDATA, SEEK_SET);
|
||||
/* Check the code */
|
||||
checkCodeStack(fd);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
if (kind == 0x12) /* got a stack segment */
|
||||
stsize = (word) header.LENGTH;
|
||||
off += header.BYTECNT;
|
||||
/* In OMF version 1, the first field is a block count */
|
||||
if (header.VERSION == 1)
|
||||
off += (header.BYTECNT * 512);
|
||||
else
|
||||
off += header.BYTECNT;
|
||||
/* Check for unusual case that causes infinite loop [v1.1] */
|
||||
if (header.BYTECNT == 0) break;
|
||||
}
|
||||
return (stsize ? stsize : 4096); /* the default stack size for programs */
|
||||
/* The default stack size for programs is 4096 */
|
||||
if (stsize)
|
||||
printf("\tStack size: %d\n", stsize);
|
||||
else
|
||||
printf("\tDefault stack size: 4096\n");
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
|
@ -115,20 +270,41 @@ void usage(void)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Added for 2.0.6: Check on how much stack space a C program uses. */
|
||||
#if defined(__STACK_CHECK__)
|
||||
#ifndef _GNO_GNO_H_
|
||||
#include <gno/gno.h>
|
||||
#endif
|
||||
static void report_stack(void)
|
||||
{
|
||||
fprintf(stderr,"\n ==> %d stack bytes used <== \n", _endStackCheck());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int exit_status=0;
|
||||
|
||||
#if defined(__STACK_CHECK__)
|
||||
_beginStackCheck();
|
||||
atexit(report_stack);
|
||||
#endif
|
||||
|
||||
if (argc == 1) usage();
|
||||
argv++; argc--;
|
||||
while (argc-- > 0) {
|
||||
fd = open(*argv,O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr,"lseg: %s: %s\n",*argv, strerror(errno));
|
||||
exit(1);
|
||||
if ((fd = open(*argv, O_RDONLY)) < 0) {
|
||||
exit_status = 1;
|
||||
warn("%s", *argv);
|
||||
} else {
|
||||
printf("File: %s\n",*argv);
|
||||
scanOMF(fd);
|
||||
close(fd);
|
||||
}
|
||||
printf("Executable: %s\n",*(argv++));
|
||||
printf("\tStack size: %d\n",scanOMF(fd));
|
||||
close(fd);
|
||||
}
|
||||
++argv;
|
||||
}
|
||||
return exit_status;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user