fw_elf

This is a tool to create an ELF from a bnx2 firmware file.1)

Usage:

Usage: ./fw_elf <mips.fw> <com|cp|rxp|tpat|txp> <out.elf>

Example:

[daniel@daniel-pc gsoc]$ ./fw_elf bnx2_bnx2-mips-06-6.2.3.fw txp txp.elf
Done

This produces the file txp.elf with appropriate .text, .data, and .rodata sections. This file should be easily loaded into a disassembler/debugger.

Code

fw_elf.c
#include <libelf.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <utils.h>
 
typedef uint32_t __be32;
 
struct bnx2_fw_file_section {
	__be32 addr;
	__be32 len;
	__be32 offset;
} __attribute__ ((__packed__));
 
struct bnx2_mips_fw_file_entry {
	__be32 start_addr;
	struct bnx2_fw_file_section text;
	struct bnx2_fw_file_section data;
	struct bnx2_fw_file_section rodata;
} __attribute__ ((__packed__));
 
struct bnx2_mips_fw_file {
	struct bnx2_mips_fw_file_entry com;
	struct bnx2_mips_fw_file_entry cp;
	struct bnx2_mips_fw_file_entry rxp;
	struct bnx2_mips_fw_file_entry tpat;
	struct bnx2_mips_fw_file_entry txp;
} __attribute__ ((__packed__));
 
char string_tbl[] = {
		'\0',
		'.','t','e','x','t','\0',
		'.','d','a','t','a','\0',
		'.','r','o','d','a','t','a','\0',
};
 
int main ( int argc, char *argv[] ) {
	int fd;
	FILE *fp;
	Elf *e;
	Elf_Scn *scn;
	Elf_Data *data;
	Elf32_Ehdr *ehdr;
	Elf32_Phdr *phdr;
	Elf32_Shdr *shdr;
	struct bnx2_mips_fw_file fw;
	struct bnx2_mips_fw_file_entry *entry;
	uint8_t *text_bytes;
	uint8_t *data_bytes;
	uint8_t *rodata_bytes;
 
	if ( argc != 4 ) {
		fprintf ( stderr, "Usage: %s <mips.fw> <com|cp|rxp|tpat|txp> <out.elf>\n", argv[0] );
		return 1;
	}
 
	fp = fopen ( argv[1], "rb" );
	if ( ! fp ) {
		fprintf ( stderr, "Failed to open file '%s'\n", argv[1] );
		return 1;
	}
	if ( fread ( &fw, sizeof ( struct bnx2_mips_fw_file ), 1, fp ) != 1 ) {
		fprintf ( stderr, "I/O error for file '%s'\n", argv[1] );
		return 1;
	}
	if ( strcmp ( argv[2], "com" ) == 0 )
		entry = &fw.com;
	else if ( strcmp ( argv[2], "cp" ) == 0 )
		entry = &fw.cp;
	else if ( strcmp ( argv[2], "rxp" ) == 0 )
		entry = &fw.cp;
	else if ( strcmp ( argv[2], "tpat" ) == 0 )
		entry = &fw.cp;
	else if ( strcmp ( argv[2], "txp" ) == 0 )
		entry = &fw.cp;
	else {
		fprintf ( stderr, "Invalid CPU argument (see usage)\n" );
		return 1;
	}
	entry->start_addr = be32_to_cpu ( entry->start_addr );
	entry->text.addr = be32_to_cpu ( entry->text.addr );
	entry->text.len = be32_to_cpu ( entry->text.len );
	entry->text.offset = be32_to_cpu ( entry->text.offset );
	entry->data.addr = be32_to_cpu ( entry->data.addr );
	entry->data.len = be32_to_cpu ( entry->data.len );
	entry->data.offset = be32_to_cpu ( entry->data.offset );
	entry->rodata.addr = be32_to_cpu ( entry->rodata.addr );
	entry->rodata.len = be32_to_cpu ( entry->rodata.len );
	entry->rodata.offset = be32_to_cpu ( entry->rodata.offset );
	if ( elf_version ( EV_CURRENT ) == EV_NONE ) {
		fprintf ( stderr, "libelf initialization failed\n" );
		return 1;
	}
	fd = open ( argv[3], O_WRONLY | O_CREAT, 0777 );
	if ( fd < 0 ) {
		fprintf ( stderr, "Failed to open output file '%s'\n", argv[3] );
		return 1;
	}
	if ( ( e = elf_begin ( fd, ELF_C_WRITE, NULL ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg( -1 ) );
		return 1;
	}
	if ( ( ehdr = elf32_newehdr ( e ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
	ehdr->e_machine = EM_MIPS;
	ehdr->e_type = ET_EXEC;
	ehdr->e_version = EV_CURRENT;
	ehdr->e_entry = entry->start_addr;
	if ( ( phdr = elf32_newphdr ( e, 1 ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	if ( ( scn = elf_newscn ( e ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	if ( ( data = elf_newdata ( scn ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	text_bytes = malloc ( entry->text.len );
	if ( ! text_bytes ) {
		fprintf ( stderr, "malloc failed\n" );
		return 1;
	}
	if ( fseek ( fp, entry->text.offset, SEEK_SET ) != 0 ) {
		fprintf ( stderr, "I/O error for file '%s'\n", argv[1] );
		return 1;
	}
	if ( fread ( text_bytes, 1, entry->text.len, fp ) != entry->text.len ) {
		fprintf ( stderr, "I/O error for file '%s'\n", argv[1] );
		return 1;
	}
	data->d_align = 1;
	data->d_off = 0LL;
	data->d_buf = text_bytes;
	data->d_type = ELF_T_BYTE;
	data->d_size = entry->text.len;
	data->d_version = EV_CURRENT;
 
	if ( ( shdr = elf32_getshdr ( scn ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	shdr->sh_name = 1;
	shdr->sh_type = SHT_PROGBITS;
	shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
	shdr->sh_addr = entry->text.addr;
	shdr->sh_entsize = 0;
 
	if ( ( scn = elf_newscn ( e ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	if ( ( data = elf_newdata ( scn ) ) == NULL ) {
		return 1;
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
	}
	data_bytes = malloc ( entry->data.len );
	if ( ! data_bytes ) {
		fprintf ( stderr, "malloc failed\n" );
		return 1;
	}
	if ( fseek ( fp, entry->data.offset, SEEK_SET ) != 0 ) {
		fprintf ( stderr, "I/O error for file '%s'\n", argv[1] );
		return 1;
	}
	if ( fread ( data_bytes, 1, entry->data.len, fp ) != entry->data.len ) {
		fprintf ( stderr, "I/O error for file '%s'\n", argv[1] );
		return 1;
	}
	data->d_align = 1;
	data->d_off = 0LL;
	data->d_buf = data_bytes;
	data->d_type = ELF_T_BYTE;
	data->d_size = entry->data.len;
	data->d_version = EV_CURRENT;
 
	if ( ( shdr = elf32_getshdr ( scn ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	shdr->sh_name = 7;
	shdr->sh_type = SHT_PROGBITS;
	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
	shdr->sh_addr = entry->data.addr;
	shdr->sh_entsize = 0;
 
	if ( ( scn = elf_newscn ( e ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	if ( ( data = elf_newdata ( scn ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	rodata_bytes = malloc ( entry->rodata.len );
	if ( ! rodata_bytes ) {
		fprintf ( stderr, "malloc failed\n" );
		return 1;
	}
	if ( fseek ( fp, entry->rodata.offset, SEEK_SET ) != 0 ) {
		fprintf ( stderr, "I/O error for file '%s'\n", argv[1] );
		return 1;
	}
	if ( fread ( rodata_bytes, 1, entry->rodata.len, fp ) != entry->rodata.len ) {
		fprintf ( stderr, "I/O error for file '%s'\n", argv[1] );
		return 1;
	}
	fclose ( fp );
	data->d_align = 1;
	data->d_off = 0LL;
	data->d_buf = rodata_bytes;
	data->d_type = ELF_T_BYTE;
	data->d_size = entry->rodata.len;
	data->d_version = EV_CURRENT;
 
	if ( ( shdr = elf32_getshdr ( scn ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	shdr->sh_name = 13;
	shdr->sh_type = SHT_PROGBITS;
	shdr->sh_flags = SHF_ALLOC;
	shdr->sh_addr = entry->rodata.addr;
	shdr->sh_entsize = 0;
 
	if ( ( scn = elf_newscn ( e ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	if ( ( data = elf_newdata ( scn ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	data->d_align = 1;
	data->d_buf = string_tbl;
	data->d_off = 0LL;
	data->d_size = sizeof ( string_tbl );
	data->d_type = ELF_T_BYTE;
	data->d_version = EV_CURRENT;
 
	if ( ( shdr = elf32_getshdr ( scn ) ) == NULL ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	shdr->sh_name = 0;
	shdr->sh_type = SHT_STRTAB;
	shdr->sh_flags = SHF_STRINGS | SHF_ALLOC;
	shdr->sh_entsize = 0;
 
	ehdr->e_shstrndx = elf_ndxscn ( scn );
 
	if ( elf_update ( e, ELF_C_NULL ) < 0 ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	phdr->p_type = PT_PHDR;
	phdr->p_offset = ehdr->e_phoff;
	phdr->p_filesz = elf32_fsize ( ELF_T_PHDR, 1, EV_CURRENT );
	phdr->p_vaddr = 0x8000000;
	elf_flagphdr ( e, ELF_C_SET, ELF_F_DIRTY );
	if ( elf_update ( e, ELF_C_WRITE ) < 0 ) {
		fprintf ( stderr, "libelf error: %s\n", elf_errmsg ( -1 ) );
		return 1;
	}
	elf_end ( e );
	close ( fd );
	printf ( "Done\n" );
	return 0;
}
 
gsoc/bnx2/fw_elf.txt · Last modified: 2012/06/10 12:58 by dewyatt
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki
All uses of this content must include an attribution to the iPXE project and the URL http://ipxe.org
References to "iPXE" may not be altered or removed.