view objgrep/mkpattern.c @ 215:d69f7512e3c1

Pirelli: documented and verified the checksum scheme used for the factory block
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 25 Dec 2016 23:48:16 +0000
parents 77cd647375e5
children
line wrap: on
line source

/*
 * objgrep: preparation of matching pattern
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "filestruct.h"
#include "intstruct.h"
#include "coffconst.h"
#include "globals.h"

extern unsigned get_u16(), get_u32();

static unsigned
arm_branch_reloc(origbits, location)
	u_char *origbits;
	unsigned location;
{
	unsigned word, dest;

	word = get_u32(origbits + location);
	if ((word & 0x0E000000) != 0x0A000000) {
		fprintf(stderr,
			"error: invalid ARM_B reloc: opcode not B or BL\n");
		exit(2);
	}
	dest = (word & 0x00FFFFFF) << 2;
	if (dest & 0x02000000)
		dest |= 0xFC000000;
	dest += location + 8;
	return(dest);
}

static unsigned
thumb_bl_reloc(origbits, location)
	u_char *origbits;
	unsigned location;
{
	unsigned ins1, ins2;
	unsigned dest;

	ins1 = get_u16(origbits + location);
	ins2 = get_u16(origbits + location + 2);
	if ((ins1 & 0xF800) != 0xF000 || (ins2 & 0xF800) != 0xF800) {
		fprintf(stderr,
			"error: invalid Thumb_BL reloc: opcode not BL\n");
		exit(2);
	}
	dest = ((ins1 & 0x7FF) << 12) | ((ins2 & 0x7FF) << 1);
	if (dest & 0x00400000)
		dest |= 0xFF800000;
	dest += location + 4;
	return(dest);
}

prepare_pattern()
{
	u_char *origbits;
	unsigned pad, n;
	struct internal_reloc *irel;
	struct external_reloc *xrel;
	unsigned lastloc, symidx;
	struct internal_syment *sym;

	origbits = objfilemap + grep_section->data_offset;
	pattern_len = (grep_section->size + 3) & ~3;
	pattern_match = malloc(pattern_len);
	if (!pattern_match) {
		perror("malloc");
		exit(2);
	}
	bcopy(origbits, pattern_match, grep_section->size);
	pattern_mask = malloc(pattern_len);
	if (!pattern_mask) {
		perror("malloc");
		exit(2);
	}
	memset(pattern_mask, 0xFF, grep_section->size);
	pad = pattern_len - grep_section->size;
	if (pad) {
		bzero(pattern_match + grep_section->size, pad);
		bzero(pattern_mask + grep_section->size, pad);
	}
	if (!grep_section->nreloc)
		return(0);
	xrel = (struct external_reloc *)
				(objfilemap + grep_section->reloc_offset);
	irel = malloc(sizeof(struct internal_reloc) * grep_section->nreloc);
	if (!irel) {
		perror("malloc");
		exit(2);
	}
	relocs = irel;
	for (n = 0; n < grep_section->nreloc; n++, xrel++, irel++) {
		irel->location = get_u32(xrel->r_vaddr);
		if (n && irel->location < lastloc) {
			fprintf(stderr, "error: non-increasing reloc order\n");
			exit(2);
		}
		lastloc = irel->location + 4;
		if (lastloc > grep_section->size) {
			fprintf(stderr,
			"error: reloc spills past the end of the section\n");
			exit(2);
		}
		symidx = get_u32(xrel->r_symndx);
		if (symidx == 0xFFFFFFFF)
			sym = 0;
		else if (symidx >= nsymtab || !symtab[symidx]) {
			fprintf(stderr,
				"error: reloc references invalid symbol #%u\n",
				symidx);
			exit(2);
		} else
			sym = symtab[symidx];
		if (sym && sym->value) {
			fprintf(stderr,
		"error: symbol #%u referenced by reloc has nonzero value\n");
			exit(2);
		}
		if (!sym) {
			irel->secbase = grep_section;
			irel->extsym = 0;
			nreloc_int++;
		} else if (sym->class == C_EXT && sym->scnum == 0) {
			irel->extsym = sym;
			irel->secbase = 0;
			nreloc_ext++;
		} else if (sym->class == C_STAT && sym->section &&
			   !strcmp(sym->name, sym->section->name)) {
			irel->secbase = sym->section;
			irel->extsym = 0;
			nreloc_int++;
		} else {
			fprintf(stderr, "error: unable to grok reloc\n");
			exit(2);
		}
		irel->type = get_u16(xrel->r_type);
		switch (irel->type) {
		case RTYPE_LONG:
			if (irel->location & 3) {
align_error:			fprintf(stderr, "error: misaligned reloc\n");
				exit(2);
			}
			irel->addend = get_u32(origbits + irel->location);
			*(uint32_t *)(pattern_match + irel->location) = 0;
			*(uint32_t *)(pattern_mask + irel->location) = 0;
			break;
		case RTYPE_ARM_B:
			if (irel->location & 3)
				goto align_error;
			irel->addend = arm_branch_reloc(origbits,
							irel->location);
			bzero(pattern_match + irel->location, 3);
			bzero(pattern_mask + irel->location, 3);
			break;
		case RTYPE_THUMB_BL:
			if (irel->location & 1)
				goto align_error;
			irel->addend = thumb_bl_reloc(origbits, irel->location);
			pattern_match[irel->location+0] = 0;
			pattern_match[irel->location+1] &= 0xF8;
			pattern_match[irel->location+2] = 0;
			pattern_match[irel->location+3] &= 0xF8;
			pattern_mask[irel->location+0] = 0;
			pattern_mask[irel->location+1] = 0xF8;
			pattern_mask[irel->location+2] = 0;
			pattern_mask[irel->location+3] = 0xF8;
			break;
		default:
			fprintf(stderr, "error: reloc type 0x%x unsupported\n",
				irel->type);
			exit(2);
		}
	}
	return(1);
}