/* Copyright (c) 1982 Regents of the University of California */
static char sccsid
[] = "@(#)object.c 1.15 (Berkeley) %G%";
* Object code interface, mainly for extraction of symbolic information.
unsigned int stringsize
; /* size of the dumped string table */
unsigned int nsyms
; /* number of symbols */
unsigned int nfiles
; /* number of files */
unsigned int nlines
; /* number of lines */
public String objname
= "a.out";
private struct nlist
*curnp
;
private Boolean strip_
= false;
private Linetab
*linep
, *prevlinep
;
public String
curfilename ()
return ((filep
-1)->filename
);
* Blocks are figured out on the fly while reading the symbol table.
private Symbol blkstack
[MAXBLKDEPTH
];
private integer curlevel
;
private integer bnum
, nesting
;
private Address addrstk
[MAXBLKDEPTH
];
if (curlevel
>= MAXBLKDEPTH
) {
fatal("nesting depth too large (%d)", curlevel
);
blkstack
[curlevel
] = curblock
;
printf("entering block %s\n", symname(b
));
b
->level
= curblock
->level
+ 1;
if (curblock
->class == FUNC
or curblock
->class == PROC
) {
if (prevlinep
!= linep
) {
curblock
->symvalue
.funcv
.src
= true;
panic("nesting depth underflow (%d)", curlevel
);
printf("exiting block %s\n", symname(curblock
));
curblock
= blkstack
[curlevel
];
* Enter a source line or file name reference into the appropriate table.
* Expanded inline to reduce procedure calls.
* private enterline (linenumber, address)
#define enterline(linenumber, address) \
if (linenumber != lp->line) { \
if (address != lp->addr) { \
* Read in the namelist from the obj file.
* Reads and seeks are used instead of fread's and fseek's
* for efficiency sake; there's a lot of data being read here.
fatal("can't open %s", file
);
read(f
, &hdr
, sizeof(hdr
));
nlhdr
.nsyms
= hdr
.a_syms
/ sizeof(nlist
);
nlhdr
.nfiles
= nlhdr
.nsyms
;
nlhdr
.nlines
= nlhdr
.nsyms
;
lseek(f
, (long) N_STROFF(hdr
), 0);
read(f
, &(nlhdr
.stringsize
), sizeof(nlhdr
.stringsize
));
stringtab
= newarr(char, nlhdr
.stringsize
);
read(f
, stringtab
, nlhdr
.stringsize
);
allocmaps(nlhdr
.nfiles
, nlhdr
.nlines
);
lseek(f
, (long) N_SYMOFF(hdr
), 0);
* Read in symbols from object file.
register struct nlist
*np
, *ub
;
register Boolean afterlg
;
namelist
= newarr(struct nlist
, nlhdr
.nsyms
);
read(f
, namelist
, nlhdr
.nsyms
* sizeof(struct nlist
));
ub
= &namelist
[nlhdr
.nsyms
];
name
= &stringtab
[index
- 4];
* If the program contains any .f files a trailing _ is stripped
* from the name on the assumption it was added by the compiler.
* This only affects names that follow the sdb N_SO entry with
if (strip_
and name
[0] != '\0' ) {
lastchar
= &name
[strlen(name
) - 1];
* not an N_STAB ==> name != nil
* name[0] == '-' ==> name == "-lg"
* name[0] != '_' ==> filename or invisible
* The "-lg" signals the beginning of global loader symbols.
if ((np
->n_type
&N_STAB
) != 0) {
} else if (name
[0] == '-') {
if (curblock
->class != PROG
) {
if (curblock
->class != PROG
) {
enterline(0, (linep
-1)->addr
+ 1);
check_global(&name
[1], np
);
} else if (name
[0] == '_') {
check_local(&name
[1], np
);
} else if ((np
->n_type
&N_TEXT
) == N_TEXT
) {
fatal("not linked for debugging, use \"cc -g ...\"");
* Get a continuation entry from the name list.
* Return the beginning of the name.
index
= curnp
->n_un
.n_strx
;
panic("continuation followed by empty stab");
name
= &stringtab
[index
- 4];
* Initialize symbol information.
program
= insert(identname("", true));
program
->symvalue
.funcv
.beginaddr
= 0;
program
->symvalue
.funcv
.inline = false;
newfunc(program
, codeloc(program
));
t_boolean
= maketype("$boolean", 0L, 1L);
t_int
= maketype("$integer", 0x80000000L
, 0x7fffffffL
);
t_char
= maketype("$char", 0L, 255L);
t_real
= maketype("$real", 8L, 0L);
t_nil
= maketype("$nil", 0L, 0L);
t_open
= maketype("integer", 0L, -1L);
* Free all the object file information that's being stored.
* Enter a namelist entry.
private enter_nl (name
, np
)
register struct nlist
*np
;
* Build a symbol for the FORTRAN common area. All GSYMS that follow
* will be chained in a list with the head kept in common.offset, and
* the tail in common.chain.
curcomm
->symvalue
.common
.chain
= commchain
;
n
= identname(name
, true);
curcomm
->block
= curblock
;
curcomm
->level
= program
->level
;
curcomm
->symvalue
.common
.chain
= nil
;
commchain
= curcomm
->symvalue
.common
.chain
;
curcomm
->symvalue
.common
.chain
= commchain
;
addrstk
[nesting
] = (linep
- 1)->addr
;
if (addrstk
[nesting
] == NOADDR
) {
newfunc(curblock
, (linep
- 1)->addr
);
addrstk
[nesting
] = (linep
- 1)->addr
;
enterline((Lineno
) np
->n_desc
, (Address
) np
->n_value
);
n
= identname(name
, true);
enterSourceModule(n
, (Address
) np
->n_value
);
* Textually included files.
enterfile(name
, (Address
) np
->n_value
);
* These symbols are assumed to have non-nil names.
if (index(name
, ':') == nil
) {
warning("old style symbol information found in \"%s\"",
printf("warning: stab entry unrecognized: ");
printf("name %s,", name
);
printf("ntype %2x, desc %x, value %x'\n",
np
->n_type
, np
->n_desc
, np
->n_value
);
* Try to find the symbol that is referred to by the given name.
* Since it's an external, we may want to follow a level of indirection.
private Symbol
findsym (n
)
s
->level
== program
->level
and
(s
->class == EXTREF
or s
->class == VAR
or
s
->class == PROC
or s
->class == FUNC
)
if (s
!= nil
and s
->class == EXTREF
) {
* Check to see if a global _name is already in the symbol table,
private check_global (name
, np
)
register struct nlist
*np
;
if (not streq(name
, "end")) {
n
= identname(name
, true);
if ((np
->n_type
&N_TYPE
) == N_TEXT
) {
t
->language
= findlanguage(".s");
t
->level
= program
->level
;
t
->symvalue
.funcv
.src
= false;
t
->symvalue
.funcv
.inline = false;
t
->symvalue
.offset
= np
->n_value
;
t
->symvalue
.funcv
.beginaddr
= np
->n_value
;
} else if ((np
->n_type
&N_TYPE
) == N_BSS
) {
u
= (Symbol
) t
->symvalue
.common
.offset
;
u
->symvalue
.offset
= u
->symvalue
.common
.offset
+np
->n_value
;
u
= u
->symvalue
.common
.chain
;
* Check to see if a namelist entry refers to a variable.
* If not, create a variable for the entry. In any case,
* set the offset of the variable according to the value field
private check_var (np
, n
)
t
->language
= findlanguage(".s");
t
->level
= program
->level
;
t
->symvalue
.offset
= np
->n_value
;
* Check to see if a local _name is known in the current scope.
private check_local (name
, np
)
register struct nlist
*np
;
n
= identname(name
, true);
cur
= ((np
->n_type
&N_TYPE
) == N_TEXT
) ? curmodule
: curblock
;
find(t
, n
) where t
->block
== cur
endfind(t
);
t
->language
= findlanguage(".s");
if ((np
->n_type
&N_TYPE
) == N_TEXT
) {
t
->symvalue
.funcv
.src
= false;
t
->symvalue
.funcv
.inline = false;
t
->symvalue
.funcv
.beginaddr
= np
->n_value
;
t
->symvalue
.offset
= np
->n_value
;
* Check to see if a symbol corresponds to a object file name.
* For some reason these are listed as in the text segment.
private check_filename (name
)
if (i
>= 0 and mname
[i
] == '.' and mname
[i
+1] == 'o') {
while (mname
[i
] != '/' and i
>= 0) {
s
= insert(identname(&mname
[i
+1], true));
s
->language
= findlanguage(".s");
s
->symvalue
.funcv
.beginaddr
= 0;
if (curblock
->class != PROG
) {
if (curblock
->class != PROG
) {
* Check to see if a symbol is about to be defined within an unnamed block.
* If this happens, we create a procedure for the unnamed block, make it
* "inline" so that tracebacks don't associate an activation record with it,
* and enter it into the function table so that it will be detected
public chkUnnamedBlock ()
if (nesting
> 0 and addrstk
[nesting
] != NOADDR
) {
startaddr
= (linep
- 1)->addr
;
sprintf(buf
, "$b%d", bnum
);
s
= insert(identname(buf
, false));
s
->symvalue
.funcv
.src
= false;
s
->symvalue
.funcv
.inline = true;
s
->symvalue
.funcv
.beginaddr
= startaddr
;
addrstk
[nesting
] = NOADDR
;
* Compilation unit. C associates scope with filenames
* so we treat them as "modules". The filename without
* the suffix is used for the module name.
* Because there is no explicit "end-of-block" mark in
* the object file, we must exit blocks for the current
private enterSourceModule (n
, addr
)
mname
= strdup(ident(n
));
if (rindex(mname
, '/') != nil
) {
mname
= rindex(mname
, '/') + 1;
suffix
= rindex(mname
, '.');
curlang
= findlanguage(suffix
);
if (curlang
== findlanguage(".f")) {
if (not (*language_op(curlang
, L_HASMODULES
))()) {
if (curblock
->class != PROG
) {
if (curblock
->class != PROG
) {
nn
= identname(mname
, true);
if (curmodule
== nil
or curmodule
->name
!= nn
) {
s
->symvalue
.funcv
.beginaddr
= 0;
if (program
->language
== nil
) {
program
->language
= curlang
;
enterfile(ident(n
), addr
);
* Allocate file and line tables and initialize indices.
private allocmaps (nf
, nl
)
filetab
= newarr(Filetab
, nf
);
linetab
= newarr(Linetab
, nl
);
* Add a file to the file table.
* If the new address is the same as the previous file address
* this routine used to not enter the file, but this caused some
* problems so it has been removed. It's not clear that this in
* turn may not also cause a problem.
private enterfile (filename
, addr
)
filep
->filename
= filename
;
filep
->lineindex
= linep
- linetab
;
* Since we only estimated the number of lines (and it was a poor
* estimation) and since we need to know the exact number of lines
* to do a binary search, we set it when we're done.
nlhdr
.nlines
= linep
- linetab
;
* Similarly for nfiles ...
nlhdr
.nfiles
= filep
- filetab
;
setsource(filetab
[0].filename
);