elf.c 10.9 KB
/*==============================================================================
    Module: elf.c
    $Revision: 1.1.1.2 $
    $Date: 2002/10/29 08:07:15 $
    $Author: blythe $
    $Source: /root/leakn64/depot/rf/sw/n64os20l/tools/gcord/com/elf.c,v $

    Routines to hand elf
==============================================================================*/
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <elf.h>

#include "global.h"
#include "option.h"
#include "update.h"

/*------------------------------------------------------------------------------
        find a section's by it's name
------------------------------------------------------------------------------*/
Elf_Scn *find_section_by_name(Elf *elf, char *name)
{
    if (IS_32BIT())
        find_section_by_name32(elf, name);
    else
        find_section_by_name64(elf, name);
}

/*------------------------------------------------------------------------------
        find a section's data by it's name
------------------------------------------------------------------------------*/
Elf_Data *find_section_data_by_name(Elf *elf, char *name)
{
    Elf_Scn     *section;

    section = find_section_by_name(elf, name);
    if (section == NULL)
        return (Elf_Data *) NULL;
    return elf_getdata(section, NULL);
}

/*------------------------------------------------------------------------------
    get text or data given an address.
------------------------------------------------------------------------------*/
Uint32 *get_textdata_by_addr(Elf *elf, Uint64 addr)
{
    if (IS_32BIT())
        get_textdata_by_addr32(elf, (Uint32) addr);
    else
        get_textdata_by_addr64(elf, addr);
}

/*------------------------------------------------------------------------------
    returns the procedure name given the gp offset.   
------------------------------------------------------------------------------*/
Addr get_addr_by_got_offset(int offset)
{
    int		index;
    Addr	address;

    ASSERT(IS_32BIT());
    address = bin.gp_value + offset;
    index = (address - bin.dt_got_base)>>2;

    return  (Addr) bin.got.got32[index].g_index;
}

/*------------------------------------------------------------------------------
  malloc and copy the content
------------------------------------------------------------------------------*/
static char *malloc_copy(char* source, unsigned size)
{
    char *dest;

    dest = (char *) malloc(size);
    if (!dest)
        error("malloc error");
    memcpy(dest, source, size);
    return dest;
}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void duplicate_elf32(void)
{
    Elf *old_elf = bin.elf;
    Elf *new_elf = bin.new_elf;
    char *shstrtab;
    char *section_name;
    int i;

    Elf32_Ehdr  *new_ehdr32, *old_ehdr32;
    Elf32_Phdr  *new_phdr32, *old_phdr32;
    Elf32_Shdr  *new_shdr, *old_shdr;
    Elf_Scn     *new_section, *old_section;
    Elf_Data    *new_data, *old_data;

    /*------------------
      get elf header and program header
    ------------------*/
    old_ehdr32 = elf32_getehdr(old_elf);
    old_phdr32 = elf32_getphdr(old_elf);

    /*------------------
      get section string table
    ------------------*/
    old_section = elf_getscn(old_elf, old_ehdr32->e_shstrndx);
    old_data =  elf_getdata(old_section, 0);
    shstrtab = old_data->d_buf;

    /*------------------
      get new elf header and program header
    ------------------*/
    new_ehdr32 = elf32_newehdr(new_elf);
    if (!new_ehdr32)
	print_elf_error("elf32_newehdr");

    new_phdr32 = elf32_newphdr(new_elf, old_ehdr32->e_phnum);
    if (!new_phdr32)
	print_elf_error("elf32_newphdr");

    /*------------------
      duplicating elf header and program header table
    ------------------*/
        /* elf header */
    memcpy(new_ehdr32, old_ehdr32, sizeof(Elf32_Ehdr));
        /* program header */
    memcpy(new_phdr32, old_phdr32, old_ehdr32->e_phnum*sizeof(Elf32_Phdr));

    /*------------------
     duplicate sections
    ------------------*/
    for (i = 1; (old_section = elf_getscn(old_elf, i)) != NULL; i++)
    {
	GCORDSECTPTR newSect;

        old_shdr = elf32_getshdr(old_section);
        section_name = shstrtab + old_shdr->sh_name;

        old_data = elf_getdata(old_section, (Elf_Data*) 0);
        new_section = elf_newscn(new_elf);
        new_shdr = elf32_getshdr(new_section);
        memcpy(new_shdr, old_shdr, sizeof(Elf32_Shdr));

        if (old_data)
	{
            new_data = elf_newdata(new_section);
            memcpy(new_data, old_data, sizeof(Elf_Data));
            if (old_data->d_buf)
	    {
                new_data->d_buf = 
			malloc_copy(old_data->d_buf, old_data->d_size);
		if ( strlen( section_name ) >= 6 &&
		    ((!strcmp(&section_name[strlen(section_name)-5],".text")) 
		|| (!strcmp(&section_name[strlen(section_name)-5], ".data")))) {
                                        /* found a (possible) segment with text
in it */
                                        if ( (newSect = (GCORDSECTPTR) malloc( sizeof( GCORDSECT ) )) == 0 )
                                            error( "No more space for sections"
);
                                        newSect->next = gcordSectList;
                                        newSect->new_shdr = new_shdr;
                                        newSect->old_shdr = old_shdr;
                                        newSect->new_section = new_section;
                                        newSect->old_section = old_section;
                                        newSect->new_data = new_data;
                                        newSect->old_data = old_data;
                                        newSect->name = strdup( section_name );
                                        gcordSectList = newSect;
                                }

                                if (!strcmp(section_name, ".reginfo")) {
                                    Uint32    *reginfo = (Uint32 *)new_data->d_buf;
                                    bin.gp_value = reginfo[5];

				}
            }
        }
    }
}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void duplicate_elf64(void)
{
    Elf *old_elf = bin.elf;
    Elf *new_elf = bin.new_elf;
    char *shstrtab;
    char *section_name;
    int i;

    Elf64_Ehdr  *new_ehdr64, *old_ehdr64;
    Elf64_Phdr  *new_phdr64, *old_phdr64;
    Elf64_Shdr  *new_shdr, *old_shdr;
    Elf_Scn     *new_section, *old_section;
    Elf_Data    *new_data, *old_data;

    /*------------------
      get elf header and program header
    ------------------*/
    old_ehdr64 = elf64_getehdr(old_elf);
    old_phdr64 = elf64_getphdr(old_elf);

    /*------------------
      get section string table
    ------------------*/
    old_section = elf_getscn(old_elf, old_ehdr64->e_shstrndx);
    old_data =  elf_getdata(old_section, 0);
    shstrtab = old_data->d_buf;

    /*------------------
      get new elf header and program header
    ------------------*/
    new_ehdr64 = elf64_newehdr(new_elf);
    new_phdr64 = elf64_newphdr(new_elf, old_ehdr64->e_phnum);

    /*------------------
      duplicating elf header and program header table
    ------------------*/
        /* elf header */
    memcpy(new_ehdr64, old_ehdr64, sizeof(Elf64_Ehdr));
        /* program header */
    memcpy(new_phdr64, old_phdr64, old_ehdr64->e_phnum*sizeof(Elf64_Phdr));

    /*------------------
     duplicate sections
    ------------------*/
    for (i = 1; (old_section = elf_getscn(old_elf, i)) != NULL; i++)
    {

        old_shdr = elf64_getshdr(old_section);
        section_name = shstrtab + old_shdr->sh_name;

        old_data = elf_getdata(old_section, (Elf_Data*) 0);
        new_section = elf_newscn(new_elf);
        new_shdr = elf64_getshdr(new_section);
        memcpy(new_shdr, old_shdr, sizeof(Elf64_Shdr));

        if (old_data)
	{
            new_data = elf_newdata(new_section);
            memcpy(new_data, old_data, sizeof(Elf_Data));

            if (old_data->d_buf)
	    {
                new_data->d_buf = 
			malloc_copy(old_data->d_buf, old_data->d_size);
            }
	    if (!strcmp(section_name, ELF_TEXT)) {
                bin.new_text = (MIPS_Inst *) new_data->d_buf;
            }
        }
    }
}

/*------------------------------------------------------------------------------
  duplicate binary
------------------------------------------------------------------------------*/
void duplicate_elf(void)
{
    elf_version(EV_CURRENT);

    /*------------------
      create new elf
    ------------------*/
    bin.new_elf = elf_begin(bin.fd_out, ELF_C_WRITE, (Elf *) NULL);
    if (!bin.new_elf) 
        print_elf_error("cannot open %s", option.out_file);

    if (IS_32BIT())
	duplicate_elf32();
    else if (IS_64BIT())
	duplicate_elf64();

    /* mark elf as dirty */
    elf_flagelf(bin.new_elf, ELF_C_SET, ELF_F_DIRTY);
    elf_flagelf(bin.new_elf, ELF_C_SET, ELF_F_LAYOUT);
}

/*------------------------------------------------------------------------------
    Expand a section and move all sections after it by "offset"..
------------------------------------------------------------------------------*/
void expand_section(Elf_Scn *section, Uint32 offset)
{
    if (IS_32BIT())
    {
	expand_section32(section, offset);
    }
    else
    {
	expand_section64(section, (Uint64) offset);
    }
}

/*------------------------------------------------------------------------------
    Open new binary
------------------------------------------------------------------------------*/
void open_new_binary(void)
{
    bin.fd_out = open(option.out_file, O_WRONLY|O_CREAT|O_TRUNC, 0755);
    if(bin.fd_out <= 0)
    {
        sysfatal("cannot open %s", option.out_file);
    }
}

/*------------------------------------------------------------------------------
    Duplicate entire binary.
    TO_DO: remove this. 
	   This is needed to copy part of mdebug section and rpt in 
	   post_process();
------------------------------------------------------------------------------*/
void copy_binary(void)
{
    unsigned size;
    void *buf;

    /*------------------
      find the size
    ------------------*/
    size = lseek(bin.fd_in, 0, SEEK_END);

    /*------------------
      set pointer to the beginning
    ------------------*/
    lseek(bin.fd_in, 0, SEEK_SET);
    lseek(bin.fd_out, 0, SEEK_SET);
    buf = malloc(size);

    if (read(bin.fd_in, buf, size) != size)
        sysfatal("reading %s", option.in_file);

    write(bin.fd_out, buf, size);
    free(buf);
}

/*------------------------------------------------------------------------------
    print a elf error.
------------------------------------------------------------------------------*/
void print_elf_error (void)
{
        int err;
        err = elf_errno();
        if (err != 0)
            error(elf_errmsg(err));
}