fixmdebug.c 8.22 KB
/*==============================================================================
	fixmdebug.c
	$Revision: 1.1.1.1 $
	$Date: 2002/05/02 03:29:20 $

	Updates addresses of external symbols (and the corresponding
	stuff in local syms).

	Avoids updating things with a 0 value. Or an external addres
	of 1 (!).
==============================================================================*/
#include <sgidefs.h> /* for types to use. */
#include <stdio.h>
#include <syms.h>  /* symtab data */

#include "global.h"
#include "mdebug.h"
#include "update.h"

typedef __psunsigned_t psunsigned;

static pHDRR     phdr;
static char     *low_address;
static char     *high_address;
static psunsigned mdbg_fileaddr;
static psunsigned mdbg_move;

static psunsigned length;

static int update_fdrs(void);
static void update_externs(void);
static int update_procedures(psunsigned initial_proc,psunsigned fdrnum,psunsigned maxproc);
static int update_local_syms(psunsigned initial_sym,psunsigned fdrnum,psunsigned maxsym);

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void fixmdebug(void* mdbg,psunsigned len,psunsigned fileaddr)
{
    phdr = (pHDRR) mdbg;
    low_address = (char *)mdbg;
    length = len;
    high_address = (void *)((char *)mdbg + len);
    mdbg_fileaddr = fileaddr;

    if(len < sizeof(HDRR)) {
	error("mdebug section %ld bytes is too small!",(long)len,0,0);
    } else if(phdr->magic != magicSym) {
	error("mdebug magic 0x%x is wrong! want 0x%x",phdr->magic,magicSym,0);
    } else {
	bin.line_post_process_offset = phdr->cbLineOffset;
	bin.line_post_process_size = phdr->cbLine;
	if(update_fdrs() == 0) {
	    update_externs();
	}
    }
    if (status.mdebug_wrong && option.verbose){
	warning("mdebug has incorrect procedure info");
    }
    return;
}

/*------------------------------------------------------------------------------
	update fdrs, pdrs, local syms as appropriate.
	return 0 if no errors.
	Else return non-zero.
------------------------------------------------------------------------------*/
static int update_fdrs(void)
{
    pFDR cur_fdr;
    pFDR high_fdr;
    psunsigned fdrnum = 0;
    static last_ipd = 0;
    static ipdFirstMSBits = 0;

    cur_fdr = (pFDR) (((psunsigned)phdr->cbFdOffset - 
        (psunsigned)mdbg_fileaddr) + (psunsigned)low_address);

    high_fdr = cur_fdr + phdr->ifdMax;
    if((char *)cur_fdr < (char *)low_address) {
	error("mdebug fdrs not in memory? %p %p",
	    (char *)cur_fdr,(char *)low_address,0);
	return 1;
    }
    if((char *)high_fdr > (char *)high_address) {
	error("mdebug fdrs not in memory? %p %p",
	    (char *)high_fdr,(char *)high_address,0);
	return 1;
    }

    for( ; cur_fdr < high_fdr;++fdrnum, ++cur_fdr)
    {
	int	first_p;

	first_p = BIG_PROCEDURE_IPDFIRST(cur_fdr);

	/* handles the 16 bit ipd overflow when -B not set */
	if (option.big_procedure_list == FALSE)
	{
	    if(cur_fdr->cpd && (last_ipd > first_p)
	        && cur_fdr->ipdFirstMSBits == 0)
	    {
		ipdFirstMSBits += 0x10000;
	    }
	    last_ipd = first_p;
	    first_p  += ipdFirstMSBits;
	}

	if (update_procedures(first_p, fdrnum,
	    BIG_PROCEDURE_CPD(cur_fdr), cur_fdr->adr))
	{
	    return 1;
	}

	if (update_local_syms(cur_fdr->isymBase,fdrnum,cur_fdr->csym))
	{
	    if ( option.debug ) 
		    printf( "update_local_syms fail\n");
	    return 1;
	}

	cur_fdr->adr = 0;	/* set it to zero so that other tools will look
					   at pdr->adr as address, not offset */
    }

    return 0;
}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
static int
update_procedures(psunsigned initial_proc,psunsigned fdrnum,psunsigned maxproc,unsigned fdr_adr)
{
    pPDR cur_pdr;
    pPDR high_pdr; /* points past end */

    cur_pdr = (pPDR) (((psunsigned)phdr->cbPdOffset - (psunsigned)mdbg_fileaddr) + (psunsigned)low_address + (initial_proc*
        sizeof(PDR)));

    high_pdr = cur_pdr + maxproc;

    if((char *)cur_pdr < (char *)low_address) {
	error("mdebug pdr not in memory? %p %p ifd %d",
	    (char *)cur_pdr,(char *)low_address,fdrnum);
	return 1;
    }
    if((char *)high_pdr > (char *)high_address) {
	error("mdebug pdr not in memory? %p %p",
	    (char *)high_pdr,(char *)high_address,fdrnum);
	return 1;
    }

    if (bin.type != PIC && fdr_adr == cur_pdr->adr)
	fdr_adr = 0;

    for( ; cur_pdr < high_pdr; ++cur_pdr) {
	unsigned	adr;

	if (option.debug)
	    dump("cur_pdr->adr = %#x", cur_pdr->adr);
	if ( bin.type == PIC){
	    /* for PIC, pdr->adr is address */
	    adr = cur_pdr->adr;
	} else{
	    /* for CPIC and non_shared pdr->adr is offset from fdr->adr */
	    adr = cur_pdr->adr + fdr_adr;
	}
	if(cur_pdr->isym == isymNil)
	    continue; /* not a real entry: a dummy */
	if(IN_TEXT(adr)){
	    cur_pdr->adr = NEW_ADDR(adr);
	    if ( option.debug )
		    printf( "update_procedures: new addr %#x\n", adr);

		
	} else{
	    if (option.debug)
		warning("incorrect info in mdebug fdr->adr %#x, pdr->adr %#x",
		    fdr_adr, cur_pdr->adr);
	    status.mdebug_wrong = TRUE;

	}
    }
    return 0;

}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
static int
update_local_syms(psunsigned initial_sym,psunsigned fdrnum,psunsigned maxsym)
{
    pSYMR cur_symr;
    pSYMR high_symr; /* points past end */

    cur_symr = (pSYMR) (((psunsigned)phdr->cbSymOffset - (psunsigned)mdbg_fileaddr) + (psunsigned)low_address + (initial_sym*
        sizeof(SYMR)));

    high_symr = cur_symr + maxsym;

    if((char *)cur_symr < (char *)low_address) {
	error("mdebug symr not in memory? %p %p ifd %d",
	    (char *)cur_symr,(char *)low_address,fdrnum);
	return 1;
    }
    if((char *)high_symr > (char *)high_address) {
	error("mdebug symr not in memory? %p %p",
	    (char *)high_symr,(char *)high_address,fdrnum);
	return 1;
    }

    for( ; cur_symr < high_symr; ++cur_symr) {
	switch(cur_symr->st) {
	case stNil:
	case stStatic:
	case stLabel:
	case stProc:
	case stStaticProc:
	case stMemberProc:
	    if(cur_symr->value == 0)
		continue;
	    if ( option.debug ) {
		    printf( "bin.text_lo 0x%x.text_hi 0x%x \n", bin.text_lo , bin.text_hi );
		    printf( "cur_symr->value 0x%x \n", cur_symr->value);
		}

	    if (get_proc_by_addr(cur_symr->value)) {
		cur_symr->value = NEW_ADDR(cur_symr->value);
	    if ( option.debug ) 
		    printf( "new addr 0x%x\n", cur_symr->value);
	    }

	    /*
	stFile?
*/

	}
    }
    return 0;
}

/*------------------------------------------------------------------------------
	Update external symbols.
------------------------------------------------------------------------------*/
static void update_externs(void)
{

    pEXTR cur_extr;


    pEXTR high_extr; /* points past end */
    if ( option.debug ) 
	    printf( "update_externs\n");

    cur_extr = (pEXTR) (((psunsigned)phdr->cbExtOffset - (psunsigned)mdbg_fileaddr) + (psunsigned)low_address);

    high_extr = cur_extr + phdr->iextMax;

    if((char *)cur_extr < (char *)low_address) {
	error("mdebug externals not in memory? %p %p",(char *)cur_extr,(char *)low_address,0);
	return;
    }
    if((char *)high_extr > (char *)high_address) {
	error("mdebug Externals not in memory? %p %p",(char *)high_extr,(char *)high_address,0);
	return;
    }

    for(  ; cur_extr < high_extr; ++cur_extr) {
	if(cur_extr->asym.value == 0 || cur_extr->asym.value == 1) {
	    continue;
	}
	if (get_proc_by_addr(cur_extr->asym.value)) {
	    cur_extr->asym.value = NEW_ADDR(cur_extr->asym.value);
	    if ( option.debug ) 
		printf("cur_extr->asym.value 0x%x\n", cur_extr->asym.value);
	}
    }
}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void update_mdebug(Elf *elf)
{
    Elf_Scn         *section;
    Elf32_Shdr      *shdr;
    Elf_Data        *data;
    int i;

    section = find_section_by_name(elf, ".mdebug");
    shdr = elf32_getshdr(section);
    if ( option.debug )
	    printf( "update_mdebug: section 0x%x \n", section);
    if (section == NULL){
        return;
    }
    data = elf_getdata(section, 0);
    fixmdebug(data->d_buf, data->d_size, shdr->sh_offset + data->d_off);
}