whang.c 6.84 KB
#include <stdio.h>
#include <sym.h>
#include <symconst.h>
#include <elf.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>

#define ELF_FILE_TYPE 0x7f454c46

typedef enum {
    ELF_OPEN,
    ELF_ERR,
    ELF_CLOSED
} ElfState;

typedef struct {
    FILE        *file;
    ElfState    state;          /* file state           */
    Elf32_Ehdr  hdr;            /* file header          */
    Elf32_Shdr  *shdr;          /* section headers      */
    char        *strtab;
} ElfFile;

char *str[] = {
    "stNil",
    "stGlobal",
    "stStatic",
    "stParam",
    "stLocal",
    "stLabel",
    "stProc",
    "stBlock",
    "stEnd",
    "stMember",
    "stTypedef",
    "stFile",
    "stRegReloc",
    "stForward",
    "stStaticProc",
    "stConstant",
    "stStaParam",
    "stBase",
    "stTag",
    "stAdjMember",
    "stPublic",
    "stProtected",
    "stPrivate",
    "stTemp",
    "stTempProc",
    "stDefArg"
};

ElfFile *elfOpen(char *name) 
{
    FILE *file;
    ElfFile *e;
    int cnt;
    
    e = (ElfFile *)malloc(sizeof(ElfFile));
    e->shdr = 0;
    e->strtab = 0;
    
    file = fopen (name, "r+");

    if (!file) {
        printf("can't open %s\n", name);
        exit(1);
    }
    
    e->file = file;
    e->state = ELF_OPEN;
    
    cnt = fread ((void *)&e->hdr, sizeof(e->hdr), 1, file);
    if (cnt != 1) {
        printf("couldn't read elf header\n");
        exit(1);
    }

    if (*(int *)&e->hdr != ELF_FILE_TYPE) {
        printf("%s is not an ELF file\n", name);
        exit(1);
    }

    return e;
}

void elfClose(ElfFile *elf) 
{
    fflush(elf->file);
    fclose(elf->file);    
}

void elfRead(ElfFile *elf, void *ptr, long offset, long size)
{
    int err;
    int cnt;
    
    assert(elf->state == ELF_OPEN);

    err = fseek(elf->file, offset, SEEK_SET);
    if (err)
        printf("elfRead seek error %d\n", err);
    
    cnt = fread (ptr, size, 1, elf->file);
    if (cnt != 1)
        printf("elfRead read error, count = %d\n", cnt);
    
}

void elfWrite(ElfFile *elf, void *ptr, long offset, long size)
{
    int err;
    int cnt;

    err = fseek(elf->file, offset, SEEK_SET);
    if (err)
        printf("elfWrite seek error %d\n", err);
    
    cnt = fwrite (ptr, size, 1, elf->file);
    if (cnt != 1)
        printf("elfWrite write error, count = %d\n", cnt);
}

void elfReadSectionHeaders(ElfFile *elf) 
{
    Elf32_Shdr  *ptr;
    
    assert(elf->state == ELF_OPEN);

    ptr = (Elf32_Shdr  *)malloc(elf->hdr.e_shentsize*elf->hdr.e_shnum);
    
    fseek(elf->file, elf->hdr.e_shoff, SEEK_SET);

    fread ((void *)ptr, elf->hdr.e_shentsize, elf->hdr.e_shnum, elf->file);

    elf->shdr = ptr;
}

char *elfReadSectionId(ElfFile *elf, Elf32_Half id)
{
    Elf32_Shdr *shdr;
    char *ptr;
    
    if (elf->shdr == 0)
        elfReadSectionHeaders(elf);
    
    assert(elf->hdr.e_shentsize == sizeof(Elf32_Shdr));

    shdr = &elf->shdr[id];
    
    ptr = (char *)malloc(shdr->sh_size);
    fseek (elf->file, shdr->sh_offset, SEEK_SET);
    fread ((void *)ptr, shdr->sh_size, 1, elf->file);
    return ptr;
}
    
void elfReadStringTab(ElfFile *elf)
{
    if (elf->shdr == 0)
        elfReadSectionHeaders(elf);

    elf->strtab = elfReadSectionId(elf, elf->hdr.e_shstrndx);
}

char *elfLookupString(ElfFile *elf, Elf32_Word name) 
{
    if (elf->strtab == 0)
        elfReadStringTab(elf);

    return &elf->strtab[name];
}

long elfLookupSectionId(ElfFile *elf, Elf32_Half id)
{
    Elf32_Shdr *shdr;
    char *ptr;
    
    if (elf->shdr == 0)
        elfReadSectionHeaders(elf);
    
    assert(elf->hdr.e_shentsize == sizeof(Elf32_Shdr));

    return elf->shdr[id].sh_offset;
    
}
    
long elfLookupSection(ElfFile *elf, char *name) 
{
    char *secName;
    Elf32_Shdr *shdr;
    int i;
    
    if (elf->shdr == 0)
        elfReadSectionHeaders(elf);
    
    assert(elf->hdr.e_shentsize == sizeof(Elf32_Shdr));
    
    for (i = 0; i < elf->hdr.e_shnum; i++) {

        shdr = &elf->shdr[i];   /* might want to increment by e_shentsize */
        
        secName = elfLookupString(elf, shdr->sh_name);

        printf("found section %s\n", secName);
        
        if (strcmp(name, secName) == 0)
            break;

    }

    if (i < elf->hdr.e_shnum)
        return elfLookupSectionId(elf, i);
    else
        return 0;
}

main(int argc, char **argv) 
{
    ElfFile     *elf;
    FDR         fdr;
    PDR         pdr;
    HDRR        hdrr;
    SYMR        symr;
    int         i,j;
    long        offset, fdrOffset;
    char        *ss;
    
    elf = elfOpen(argv[1]);

    /* read the .mdebug header */
    elfRead(elf, &hdrr, elfLookupSection(elf, ".mdebug"), sizeof(HDRR));
    
    for (i = 0; i < hdrr.ifdMax; i++) {

        /* read the FDR */
        fdrOffset = hdrr.cbFdOffset + i*sizeof(FDR);
        elfRead(elf, &fdr, fdrOffset, sizeof(FDR));

        /* get the local string table */
        ss = (char *)malloc(fdr.cbSs);
        elfRead(elf, ss, hdrr.cbSsOffset + fdr.issBase, fdr.cbSs);

        printf("File %d: %s\n", i, &ss[fdr.rss]);

        /*
         * Get the first PDR and look up its symbol. The symbol will
         * have the absolute address of the procedure. We will
         * subtract the pdr.adr offset to get the real fdr.adr. Note:
         * assumes that the pdrs are given in order.
         */
        if (fdr.cpd) {
            
            offset = hdrr.cbPdOffset + fdr.ipdFirst*sizeof(PDR);
            elfRead(elf, &pdr, offset, sizeof(PDR));

            if (pdr.isym != isymNil) {
                if (fdr.csym) {
                    /* local symbol table */
                    offset = hdrr.cbSymOffset +
                        (fdr.isymBase + pdr.isym)*sizeof(SYMR);
                    elfRead(elf, &symr, offset, sizeof(SYMR));
                    switch(symr.st) {
                      case (stProc):
                      case (stStaticProc):
                          fdr.adr = symr.value - pdr.adr;
                          printf("\tnew fdr.adr = 0x%x\n", fdr.adr);
                          elfWrite(elf, &fdr, fdrOffset, sizeof(FDR));
                          /* ### write out new fdr */
                          break;
                      default:
                          printf("\tbad proc sym %s %s\n",
                                 &ss[symr.iss], str[symr.st]);
                          break;
                    }
                
                } else {
                    /* external symbol table */
                    printf("\tExternal Proc Sym FDR %d PDR %d\n", i,j);
                }
            }
        }
        

        free(ss);       /* ditch the string table */
    }

    elfClose(elf);
}

#if 0
        /* get all the symbols for this fdr */
        for (j = 0; j < fdr.csym; j++) {
            offset = hdrr.cbSymOffset + (fdr.isymBase + j)*sizeof(SYMR);
            elfRead(elf, &symr, offset, sizeof(SYMR));
            if (symr.st != stNil)
                printf("\t%s\n", &ss[symr.iss]);
        }
#endif