diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/coff.c	Sat Jun 06 04:51:15 2015 +0000
@@ -0,0 +1,141 @@
+/*
+ * 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);
+}