view tool/coff.c @ 6:87e9f30f5f86

ti-libpatch: patching implemented
author Space Falcon <falcon@ivan.Harhan.ORG>
date Sat, 06 Jun 2015 04:51:15 +0000
parents
children
line wrap: on
line source

/*
 * This C module implements COFF operations for ti-libpatch.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "coffstruct.h"
#include "patchinfo.h"
#include "globals.h"

struct external_scnhdr *sections_raw;
unsigned nsections;
unsigned strtab_offset;

static unsigned
get_u16(ptr)
	u_char *ptr;
{
	return ptr[0] | ptr[1] << 8;
}

static unsigned
get_u32(ptr)
	u_char *ptr;
{
	return ptr[0] | ptr[1] << 8 | ptr[2] << 16 | ptr[3] << 24;
}

parse_coff_hdr()
{
	struct external_filehdr *filehdr_struct;
	unsigned symtab_offset;
	unsigned nsymtab;

	filehdr_struct = (struct external_filehdr *) member_body;
	if (get_u16(filehdr_struct->f_magic) != 0xC2) {
		fprintf(stderr,
			"error: member \"%s\" is not a TI COFF2 object\n",
			member_name);
		exit(1);
	}
	if (get_u16(filehdr_struct->f_target_id) != 0x97) {
		fprintf(stderr, "error: member \"%s\" is not a TMS470 object\n",
			member_name);
		exit(1);
	}
	if (get_u16(filehdr_struct->f_opthdr)) {
		fprintf(stderr,
		"error: member \"%s\" has the \"optional\" header present\n",
			member_name);
		exit(1);
	}
	sections_raw = (struct external_scnhdr *)
				(member_body + sizeof(struct external_filehdr));
	nsections = get_u16(filehdr_struct->f_nscns);
	symtab_offset = get_u32(filehdr_struct->f_symptr);
	nsymtab = get_u32(filehdr_struct->f_nsyms);
	strtab_offset = symtab_offset +
				sizeof(struct external_syment) * nsymtab;
	return(0);
}

static struct external_scnhdr *
find_section_shortname(soughtname)
	char *soughtname;
{
	unsigned i;
	struct external_scnhdr *scnhdr;

	for (i = 0; i < nsections; i++) {
		scnhdr = sections_raw + i;
		if (!strncmp(scnhdr->s_name, soughtname, 8))
			return(scnhdr);
	}
	return(0);
}

static struct external_scnhdr *
find_section_longname(soughtname)
	char *soughtname;
{
	unsigned i;
	struct external_scnhdr *scnhdr;
	u_char *np, *longname;

	for (i = 0; i < nsections; i++) {
		scnhdr = sections_raw + i;
		np = scnhdr->s_name;
		if (np[0] || np[1] || np[2] || np[3])
			continue;
		longname = member_body + strtab_offset + get_u32(np + 4);
		if (!strcmp(longname, soughtname))
			return(scnhdr);
	}
	return(0);
}

static struct external_scnhdr *
find_section(soughtname)
	char *soughtname;
{
	if (strlen(soughtname) <= 8)
		return find_section_shortname(soughtname);
	else
		return find_section_longname(soughtname);
}

apply_patch(patch)
	struct patch_desc *patch;
{
	struct external_scnhdr *scnhdr;
	unsigned data_offset, section_size;

	scnhdr = find_section(patch->section);
	if (!scnhdr) {
		fprintf(stderr,
		"error: could not find section \"%s\" in member \"%s\"\n",
			patch->section, member_name);
		exit(1);
	}
	data_offset = get_u32(scnhdr->s_scnptr);
	section_size = get_u32(scnhdr->s_size);
	if (data_offset + section_size > member_size) {
		fprintf(stderr,
		"error: section \"%s\" in member \"%s\" exceeds member size\n",
			patch->section, member_name);
		exit(1);
	}
	if (patch->offset >= section_size) {
		fprintf(stderr,
	"error: patch offset 0x%x in section \"%s\" exceeds section size\n",
			patch->offset, patch->section);
		exit(1);
	}
	/* do it! */
	member_body[data_offset + patch->offset] = patch->new_byte;
	return(0);
}