1
0
Files
2022-09-29 17:59:04 +03:00

1367 lines
32 KiB
C

#ident "$Header: /proj/irix6.5.7m/isms/irix/cmd/icrash_old/lib/libutil/RCS/mload.c,v 1.1 1999/05/25 19:19:20 tjm Exp $"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stream.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <libelf.h>
#include <stdlib.h>
#include <string.h>
#include <filehdr.h>
#include "icrash.h"
#include "extern.h"
#define M_ADDR(symp) (PTRSZ64(K) ? (*(uint64*)symp) : (*(uint*)symp))
/* This is a generic name for symbols that are not found in a loadable
* module's symbol table. Since the functions that reference it (trace,
* dis, etc.) do not free it, we can use it freely whenever we are not
* able to locate an actual symbol name.
*/
char *mlinfoname = "<LOADABLE_MODULE>";
/*
* addr_to_mlinfo()
*
* Return a pointer to a block of memory containing the ml_info struct
* for a given virtual address (addr).
*
*/
k_ptr_t
addr_to_mlinfo(kaddr_t addr)
{
k_ptr_t mlp;
kaddr_t mlinfo, end, text;
mlp = alloc_block(ML_INFO_SIZE(K), B_TEMP);
mlinfo = K_MLINFOLIST(K);
while (mlinfo) {
kl_get_struct(K, mlinfo, ML_INFO_SIZE(K), mlp, "ml_info");
text = kl_kaddr(K, mlp, "ml_info", "ml_text");
end = kl_kaddr(K, mlp, "ml_info", "ml_end");
/* Check to see if addr falls inside this module's address
* space.
*/
if (text && ((addr >= text) && (addr <= end))) {
return(mlp);
}
else {
mlinfo = kl_kaddr(K, mlp, "ml_info", "ml_next");
}
}
free_block(mlp);
return((k_ptr_t)NULL);
}
/*
* ml_symname()
*
* Return the name of the symbol in symp. If strtab is NULL, use mlp,
* alloc space for the stringtab, and find the symbol name. Note that
* the symbol name returned is a dup of the one found in strtab. We have
* to do this because we don't know how long strtab will be staying around.
*/
char *
ml_symname(char *strtab, k_ptr_t symp, k_ptr_t mlp)
{
char *s, *name;
int strtab_alloced = 0;
if (!strtab) {
int strtabsz;
kaddr_t stringtab;
if (!mlp) {
/* Can't do anything here (XXX - need error code?)
*/
return((char *)NULL);
}
/* Get the stringtab pointer. We have to test for a vlaid
* stringtab pointer because there was a case when ml_nsyms
* was > 0 and stringtab was NULL.
*/
if (!(stringtab = kl_kaddr(K, mlp, "ml_info", "ml_stringtab"))) {
return((char *)NULL);
}
strtabsz = KL_INT(K, mlp, "ml_info", "ml_strtabsz");
strtab = (char*)alloc_block(strtabsz, B_TEMP);
kl_get_block(K, stringtab, strtabsz, strtab, "ml_sym");
strtab_alloced = 1;
}
if (PTRSZ64(K)) {
s = strtab + *(uint*)((uint)symp + 8);
}
else {
s = strtab + *(uint*)((uint)symp + 4);
}
/* We have to copy over the name to a temp block because the strtab
* that contains the name string is likely to be freed before the
* name can be used (it will be if it was alloced in this function).
*/
name = (char*)alloc_block(strlen(s) + 1, B_TEMP);
strcpy(name, s);
if (strtab_alloced) {
free_block((k_ptr_t)strtab);
}
return(name);
}
/*
* ml_findsym()
*
* Walk through the symbol table for a given loadable module and check
* to see if there is a match for a particular name or address. Note that
* with address, we will return a pointer to the closest record (equal to
* or less than). Also, we can't check for both addr and name, so name
* takes precedence (because it's possible for there to be an exact match).
*/
k_ptr_t
ml_findsym(kaddr_t addr, char *name, k_ptr_t mlp)
{
int i, nsyms, strtabsz;
char *s, *strtab;
kaddr_t stringtab, sym, lastsym = 0;
k_ptr_t symp;
/* Just in case...
*/
if (!mlp) {
return((k_ptr_t)NULL);
}
nsyms = KL_INT(K, mlp, "ml_info", "ml_nsyms");
if (nsyms == 0) {
return((k_ptr_t)NULL);
}
/* If we are doing a name search, we have to allocate space for
* the module string table.
*/
if (name) {
/* Get the stringtab pointer. We have to test for a vlaid
* stringtab pointer because there was a case when ml_nsyms
* was > 0 and stringtab was NULL.
*/
stringtab = kl_kaddr(K, mlp, "ml_info", "ml_stringtab");
if (!stringtab) {
return((k_ptr_t)NULL);
}
strtabsz = KL_INT(K, mlp, "ml_info", "ml_strtabsz");
if (!strtabsz) {
return((k_ptr_t)NULL);
}
strtab = (char*)alloc_block(strtabsz, B_TEMP);
kl_get_block(K, stringtab, strtabsz, strtab, "ml_sym");
}
sym = kl_kaddr(K, mlp, "ml_info", "ml_symtab");
symp = alloc_block(ML_SYM_SIZE(K), B_TEMP);
for (i = 0; i < nsyms; i++) {
kl_get_block(K, sym, ML_SYM_SIZE(K), symp, "ml_sym");
if (name) {
s = ml_symname(strtab, symp, (k_ptr_t)NULL);
if (!strcmp(name, s)) {
free_block((k_ptr_t)strtab);
free_block((k_ptr_t)s);
return(symp);
}
free_block((k_ptr_t)s);
}
else {
if (addr == M_ADDR(symp)) {
return(symp);
}
if (addr < M_ADDR(symp)) {
/* lastsym is really the entry we want. We have to load it
* back in and return it...unless addr falls before the
* first sym, in which case we return a NULL pointer.
*/
if (i) {
kl_get_block(K, lastsym, ML_SYM_SIZE(K), symp, "ml_sym");
return (symp);
}
else {
free_block(symp);
return((k_ptr_t)NULL);
}
}
lastsym = sym;
}
sym += ML_SYM_SIZE(K);
}
if (name) {
free_block((k_ptr_t)strtab);
}
free_block(symp);
return((k_ptr_t)NULL);
}
/*
* ml_addrtosym()
*
* Finds the symbol with the closest address (equal to or less than).
* Note that an exact match is not necessary. As such, there is no
* gaurantee that the symbol entry found is the correct one (it's up
* to the caller to verify this).
*/
k_ptr_t
ml_addrtosym(kaddr_t addr, k_ptr_t mlp)
{
int mlp_alloced = 0;
k_ptr_t symp;
/* If mlp is NULL, find out which module addr is from...
*/
if (!mlp) {
if (!(mlp = addr_to_mlinfo(addr))) {
return((k_ptr_t)NULL);
}
mlp_alloced = 1;
}
symp = ml_findsym(addr, (char *)NULL, mlp);
if (mlp_alloced) {
free_block(mlp);
}
return (symp);
}
/*
* ml_nmtosym() -- Finds a loadable module symbol that matches for name.
*/
k_ptr_t
ml_nmtosym(char *name, k_ptr_t mlp)
{
k_ptr_t symp;
symp = ml_findsym(0, name, mlp);
return (symp);
}
/*
* ml_findaddr()
*
* Return a pointer to a symaddr_t struct containing information for
* the loadable module that contains addr. With functions, addre
* must be >= lowpc and <= highpc (non-text symbols must be an exact
* match). If addr is greater than the first addr in the list AND
* no match is found, last will be loaded with the pointer to the
* struct where the new record (for addr) should be inserted (if there
* is a last pointer).
*/
symaddr_t *
ml_findaddr(kaddr_t addr, symaddr_t **last, int flag)
{
symaddr_t *lastsp = 0;
symaddr_t *sp;
/* Zero out the last pointer
*/
if (last) {
*last = (symaddr_t *)NULL;
}
sp = stp->st_ml_addr_ptr;
while (sp) {
if (addr < sp->s_lowpc) {
/* We've gone far enough, it's not here...
*/
break;
}
/* If the address is from a function, then sp will contain both
* lowpc and highpc values. Otherwise, only the lowpc vlaue will
* be set. With a non-function address, only a match of addr to
* lowpc will result in success.
*/
if ((addr <= sp->s_highpc) || (addr == sp->s_lowpc)) {
return(sp);
}
lastsp = sp;
sp = sp->s_next;
}
if (lastsp) {
if (last) {
*last = lastsp;
}
if (flag) {
return(lastsp);
}
}
return((symaddr_t *)NULL);
}
/*
* ml_findname()
*
* Return a pointer to a symaddr_t struct containing information for
* the loadable module symbol that matches name. If there is no match
* match).
*/
symaddr_t *
ml_findname(char *name)
{
symaddr_t *sp;
sp = stp->st_ml_addr_ptr;
while (sp) {
if (!strcmp(name, sp->s_name)) {
return(sp);
}
sp = sp->s_next;
}
return((symaddr_t *)NULL);
}
/*
* ml_insertaddr()
*
* Insert a record in the symbol table for a loadable module symbol/addr.
* If a last pointer is passed in, then we insert the new record at that
* point. Otherwise we have to search the list to find the insert point.
*/
symaddr_t *
ml_insertaddr(kaddr_t lowpc, kaddr_t highpc, char *name, symaddr_t *last)
{
char *s = 0;
symaddr_t *newsp;
/* Before we do anything, we have to see if we have been passed
* a pointer (last) to an insert point in the list. If we weren't
* then we have to walk the list and find it. Just in case, we
* will check to see if we found a record matching lowpc. If we
* do then we will return a pointer to the record instead.
*/
if (!last) {
if (newsp = ml_findaddr(lowpc, &last, 0)) {
return(newsp);
}
}
/* Allocate permanent space for the new entry
*/
newsp = (symaddr_t *)alloc_block(sizeof(symaddr_t), B_PERM);
newsp->s_lowpc = lowpc;
newsp->s_highpc = highpc;
/* Check to see if there is a name string. If there isn't, we need
* to get it from the symbol table in the ml_info struct. If there is,
* we need to check to see if it is the generic mlinfoname. If
* it is, then we don't have to dup it...
*/
if (!name) {
k_ptr_t mlp, symp;
/* Just in case, check to make sure lowpc is from a module.
*/
if (!(mlp = addr_to_mlinfo(lowpc))) {
return((symaddr_t *)NULL);
}
if (symp = ml_addrtosym(lowpc, mlp)) {
/* Make sure the symbol address and the lowpc match
*/
if (lowpc == M_ADDR(symp)) {
s = ml_symname((char*)NULL, symp, mlp);
}
if (s) {
newsp->s_name = strdup(s);
free_block((k_ptr_t)s);
}
else {
newsp->s_name = mlinfoname;
}
free_block(symp);
}
else {
newsp->s_name = mlinfoname;
}
free_block(mlp);
}
else if (name == mlinfoname) {
newsp->s_name = mlinfoname;
}
else {
newsp->s_name = strdup(name);
}
/* Insert the new record after sp if the new record goes anyware
* but the front of the list.
*/
if (last) {
newsp->s_next = last->s_next;
last->s_next = newsp;
}
else if (stp->st_ml_addr_ptr) {
newsp->s_next = stp->st_ml_addr_ptr;
stp->st_ml_addr_ptr = newsp;
}
else {
stp->st_ml_addr_ptr = newsp;
}
stp->st_ml_addr_cnt++;
return(newsp);
}
/*
* ml_addrtonm()
*
*/
char *
ml_addrtonm(kaddr_t addr)
{
int i, strtabsz;
char *s, *strtab;
kaddr_t stringtab;
k_ptr_t symp, mlp;
kaddr_t start, end;
symaddr_t *sp, *lastsp, *newsp;
/* If addr is already on the list, we don't have to go any
* furthur, just return the name.
*/
if (sp = ml_findaddr(addr, &lastsp, 0)) {
return(sp->s_name);
}
/* Find out which module addr is from...
*/
if (!(mlp = addr_to_mlinfo(addr))) {
return((char*)NULL);
}
/* Treat addr as an instruction and try and get the start address
* of the function. If there isn't a start address, try and find
* a sym address...
*/
start = ml_funcaddr(addr);
if (!start) {
free_block(mlp);
/* Check and see if there is a (non-text) symbol that
* matches this addr. Since we don't have any way to
* determine if the next symbol is REALLY the next symbol,
* we only determine success if there is an exact match.
*/
if (start = ml_symaddr(addr)) {
/* This is the closest symbol. Add it to the list. If
* (addr == start) then return the symbol's name.
*/
sp = ml_insertaddr(start, 0, (char *)NULL, lastsp);
if (addr == start) {
return(sp->s_name);
}
}
return((char *)NULL);
}
/* Now try for an end address. If we get an end address, make
* sure addr falls between it and the start address. Because we
* are doing this process via brute force, we may walk back to
* the start of the last function and then get ITS function end.
* If the address falls beyond that addresss, then addr is not
* from a function.
*/
end = ml_funcend(start);
if (addr > end) {
end = 0;
}
if (!end) {
free_block(mlp);
/* This isn't a function. All we need to do is check to see
* if this is a symbol address, log the record, and return
* the name.
*/
if (start = ml_symaddr(addr)) {
if (addr == start) {
/* Add this symbol to the list and return its name...
*/
sp = ml_insertaddr(start, 0, (char *)NULL, lastsp);
return(sp->s_name);
}
}
return((char *)NULL);
}
/* We now know that addr is from a function and that the function
* is NOT on the list. We need to determine the name of the function,
* add the function to the list, and return the function name.
*/
if (KL_INT(K, mlp, "ml_info", "ml_nsyms") == 0) {
ml_insertaddr(start, end, mlinfoname, lastsp);
free_block(mlp);
return((char *)NULL);
}
/* Get the stringtab pointer. We have to test for a vlaid
* stringtab pointer because there was a case when ml_nsyms
* was > 0 and stringtab was NULL.
*/
stringtab = kl_kaddr(K, mlp, "ml_info", "ml_stringtab");
strtabsz = KL_INT(K, mlp, "ml_info", "ml_strtabsz");
if (!stringtab || (strtabsz == 0)) {
free_block(mlp);
return((char *)NULL);
}
strtab = (char*)alloc_block(strtabsz, B_TEMP);
kl_get_block(K, stringtab, strtabsz, strtab, "ml_sym");
if (symp = ml_addrtosym(addr, mlp)) {
if (start == M_ADDR(symp)) {
s = ml_symname(strtab, symp, (k_ptr_t)NULL);
/* Add the entry to the list and then return the name...
*/
newsp = ml_insertaddr(start, end, s, lastsp);
free_block((k_ptr_t)s);
free_block((k_ptr_t)strtab);
free_block(mlp);
free_block(symp);
return(newsp->s_name);
}
free_block(symp);
}
ml_insertaddr(start, end, mlinfoname, lastsp);
free_block(mlp);
free_block((k_ptr_t)strtab);
return(mlinfoname);
}
/*
* ml_nmtoaddr() -- Return the address of the loadable module symbol 'name'
*/
kaddr_t
ml_nmtoaddr(char *name)
{
k_ptr_t mlp, symp;
kaddr_t addr, mlinfo, start, end;
symaddr_t *sp;
/* Check to see if we already have an entry that matches for name
*/
if (sp = ml_findname(name)) {
return(sp->s_lowpc);
}
mlp = alloc_block(ML_INFO_SIZE(K), B_TEMP);
mlinfo = K_MLINFOLIST(K);
while (mlinfo) {
kl_get_struct(K, mlinfo, ML_INFO_SIZE(K), mlp, "ml_info");
/* Make sure there is address space associated with this
* module. There is a case with 32-bit systems where base,
* text and end are zero, but there are a TON of symbols. The
* symbols are the KERNELS symbols. Since we already have these,
* there is no need to look through this list...
*/
if (!kl_kaddr(K, mlp, "ml_info", "ml_text")) {
mlinfo = kl_kaddr(K, mlp, "ml_info", "ml_next");
continue;
}
if (symp = ml_nmtosym(name, mlp)) {
addr = M_ADDR(symp);
if (!ml_funcaddr(addr)) {
ml_insertaddr(addr, 0, name, (symaddr_t*)NULL);
}
free_block(mlp);
free_block(symp);
return(addr);
}
mlinfo = kl_kaddr(K, mlp, "ml_info", "ml_next");
}
free_block(mlp);
return((kaddr_t)NULL);
}
/*
* is_mload() -- is addr from a loadable module?
*/
int
is_mload(kaddr_t addr)
{
k_ptr_t mlp;
if (mlp = addr_to_mlinfo(addr)) {
/* If there was success, we have to free the block here
* or it will get lost.
*/
free_block(mlp);
return(1);
}
return(0);
}
/*
* ml_symaddr()
*
* Check to see if addr is from a loadable module address space. If it
* is, then see if it matches with an entry in the module's symbol table.
* Note that this operation is VERY crude. Only the start address of a
* symbol and an offset into the name space is contained in a symbol table
* entry. It isn't even clear if the symbol is for a function, variable, or
* whatever.
*/
kaddr_t
ml_symaddr(kaddr_t addr)
{
int i, nsyms;
kaddr_t sym, cur_addr, last_addr = 0;
k_ptr_t mlp, symp;
/* Check to see if addr is from a loadable module.
*/
if (!(mlp = addr_to_mlinfo(addr))) {
return((kaddr_t)NULL);
}
symp = alloc_block(ML_SYM_SIZE(K), B_TEMP);
sym = kl_kaddr(K, mlp, "ml_info", "ml_symtab");
nsyms = KL_INT(K, mlp, "ml_info", "ml_nsyms");
for (i = 0; i < nsyms; i++) {
kl_get_block(K, sym, ML_SYM_SIZE(K), symp, "ml_sym");
cur_addr = M_ADDR(symp);
if (addr < cur_addr) {
break;
}
last_addr = cur_addr;
sym += ML_SYM_SIZE(K);
}
free_block(mlp);
free_block(symp);
return (last_addr);
}
/*
* ml_funcname()
*
*/
char *
ml_funcname(kaddr_t addr)
{
char *name;
symaddr_t *sp;
/* Check to see if addr is from a function...
*/
if (ml_funcaddr(addr)) {
if (name = ml_addrtonm(addr)) {
return(name);
}
}
return((char *)NULL);
}
/*
* ml_funcaddr()
*
* walk back through the code to find the first instruction of a function.
* This is really a hack! It's something we have to do because little if
* any information is stored in the loadable module symbol table. We
* consider the instruction where the stack pointer gets decremented to
* be the first instruction of the function (even though, in some cases,
* it isn't). That is if there is no symbol table entry. If there is
* a symbol table entry, we use the address of the symbol as the start
* address.
*/
kaddr_t
ml_funcaddr(kaddr_t addr)
{
int instr, instr_cnt;
int i, off, size;
char *name, *s;
k_ptr_t symp, mlp, blk, cur;
kaddr_t start_addr, blk_addr, cur_addr, sym_addr, sym_end, end;
kaddr_t ml_text;
symaddr_t *sp, *lastsp;
/* Check to see if we already have an address record that matches
* for addr.
*/
if (sp = ml_findaddr(addr, &lastsp, 0)) {
/* Make sure this is a function
*/
if (sp->s_highpc) {
return(sp->s_lowpc);
}
else {
return((kaddr_t)NULL);
}
}
/* We didn't find it, so get the ml_info struct this addr is from.
*/
if (!(mlp = addr_to_mlinfo(addr))) {
return((kaddr_t)NULL);
}
/* Get the start of the module's text segment...
*/
ml_text = kl_kaddr(K, mlp, "ml_info", "ml_text");
free_block(mlp);
/* Make sure addr is aligned properly (should we just return?)
*/
if (addr % 4) {
start_addr = addr & (~3);
}
else {
start_addr = addr;
}
blk_addr = start_addr - 4096 + 4;
if (blk_addr < ml_text) {
blk_addr = ml_text;
}
size = start_addr - blk_addr + 4;
instr_cnt = size / 4;
blk = alloc_block(4096, B_TEMP);
while (start_addr >= ml_text) {
cur = (k_ptr_t)((unsigned)blk + (size - 4));
cur_addr = start_addr;
kl_get_block(K, blk_addr, size, blk, "instr");
for (i = 0; i < instr_cnt; i++, cur_addr -= 4) {
off = 0;
instr = *((int*)cur);
if (PTRSZ64(K)) {
int op;
if (op = (instr & 0xfc000000) >> 26) {
if ((op == 25) && (((instr & 0x3e00000) >> 21) == 29) &&
(((instr & 0x1f0000) >> 16) == 29)) {
off = (short)(instr & 0xffff);
}
}
}
else {
if ((instr & 0xffff0000) == 0x27bd0000) {
off = (short)(instr & 0xffff);
}
}
/* Check to see if the offset is less than zero. If
* it is then it means we are at the start of a new
* function (or block of text?).
*/
if (off < 0) {
free_block(blk);
/* Get the start address of the closest symbol. We will
* compare it with the start address we arrived at to see
* if there is a match...
*/
sym_addr = ml_symaddr(addr);
if (!sym_addr) {
/* If there is no matching symbol, we check to make
* sure the address falls within the function starting
* at cur_addr.
*/
end = ml_funcend(cur_addr);
if (addr > end) {
return((kaddr_t)NULL);
}
else {
ml_insertaddr(cur_addr, end, mlinfoname, lastsp);
return(cur_addr);
}
}
sym_end = ml_funcend(sym_addr);
/* If there is a gap between the symbol address and the
* instruction that decrements the SP, AND addr falls
* between the two, cur_add will be from the previous
* function. If the symbol found is not a function,
* return NULL.
*/
if (cur_addr < sym_addr) {
if (sym_end) {
ml_insertaddr(sym_addr, sym_end, (char *)NULL, lastsp);
return(sym_addr);
}
return((kaddr_t)NULL);
}
/* Now, we have to see if addr falls within the function
* found by ml_symaddr(). It's possible that there is a
* gap in the symbol table (we can count on it!). It's also
* possible that the addr falls beyond the end of the last
* function. In that case, just return NULL.
*/
if (addr > sym_end) {
/* Check and see if cur_addr is a start of a function
*/
end = ml_funcend(cur_addr);
if (addr <= end) {
ml_insertaddr(cur_addr, end, (char *)NULL, lastsp);
return(cur_addr);
}
return((kaddr_t)NULL);
}
ml_insertaddr(sym_addr, sym_end, (char *)NULL, lastsp);
return(sym_addr);
}
cur = (k_ptr_t)((unsigned)cur - 4);
}
/* There's a special case that exists when the first symbol
* has the same address as ml_text and the first instruction is
* not the one where SP is decremented. If we don't handle it
* here, we will just loop forever...
*/
if (cur_addr < ml_text) {
kaddr_t taddr;
cur_addr = addr;
sym_addr = ml_symaddr(cur_addr);
sym_end = ml_funcend(sym_addr);
/* We don't know if sym_end is really the end of the function
* that starts at sym_addr. We need to walk back, symbol
* by symbol, until we have the real symbol end (at least
* based on what's in the symbol table).
*/
taddr = ml_symaddr(sym_end);
while (taddr > sym_addr) {
sym_end = taddr - 4;
taddr = ml_symaddr(sym_end);
}
if ((addr >= sym_addr) && (addr <= sym_end)) {
free_block(blk);
ml_insertaddr(sym_addr, sym_end, (char *)NULL, lastsp);
return(sym_addr);
}
else {
break;
}
}
start_addr = blk_addr;
blk_addr = start_addr - 4096 + 4;
if (blk_addr < ml_text) {
blk_addr = ml_text;
}
size = start_addr - blk_addr + 4;
instr_cnt = size / 4;
}
free_block(blk);
return((kaddr_t)NULL);
}
/*
* ml_funcend()
*
* Determine the end address for a function starting at addr (we have
* to have faith that addr is in deed a function start address).
*
* This is an mlinfo internal function.
*/
kaddr_t
ml_funcend(kaddr_t addr)
{
int cnt = 0, instr, instr_cnt;
int i, off, size, func_size;
k_ptr_t mlp;
k_ptr_t blk, cur;
kaddr_t end_addr, cur_addr, blk_addr, tmp_addr = 0;
kaddr_t ml_end;
symaddr_t *sp, *lastsp;
/* Check to see if we already have an address record that matches
* for addr.
*/
if (sp = ml_findaddr(addr, &lastsp, 0)) {
return(sp->s_highpc);
}
/* Make sure addr is from a loadable module...
*/
if (!(mlp = addr_to_mlinfo(addr))) {
return((kaddr_t)NULL);
}
/* Get the end of the text segment. We have to make sure
* that it is aligned properly (it isn't always).
*/
ml_end = kl_kaddr(K, mlp, "ml_info", "ml_end");
free_block(mlp);
if (ml_end % 3) {
ml_end = ml_end & (~3);
}
/* We have to walk past the instruction that decrements the SP (Note
* that this may not be the first instruction of the function).
*/
off = 0;
blk_addr = addr;
do {
kl_get_block(K, blk_addr, 4, (char*)&instr, "instr");
if (PTRSZ64(K)) {
int op;
if (op = (instr & 0xfc000000) >> 26) {
if ((op == 25) && (((instr & 0x3e00000) >> 21) == 29) &&
(((instr & 0x1f0000) >> 16) == 29)) {
off = (short)(instr & 0xffff);
}
}
}
else {
if ((instr & 0xffff0000) == 0x27bd0000) {
off = (short)(instr & 0xffff);
}
}
/* We can expect to find the instruction that decrements the SP
* fairly soon in the function. If we don't find it in a reasonible
* number of searches, we just bail...
*/
cnt++;
if (cnt == 25) {
return((kaddr_t)NULL);
}
/* Step over the current instr in any event
*/
blk_addr += 4;
if (off < 0) {
break;
}
} while (blk_addr < ml_end);
if ((blk_addr + 4096) > ml_end) {
size = (ml_end - blk_addr);
}
else {
size = 4096;
}
instr_cnt = size / 4;
blk = alloc_block(4096, B_TEMP);
while (blk_addr <= ml_end) {
kl_get_block(K, blk_addr, size, blk, "instr");
cur_addr = blk_addr;
cur = blk;
for (i = 0; i < instr_cnt; i++, cur_addr += 4) {
off = 0;
instr = *((int*)cur);
if (PTRSZ64(K)) {
int op;
if (op = (instr & 0xfc000000) >> 26) {
if ((op == 25) && (((instr & 0x3e00000) >> 21) == 29) &&
(((instr & 0x1f0000) >> 16) == 29)) {
off = (short)(instr & 0xffff);
}
}
}
else {
if ((instr & 0xffff0000) == 0x27bd0000) {
off = (short)(instr & 0xffff);
}
}
/* Check to see if the offset is less than zero. If
* it is then we have reached the start of the next
* function. We just back up one and figure that as
* the end of the function.
*
* There is a problem when the start address of a
* function comes before the instr where the SP is
* incremented. In effect, this puts our end address
* within the next function!
*/
if (off < 0) {
kaddr_t sym_addr;
end_addr = cur_addr - 4;
sym_addr = ml_symaddr(end_addr);
if (sym_addr > addr) {
end_addr = sym_addr - 4;
}
free_block(blk);
return(end_addr);
}
else if (off > 0) {
/* We have to capture this in the event that this is the
* last function in the module address space. In that
* instance, there won't be a next function's decrementing
* of the SP.
*/
tmp_addr = cur_addr;
}
cur = (k_ptr_t)((unsigned)cur + 4);
}
if (size == 4096) {
blk_addr += 4096;
}
else {
/* We've finished walking the code for this loadable module
*/
break;
}
if ((blk_addr + 4096) > ml_end) {
size = (ml_end - blk_addr);
}
else {
size = 4096;
}
instr_cnt = size / 4;
}
free_block(blk);
return(tmp_addr);
}
/*
* ml_funcsize()
*/
int
ml_funcsize(kaddr_t addr)
{
int func_size;
kaddr_t func_addr, func_end;
kaddr_t ml_end;
/* Get the start address of a function..
*/
func_addr = ml_funcaddr(addr);
if (func_addr == (kaddr_t)NULL) {
return((kaddr_t)NULL);
}
func_end = ml_funcend(func_addr);
if (func_end == (kaddr_t)NULL) {
return((kaddr_t)NULL);
}
func_size = (func_end - func_addr) + 4;
return(func_size);
}
#ifdef NOT
XXX : This is old stuff that may still be useful. We're going to keep
it around for a while...
#define CHECK_MLINFOLIST() \
if (ACTIVE(K)) {\
} \
else { \
if (!K_MLINFOLIST(K)) { \
if (DEBUG(DC_GLOBAL, 1)) { \
fprintf(stderr, "No modules loaded.\n"); \
} \
return((k_ptr_t)NULL); \
} \
}
/*
* print_minfo()
*/
print_minfo(i_ml_info_t *ml, int flags, FILE *ofp)
{
int i;
if (DEBUG(DC_GLOBAL, 3)) {
fprintf(stderr, "ml=0x%x\n", ml);
}
fprintf(ofp, "%4d %15s %8x %5x %6d\n",
ml->desc.m_id, ml->desc.m_prefix, ml->mp.ml_text,
ml->desc.m_flags, ml->desc.m_refcnt);
if (flags & DO_FULL) {
cfg_driver_t *drv = (cfg_driver_t *)NULL;
if (ml->desc.m_type == M_DRIVER) {
drv = (cfg_driver_t *)alloc_block(sizeof(cfg_driver_t), B_TEMP);
if (!get_block(sizeof(cfg_driver_t), ml->desc.m_data,
drv, "cfg_driver_t")) {
free_block(drv);
return;
}
fprintf(ofp, "\n");
fprintf(ofp, " DRIVER INFORMATION\n");
fprintf(ofp, " ------------------\n");
for (i = 0; i< drv->d.d_nmajors; i++) {
fprintf(ofp, " MAJOR: %3d -- ", drv->d.d_majors[i]);
if (drv->d_typ == (MDRV_CHAR|MDRV_BLOCK)) {
fprintf (ofp, "b/cdevsw[%d]\n", drv->d_dev);
}
else if (drv->d_typ == MDRV_CHAR) {
fprintf (ofp, "cdevsw[%d]\n", drv->d_dev);
}
else if (drv->d_typ == MDRV_BLOCK) {
fprintf (ofp, "bdevsw[%d]\n", drv->d_dev);
}
else if (drv->d_typ == MDRV_STREAM) {
fprintf (ofp, "cdevsw[%d])\n", drv->d_dev);
fprintf (ofp, " open 0x%x, unload 0x%x\n",
drv->d_ropen, drv->d_unload);
}
else if (ml->desc.m_type == M_FILESYS) {
fprintf (ofp, " Illegal module type: filesys\n");
}
else if (ml->desc.m_type == M_STREAMS) {
cfg_streams_t *str;
str = (cfg_streams_t *)
alloc_block(sizeof(cfg_streams_t), B_TEMP);
get_block(ml->desc.m_data, sizeof(cfg_streams_t),
str, "cfg_streams_t");;
fprintf(ofp, "\n");
fprintf(ofp, " STREAMS MODULE INFO\n");
fprintf(ofp, " -------------------\n");
fprintf(ofp, " fmodsw entry %d\n", str->s_fmod);
fprintf(ofp, " open 0x%x, unload 0x%x, close 0x%x, "
"info 0x%x\n", str->s_ropen, str->s_unload,
str->s_rclose, str->s_info);
}
else if (ml->desc.m_type == M_OTHER) {
fprintf (ofp, " Illegal module type: other\n");
}
}
}
if (drv) {
free_block(drv);
}
fprintf(ofp, "\n");
}
return;
}
/*
* domlist()
*/
domlist(command_t cmd)
{
int i, mode, firsttime = 1, module_cnt = 0;
unsigned value;
i_ml_info_t *ml;
CHECK_MLINFOLIST();
fprintf(cmd.ofp, " ID PREFIX TEXT FLAGS REFCNT\n");
fprintf(cmd.ofp, "============================================================================\n");
ml = mlinfo;
for (i = 0; i < cmd.nargs; i++) {
value = get_value(cmd.args[i], &mode, 0);
if (mode == 0) {
mode = 1;
}
while (ml) {
if ((mode == 2) && ((unsigned)ml->m != value)) {
ml = ml->next;
continue;
}
if ((mode == 2) || (value == ml->desc.m_id)) {
if (DEBUG(DC_GLOBAL, 1) || (cmd.flags & DO_FULL)) {
if (!firsttime) {
fprintf(cmd.ofp, " ID PREFIX TEXT FLAGS REFCNT\n");
fprintf(cmd.ofp, "============================================================================\n");
}
else {
firsttime = 0;
}
}
module_cnt++;
print_minfo(ml, cmd.flags, cmd.ofp);
break;
}
ml = ml->next;
}
}
if (!cmd.nargs) {
while (ml) {
if (DEBUG(DC_GLOBAL, 1) || (cmd.flags & DO_FULL)) {
if (!firsttime) {
fprintf(cmd.ofp, " ID PREFIX TEXT FLAGS REFCNT\n");
fprintf(cmd.ofp, "============================================================================\n");
}
else {
firsttime = 0;
}
}
module_cnt++;
print_minfo(ml, cmd.flags, cmd.ofp);
ml = ml->next;
}
}
fprintf(cmd.ofp, "============================================================================\n");
fprintf(cmd.ofp, "%d module%s found\n",
module_cnt, (module_cnt != 1) ? "s" : "");
}
/*
* dominfo()
*/
dominfo(command_t cmd)
{
int i, mode, module_cnt = 0;
unsigned value;
i_ml_info_t *ml;
CHECK_MLINFOLIST();
fprintf(cmd.ofp, " ML_INFO OBJ SYMTAB NSYMS STRINGTAB DESC TEXT END\n");
fprintf(cmd.ofp, "============================================================================\n");
for (i = 0; i < cmd.nargs; i++) {
value = get_value(cmd.args[i], &mode, 0);
if (mode == 0) {
mode = 1;
}
if (!(ml = get_ml_info(value, mode))) {
continue;
}
module_cnt++;
print_ml_info(ml, cmd.flags, cmd.ofp);
}
if (!cmd.nargs) {
ml = mlinfo;
while (ml) {
module_cnt++;
print_ml_info(ml, cmd.flags, cmd.ofp);
ml = ml->next;
}
}
fprintf(cmd.ofp, "============================================================================\n");
fprintf(cmd.ofp, "%d module%s found\n",
module_cnt, (module_cnt != 1) ? "s" : "");
}
#define STRSZ 128
/*
* domlkup()
*/
domlkup(command_t cmd)
{
int i, j;
SYMR *sym;
i_ml_info_t *ml;
char *str;
CHECK_MLINFOLIST();
fprintf(cmd.ofp, " NAME VALUE TYPE CLASS\n");
fprintf(cmd.ofp, "===========================================\n");
for (i = 0; i < cmd.nargs; i++) {
ml = mlinfo;
while (ml) {
if (sym = ml_find_by_name(cmd.args[i], ml)) {
str = ml->stringtab + sym->iss;
print_ml_sym(sym, str, cmd.ofp);
break;
}
ml = ml->next;
}
}
fprintf(cmd.ofp, "===========================================\n");
}
/*
* domaddr() -- Print information for symbol containing addr
*/
int
domaddr(command_t cmd)
{
int i, j;
unsigned addr;
SYMR *sym;
i_ml_info_t *ml;
char *str;
CHECK_MLINFOLIST();
fprintf(cmd.ofp, " NAME VALUE TYPE CLASS\n");
fprintf(cmd.ofp, "===========================================\n");
for (i = 0; i < cmd.nargs; i++) {
addr = GET_VALUE(cmd.args[i]);
if (!(ml = get_ml_info(addr, 3))) {
continue;
}
if (sym = ml_find_by_addr(addr, ml)) {
str = ml->stringtab + sym->iss;
print_ml_sym(sym, str, cmd.ofp);
}
}
fprintf(cmd.ofp, "===========================================\n");
}
/*
* domsym() -- Print symbol list for loadable module
*/
int
domsym(command_t cmd)
{
int i, j, mode;
unsigned value;
SYMR *sym;
i_ml_info_t *ml;
char *str;
CHECK_MLINFOLIST();
for (i = 0; i < cmd.nargs; i++) {
value = get_value(cmd.args[i], &mode, 0);
if (mode == 0) {
mode = 1;
}
if (mode == 1) {
fprintf(cmd.ofp, "SYMBOLS FOR MODULE ID: %d\n\n", value);
}
else {
fprintf(cmd.ofp, "SYMBOLS FOR MODULE : 0x%x\n\n", value);
}
fprintf(cmd.ofp, " NAME VALUE TYPE CLASS\n");
fprintf(cmd.ofp, "===========================================\n");
if (!(ml = get_ml_info(value, mode))) {
continue;
}
sym = ml->symtab;
for (j = 0; j < ml->mp.ml_nsyms; j++, sym++) {
str = ml->stringtab + sym->iss;
print_ml_sym(sym, str, cmd.ofp);
}
fprintf(cmd.ofp, "===========================================\n");
fprintf(cmd.ofp, "\n");
}
}
#endif