Skip to content

Commit

Permalink
Symbol migration tool for functions and global data. #175
Browse files Browse the repository at this point in the history
  • Loading branch information
travisgoodspeed committed Jul 12, 2016
1 parent f1c2120 commit 8748b4b
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 0 deletions.
25 changes: 25 additions & 0 deletions symbols/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

UNWRAPPED=../firmware/unwrapped
GOLD=../firmware/unwrapped/D002.032.img
GOLDSYM=../applet/src/symbols_2_032

all: symgrate run

clean:
rm -f symgrate symbols_*
images:
cd ../firmware && make all

run: all images
./symgrate $(GOLD) $(UNWRAPPED)/D002.034.img <$(GOLDSYM) >symbols_d02_034
./symgrate $(GOLD) $(UNWRAPPED)/D003.008.img <$(GOLDSYM) >symbols_d03_008
./symgrate $(GOLD) $(UNWRAPPED)/D013.009.img <$(GOLDSYM) >symbols_d13_009
./symgrate $(GOLD) $(UNWRAPPED)/S003.012.img <$(GOLDSYM) >symbols_s03_012
./symgrate $(GOLD) $(UNWRAPPED)/S013.012.img <$(GOLDSYM) >symbols_s13_012
./symgrate $(GOLD) $(UNWRAPPED)/D013.014.img <$(GOLDSYM) >symbols_d13_014
wc -l symbols_*
@echo "These are temporary symbol files that will be overwritten."
@echo "Move them elsewhere before editing."



14 changes: 14 additions & 0 deletions symbols/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
This directory is used to auto-generate symbols for unknown MD380
firmware versions from the present gold-standard version, which will
likely be 2.032 for quite some time.

The tool's parser is too primitive to understand addition, so please
ensure that all input lines are either (1) just a comment, (2) just
whitespace, or (3) a symbol name and value with no arithmetic.

'make clean all' ought to produce symbol files for all versions, for
all functions that match.

Cheers,
--Travis

226 changes: 226 additions & 0 deletions symbols/symgrate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
/* \file symgrate.c
\author Travis Goodspeed <travis@radiantmachines.com
\brief Symbol migration tool.
This is a quick and dirty tool for migrating function symbols in
Thumb(2) machine code on ARM Cortex M4, and more specifically, for
migrating function symbols between various firmware images of the
Tytera MD380. I hope someday to target related radios, such as
those from Connect Systems.
The general theory of operation is pretty simple. We have a
known-good firmware images (2.032) with a number of identified
functions, and we wish to hook, patch, or call those functions on a
new firmware image. Since Thumb uses constant pools for its
immediates, rather than putting them inside the instructions, the
related function ought to be the closes match for the starting
code.
Where possible, this tool matches each function in the old image to
an address in the new image. This will succeed where the function
and optimizations haven't changed between revisions, hopefully
leaving just a few remaining functions to search for manually in
IDA+Bindiff or Radare. The goal is not to be sophisticated, but to
catch as much of a break for free as possible.
A separate tool will be needed to find branches and RAM addresses.
Also, this parser sucks.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//Image begins just after the bootloader.
const int BASE=0x0800C000;
const int MAXLEN=1024*1024;

//These refer to the actual buffers.
char *Src;
char *Dst;

//These macros grab a byte from the device.
#define src8(x) (*(Src+x-BASE))
#define dst8(x) (*(Src+x-BASE))

//These macros grab a word from the device.
#define src32(x) (*((int*)(Src+x-BASE)))
#define dst32(x) (*((int*)(Dst+x-BASE)))

//These macros grab a short from the device.
#define src16(x) (*((short*)(Src+x-BASE)))
#define dst16(x) (*((short*)(Dst+x-BASE)))



//! Loads a disk image into a buffer.
int loadbuffer(char *buf, const char *filename){
FILE *f;
int len;

f=fopen(filename,"r");
if(!f){
printf("File %s not found!\n", filename);
exit(1);
}

//FIXME hardcoded size
len=fread(buf, 1024, 1024, f);

return 0;
}

//! Allocate the buffers.
int mallocbuffers(){
Src=(char*) malloc(MAXLEN);
Dst=(char*) malloc(MAXLEN);
return 1;//success
}

//! Scores a match between the src and destination buffer by length.
int scorematch(int sadr, int dadr){
int i=0;

/* Compare up to the first 1024 bytes, one pair at a time. Usually
the best score is the same function if that function hasn't been
modified between versions.
*/
do{
i+=2;
}while(src32(sadr+i)==dst32(dadr+i) && i<1024);

return i;
}

//!Locates a symbol by name and address.
int findsymbol(const char *name, int adr){
int isfunction=adr&1;
adr=adr&~1;

if(adr&0x20000000){ //RAM
printf("/* %s is a RAM address and cannot be converted. */\n",
name);
return adr|isfunction;
}else if(adr&0x40000000){ //IO
printf("%s = 0x%08x;\n",
name,adr|isfunction);
return adr|isfunction;
}


/* Here we run through the destination image, trying to find
anything that matches a few bytes. The decision of whether to
accept the match comes later.
*/
short tofind=src16(adr);
int dadr=0, dscore=0;
for(int i=0;i<(MAXLEN);i+=2){
if(src16(adr)==dst16(BASE+i)){
int score=scorematch(adr,BASE+i);

if(score>dscore){
dscore=score;
dadr=adr;
}
}
}

if(dadr && dscore>8)
printf("%-20s = 0x%08x; /* %i byte match */\n",
name,
adr+isfunction,
dscore);
else if(dadr)
printf("/* %s has bad match of %i points at 0x%08x*/\n",
name, dscore, adr+isfunction);
else
printf("/* %s not found. */\n",
name);

return dadr;
}

//! Ugly shotgun parser for one record of the file.
int parseline(char *line,
char *retname, int *retadr){
//Assumes a form like this:
//md380_spiflash_read = 0x802fd83;


char *start=line;
char *eq=strstr(line,"=");
char *semicolon=strstr(line,";");
char *name=start;
char *adr=strstr(line,"0x");
char *plus=strstr(line,"+");

//We can't handle arithmetic
if(plus){
return 0;
}

//We need all these fields.
if(name && semicolon && eq && adr){
sscanf(name,"%s ",retname);
sscanf(adr, "0x%08x",retadr);
return 1;
}

return 0;
}

//! Ugly puntgun parser loop, terribly unsafe.
int parseloop(){
static char line[10240];
//FIXME This should really be rewritten with a better parsing library.

static char name[1024];
int adr;
memset(name,1024,0);

while(!feof(stdin)){
//Read the line.
fgets(line,1024,stdin);

if(strlen(line)==1){ //empty line.
printf("\n");
}else if(line[0]=='/' && line[1]=='*'){ //commenty line
printf("%s",line);
}else if(parseline(line,name,&adr)){
//Look for a symbol match.
//This prints its own result.
findsymbol(name,adr);
}else{
printf("/* Unparsed line: %s */\n",
line);
}
}
return 0;
}

//! Main method. Maybe abstract this a bit?
int main(int argc, char **argv){
//Allocate the buffers.
mallocbuffers();

if(argc<3){
printf("Usage: %s D002.032.img D013.014.img "
"<symbols_D002.032 >symbols_D013.014\n",
argv[0]);
return 1;
}

//Load the source and destination buffers.
loadbuffer(Src,argv[1]);
loadbuffer(Dst,argv[2]);


printf("/* Symbols for %s imported from %s. */\n",
argv[2],
argv[1]);

parseloop();
}

0 comments on commit 8748b4b

Please sign in to comment.