mirror of
https://git.planet-casio.com/Lephenixnoir/fxsdk.git
synced 2024-12-28 04:23:37 +01:00
fxos: bring disassembling to a new level
Almost-complete implementation of fxos, the disassembler in particular is now able to detect syscalls and register addresses on the fly, plus support for SH4-only instructions.
This commit is contained in:
parent
ed8e199f47
commit
25db504c22
26 changed files with 3259 additions and 281 deletions
37
Makefile
37
Makefile
|
@ -6,12 +6,10 @@ include Makefile.cfg
|
|||
endif
|
||||
|
||||
# Compiler flags
|
||||
cflags = -Wall -Wextra -std=c11 -O2 -I $(dir $<) -D_GNU_SOURCE \
|
||||
cflags = -Wall -Wextra -std=c11 -g -I $(dir $<) -D_GNU_SOURCE \
|
||||
-DFXSDK_PREFIX='"$(PREFIX)"' $(CFLAGS)
|
||||
# Linker flags
|
||||
lflags = -lpng
|
||||
# Bison generation flags
|
||||
# bflags = -L C --defines=$(@:.c=.h) --verbose
|
||||
# Dependency generation flags
|
||||
dflags = -MT $@ -MMD -MP -MF $(@:%.o=%.d)
|
||||
|
||||
|
@ -28,15 +26,18 @@ src = $(wildcard $1/*.c)
|
|||
src-fxsdk := $(call src,fxsdk)
|
||||
src-fxg1a := $(call src,fxg1a)
|
||||
src-fxos := $(call src,fxos)
|
||||
lex-fxos := $(wildcard fxos/*.l)
|
||||
|
||||
obj = $(src-$1:%=build/%.o)
|
||||
obj-fxsdk := $(call obj,fxsdk)
|
||||
obj-fxg1a := $(call obj,fxg1a)
|
||||
obj-fxos := $(call obj,fxos)
|
||||
obj = $($1:%=build/%.o)
|
||||
lex = $($1:%.l=build/%.yy.c.o)
|
||||
obj-fxsdk := $(call obj,src-fxsdk)
|
||||
obj-fxg1a := $(call obj,src-fxg1a)
|
||||
obj-fxos := $(call obj,src-fxos) $(call lex,lex-fxos)
|
||||
|
||||
# Symbolic targets
|
||||
|
||||
all: $(bin)
|
||||
@echo $(lex-fxos)
|
||||
|
||||
all-fxsdk: bin/fxsdk
|
||||
all-fxg1a: bin/fxg1a
|
||||
|
@ -62,17 +63,11 @@ build/%.c.o: %.c
|
|||
@mkdir -p $(dir $@)
|
||||
gcc -c $< -o $@ $(cflags) $(dflags)
|
||||
|
||||
# Flex lexers (unused since fxconv is written in Python)
|
||||
# build/%/lexer.yy.c: %/lexer.l build/%/parser.tab.c
|
||||
# flex -o $@ -s $<
|
||||
# build/%/lexer.yy.c.o: build/%/lexer.yy.c
|
||||
# gcc -c $< -o $@ $(cflags) -Wno-unused-function $(dflags) -I $*
|
||||
|
||||
# Bison parsers (unused since fxconv is written in Python)
|
||||
# build/%/parser.tab.c: %/parser.y
|
||||
# bison $< -o $@ $(bflags)
|
||||
# build/%/parser.tab.c.o: build/%/parser.tab.c
|
||||
# gcc -c $< -o $@ $(cflags) $(dflags) -I $*
|
||||
# Flex lexers for the fxos database
|
||||
build/fxos/lexer-%.yy.c: fxos/lexer-%.l
|
||||
flex -o $@ -s $<
|
||||
build/fxos/lexer-%.yy.c.o: build/fxos/lexer-%.yy.c
|
||||
gcc -c $< -o $@ $(cflags) -Wno-unused-function $(dflags) -I fxos
|
||||
|
||||
#
|
||||
# Dependency system, misc.
|
||||
|
@ -95,10 +90,16 @@ Makefile.cfg:
|
|||
|
||||
install: $(bin)
|
||||
install -d $(PREFIX)/bin
|
||||
install -d $(PREFIX)/share/fxsdk
|
||||
install $(bin) -m 755 $(PREFIX)/bin
|
||||
install fxos/*.txt -m 644 $(PREFIX)/share/fxsdk
|
||||
install fxconv/fxconv-main.py -m 755 $(PREFIX)/bin/fxconv
|
||||
install fxconv/fxconv.py -m 644 $(PREFIX)/bin
|
||||
|
||||
uninstall:
|
||||
rm -f $(PREFIX)/bin/{fxsdk,fxg1a,fxos,fxconv,fxconv.py}
|
||||
rm -rf $(PREFIX)/share/fxsdk
|
||||
|
||||
#
|
||||
# Cleaning
|
||||
#
|
||||
|
|
4
configure
vendored
4
configure
vendored
|
@ -5,7 +5,7 @@
|
|||
#
|
||||
|
||||
# Path parameters
|
||||
PREFIX="/usr"
|
||||
PREFIX="$HOME/.local"
|
||||
# Individual component selection
|
||||
BUILD_fxsdk=1
|
||||
BUILD_fxconv=1
|
||||
|
@ -47,7 +47,7 @@ Install folders:
|
|||
Executables will be installed in <prefix>/bin and runtime data in
|
||||
<prefix>/share/fxsdk.
|
||||
|
||||
--prefix=<prefix> Base install folder [default /usr]
|
||||
--prefix=<prefix> Base install folder [default $HOME/.local]
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
|
22
fxos/analysis.c
Normal file
22
fxos/analysis.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <fxos.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* analysis_short(): Print a one-line summary for an address */
|
||||
void analysis_short(struct os const *os, uint32_t value)
|
||||
{
|
||||
/* Find out whether it is a syscall address */
|
||||
int syscall = os_syscall_find(os, value);
|
||||
|
||||
if(syscall != -1)
|
||||
{
|
||||
printf(" %%%03x", syscall);
|
||||
|
||||
/* Also find out the syscall's name! */
|
||||
struct sys_call const *call = sys_find(syscall);
|
||||
if(call) printf(" %s", call->name);
|
||||
}
|
||||
|
||||
/* Find out any peripheral register address */
|
||||
struct reg_address const *reg = reg_find(value);
|
||||
if(reg) printf(" %s", reg->name);
|
||||
}
|
220
fxos/asm-sh3.txt
Normal file
220
fxos/asm-sh3.txt
Normal file
|
@ -0,0 +1,220 @@
|
|||
# Instruction decoding table: 'sh3'
|
||||
# Format: [01nmdi]{16}, followed by the mnemonic and the list of arguments.
|
||||
# There should be at most one series of each argument letter in the opcode.
|
||||
#
|
||||
# Possible argument strings are predefined and include:
|
||||
# rn rm #imm
|
||||
# jump8 jump12 disp pcdisp
|
||||
# @rn @rm @rn+ @rm+ @-rn
|
||||
# @(disp,rn) @(disp,rm) @(r0,rn) @(r0,rm) @(disp,gbr)
|
||||
#
|
||||
# The disassembler substitutes some elements as follows:
|
||||
# rn -> value of the "n"-sequence
|
||||
# rm -> value of the "m"-sequence
|
||||
# #imm -> value of the "i"-sequence
|
||||
# disp -> value of the "d"-sequence
|
||||
# jump8 -> value of the 8-bit "d"-sequence plus value of PC
|
||||
# jump12 -> value of the 12-bit "d"-sequence plus value of PC
|
||||
# pcdisp -> same as "jump8", but also prints pointed value (for data)
|
||||
|
||||
0000000001001000 clrs
|
||||
0000000000001000 clrt
|
||||
0000000000101000 clrmac
|
||||
0000000000011001 div0u
|
||||
0000000000111000 ldtlb
|
||||
0000000000001001 nop
|
||||
0000000000101011 rte
|
||||
0000000000001011 rts
|
||||
0000000001011000 sets
|
||||
0000000000011000 sett
|
||||
0000000000011011 sleep
|
||||
|
||||
0100nnnn00010101 cmp/pl rn
|
||||
0100nnnn00010001 cmp/pz rn
|
||||
0100nnnn00010000 dt rn
|
||||
0000nnnn00101001 movt rn
|
||||
0100nnnn00000100 rotl rn
|
||||
0100nnnn00000101 rotr rn
|
||||
0100nnnn00100100 rotcl rn
|
||||
0100nnnn00100101 rotcr rn
|
||||
0100nnnn00100000 shal rn
|
||||
0100nnnn00100001 shar rn
|
||||
0100nnnn00000000 shll rn
|
||||
0100nnnn00000001 shlr rn
|
||||
0100nnnn00001000 shll2 rn
|
||||
0100nnnn00001001 shlr2 rn
|
||||
0100nnnn00011000 shll8 rn
|
||||
0100nnnn00011001 shlr8 rn
|
||||
0100nnnn00101000 shll16 rn
|
||||
0100nnnn00101001 shlr16 rn
|
||||
|
||||
0011nnnnmmmm1100 add rm, rn
|
||||
0011nnnnmmmm1110 addc rm, rn
|
||||
0011nnnnmmmm1111 addv rm, rn
|
||||
0010nnnnmmmm1001 and rm, rn
|
||||
0011nnnnmmmm0000 cmp/eq rm, rn
|
||||
0011nnnnmmmm0010 cmp/hs rm, rn
|
||||
0011nnnnmmmm0011 cmp/ge rm, rn
|
||||
0011nnnnmmmm0110 cmp/hi rm, rn
|
||||
0011nnnnmmmm0111 cmp/gt rm, rn
|
||||
0010nnnnmmmm1100 cmp/str rm, rn
|
||||
0011nnnnmmmm0100 div1 rm, rn
|
||||
0010nnnnmmmm0111 div0s rm, rn
|
||||
0011nnnnmmmm1101 dmuls.l rm, rn
|
||||
0011nnnnmmmm0101 dmulu.l rm, rn
|
||||
0110nnnnmmmm1110 exts.b rm, rn
|
||||
0110nnnnmmmm1111 exts.w rm, rn
|
||||
0110nnnnmmmm1100 extu.b rm, rn
|
||||
0110nnnnmmmm1101 extu.w rm, rn
|
||||
0110nnnnmmmm0011 mov rm, rn
|
||||
0000nnnnmmmm0111 mul.l rm, rn
|
||||
0010nnnnmmmm1111 muls.w rm, rn
|
||||
0010nnnnmmmm1110 mulu.w rm, rn
|
||||
0110nnnnmmmm1011 neg rm, rn
|
||||
0110nnnnmmmm1010 negc rm, rn
|
||||
0110nnnnmmmm0111 not rm, rn
|
||||
0010nnnnmmmm1011 or rm, rn
|
||||
0100nnnnmmmm1100 shad rm, rn
|
||||
0100nnnnmmmm1101 shld rm, rn
|
||||
0011nnnnmmmm1000 sub rm, rn
|
||||
0011nnnnmmmm1010 subc rm, rn
|
||||
0011nnnnmmmm1011 subv rm, rn
|
||||
0110nnnnmmmm1000 swap.b rm, rn
|
||||
0110nnnnmmmm1001 swap.w rm, rn
|
||||
0010nnnnmmmm1000 tst rm, rn
|
||||
0010nnnnmmmm1010 xor rm, rn
|
||||
0010nnnnmmmm1101 xtrct rm, rn
|
||||
|
||||
0100mmmm00001110 ldc rm, sr
|
||||
0100mmmm00011110 ldc rm, gbr
|
||||
0100mmmm00101110 ldc rm, vbr
|
||||
0100mmmm00111110 ldc rm, ssr
|
||||
0100mmmm01001110 ldc rm, spc
|
||||
0100mmmm10001110 ldc rm, r0_bank
|
||||
0100mmmm10011110 ldc rm, r1_bank
|
||||
0100mmmm10101110 ldc rm, r2_bank
|
||||
0100mmmm10111110 ldc rm, r3_bank
|
||||
0100mmmm11001110 ldc rm, r4_bank
|
||||
0100mmmm11011110 ldc rm, r5_bank
|
||||
0100mmmm11101110 ldc rm, r6_bank
|
||||
0100mmmm11111110 ldc rm, r7_bank
|
||||
0100mmmm00001010 lds rm, mach
|
||||
0100mmmm00011010 lds rm, macl
|
||||
0100mmmm00101010 lds rm, pr
|
||||
0000nnnn00000010 stc sr, rn
|
||||
0000nnnn00010010 stc gbr, rn
|
||||
0000nnnn00100010 stc vbr, rn
|
||||
0000nnnn00110010 stc ssr, rn
|
||||
0000nnnn01000010 stc spc, rn
|
||||
0000nnnn10000010 stc r0_bank, rn
|
||||
0000nnnn10010010 stc r1_bank, rn
|
||||
0000nnnn10100010 stc r2_bank, rn
|
||||
0000nnnn10110010 stc r3_bank, rn
|
||||
0000nnnn11000010 stc r4_bank, rn
|
||||
0000nnnn11010010 stc r5_bank, rn
|
||||
0000nnnn11100010 stc r6_bank, rn
|
||||
0000nnnn11110010 stc r7_bank, rn
|
||||
0000nnnn00001010 sts mach, rn
|
||||
0000nnnn00011010 sts macl, rn
|
||||
0000nnnn00101010 sts pr, rn
|
||||
|
||||
0100nnnn00101011 jmp @rn
|
||||
0100nnnn00001011 jsr @rn
|
||||
0000nnnn10000011 pref @rn
|
||||
0100nnnn00011011 tas.b @rn
|
||||
0010nnnnmmmm0000 mov.b rm, @rn
|
||||
0010nnnnmmmm0001 mov.w rm, @rn
|
||||
0010nnnnmmmm0010 mov.l rm, @rn
|
||||
0110nnnnmmmm0000 mov.b @rm, rn
|
||||
0110nnnnmmmm0001 mov.w @rm, rn
|
||||
0110nnnnmmmm0010 mov.l @rm, rn
|
||||
0000nnnnmmmm1111 mac.l @rm+, @rn+
|
||||
0100nnnnmmmm1111 mac.w @rm+, @rn+
|
||||
|
||||
0110nnnnmmmm0100 mov.b @rm+, rn
|
||||
0110nnnnmmmm0101 mov.w @rm+, rn
|
||||
0110nnnnmmmm0110 mov.l @rm+, rn
|
||||
|
||||
0100mmmm00000111 ldc.l @rm+, sr
|
||||
0100mmmm00010111 ldc.l @rm+, gbr
|
||||
0100mmmm00100111 ldc.l @rm+, vbr
|
||||
0100mmmm00110111 ldc.l @rm+, ssr
|
||||
0100mmmm01000111 ldc.l @rm+, spc
|
||||
0100mmmm10000111 ldc.l @rm+, r0_bank
|
||||
0100mmmm10010111 ldc.l @rm+, r1_bank
|
||||
0100mmmm10100111 ldc.l @rm+, r2_bank
|
||||
0100mmmm10110111 ldc.l @rm+, r3_bank
|
||||
0100mmmm11000111 ldc.l @rm+, r4_bank
|
||||
0100mmmm11010111 ldc.l @rm+, r5_bank
|
||||
0100mmmm11100111 ldc.l @rm+, r6_bank
|
||||
0100mmmm11110111 ldc.l @rm+, r7_bank
|
||||
0100mmmm00000110 lds.l @rm+, mach
|
||||
0100mmmm00010110 lds.l @rm+, macl
|
||||
0100mmmm00100110 lds.l @rm+, pr
|
||||
|
||||
0010nnnnmmmm0100 mov.b rm, @-rn
|
||||
0010nnnnmmmm0101 mov.w rm, @-rn
|
||||
0010nnnnmmmm0110 mov.l rm, @-rn
|
||||
|
||||
0100nnnn00000011 stc.l sr, @-rn
|
||||
0100nnnn00010011 stc.l gbr, @-rn
|
||||
0100nnnn00100011 stc.l vbr, @-rn
|
||||
0100nnnn00110011 stc.l ssr, @-rn
|
||||
0100nnnn01000011 stc.l spc, @-rn
|
||||
0100nnnn10000011 stc.l r0_bank, @-rn
|
||||
0100nnnn10010011 stc.l r1_bank, @-rn
|
||||
0100nnnn10100011 stc.l r2_bank, @-rn
|
||||
0100nnnn10110011 stc.l r3_bank, @-rn
|
||||
0100nnnn11000011 stc.l r4_bank, @-rn
|
||||
0100nnnn11010011 stc.l r5_bank, @-rn
|
||||
0100nnnn11100011 stc.l r6_bank, @-rn
|
||||
0100nnnn11110011 stc.l r7_bank, @-rn
|
||||
0100nnnn00000010 sts.l mach, @-rn
|
||||
0100nnnn00010010 sts.l macl, @-rn
|
||||
0100nnnn00100010 sts.l pr, @-rn
|
||||
|
||||
10000000nnnndddd mov.b r0, @(disp, rn)
|
||||
10000001nnnndddd mov.w r0, @(disp, rn)
|
||||
0001nnnnmmmmdddd mov.l rm, @(disp, rn)
|
||||
10000100mmmmdddd mov.b @(disp, rm), r0
|
||||
10000101mmmmdddd mov.w @(disp, rm), r0
|
||||
0101nnnnmmmmdddd mov.l @(disp, rm), rn
|
||||
0000nnnnmmmm0100 mov.b rm, @(r0, rn)
|
||||
0000nnnnmmmm0101 mov.w rm, @(r0, rn)
|
||||
0000nnnnmmmm0110 mov.l rm, @(r0, rn)
|
||||
0000nnnnmmmm1100 mov.b @(r0, rm), rn
|
||||
0000nnnnmmmm1101 mov.w @(r0, rm), rn
|
||||
0000nnnnmmmm1110 mov.l @(r0, rm), rn
|
||||
11000000dddddddd mov.b r0, @(disp, gbr)
|
||||
11000001dddddddd mov.w r0, @(disp, gbr)
|
||||
11000010dddddddd mov.l r0, @(disp, gbr)
|
||||
11000100dddddddd mov.b @(disp, gbr), r0
|
||||
11000101dddddddd mov.w @(disp, gbr), r0
|
||||
11000110dddddddd mov.l @(disp, gbr), r0
|
||||
|
||||
11001101iiiiiiii and.b #imm, @(r0, gbr)
|
||||
11001111iiiiiiii or.b #imm, @(r0, gbr)
|
||||
11001100iiiiiiii tst.b #imm, @(r0, gbr)
|
||||
11001110iiiiiiii xor.b #imm, @(r0, gbr)
|
||||
|
||||
1001nnnndddddddd mov.w pcdisp, rn
|
||||
1101nnnndddddddd mov.l pcdisp, rn
|
||||
11000111dddddddd mova pcdisp, r0
|
||||
|
||||
0000mmmm00100011 braf rm
|
||||
0000mmmm00000011 bsrf rm
|
||||
10001011dddddddd bf jump8
|
||||
10001111dddddddd bf/s jump8
|
||||
10001001dddddddd bt jump8
|
||||
10001101dddddddd bt/s jump8
|
||||
1010dddddddddddd bra jump12
|
||||
1011dddddddddddd bsr jump12
|
||||
|
||||
0111nnnniiiiiiii add #imm, rn
|
||||
11001001iiiiiiii and #imm, r0
|
||||
10001000iiiiiiii cmp/eq #imm, r0
|
||||
1110nnnniiiiiiii mov #imm, rn
|
||||
11001011iiiiiiii or #imm, r0
|
||||
11001000iiiiiiii tst #imm, r0
|
||||
11001010iiiiiiii xor #imm, r0
|
||||
11000011iiiiiiii trapa #imm
|
26
fxos/asm-sh4.txt
Normal file
26
fxos/asm-sh4.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Instruction decoding table: 'sh4'
|
||||
# This table is an extension for SH4 processors. See 'asm-sh3.txt' for details
|
||||
# on the format.
|
||||
|
||||
0000nnnn01110011 movco.l r0, @rn
|
||||
0000mmmm01100011 movli.l @rm, r0
|
||||
0100mmmm10101001 movua.l @rm, r0
|
||||
0100mmmm11101001 movua.l @rm+, r0
|
||||
0000nnnn11000011 movca.l r0, @rn
|
||||
|
||||
0000nnnn11100011 icbi @rn
|
||||
0000nnnn10010011 ocbi @rn
|
||||
0000nnnn10100011 ocbp @rn
|
||||
0000nnnn10110011 ocbwb @rn
|
||||
|
||||
0000nnnn11010011 prefi @rn
|
||||
0000000010101011 synco
|
||||
|
||||
0100mmmm00111010 ldc rm, sgr
|
||||
0100mmmm11111010 ldc rm, dbr
|
||||
0100mmmm00110110 ldc.l @rm+, sgr
|
||||
0100mmmm11110110 ldc.l @rm+, dbr
|
||||
0000nnnn00111010 stc sgr, rn
|
||||
0000nnnn11111010 stc dbr, rn
|
||||
0100nnnn00110010 stc.l sgr, @-rn
|
||||
0100nnnn11110010 stc.l dbr, @-rn
|
74
fxos/asm.c
Normal file
74
fxos/asm.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <util.h>
|
||||
#include <string.h>
|
||||
|
||||
/* asm_free_item(): Free an assembly instruction details */
|
||||
static void asm_free_item(void *item)
|
||||
{
|
||||
struct asm_insn *insn = item;
|
||||
free(insn->mnemonic);
|
||||
free(insn->literal1);
|
||||
free(insn->literal2);
|
||||
}
|
||||
|
||||
/* asm_load(): Load an assembly table */
|
||||
void asm_load(char const *file)
|
||||
{
|
||||
err_context("assembly", file, NULL);
|
||||
if(!table_available())
|
||||
{
|
||||
err("too many tables, skipping");
|
||||
err_pop();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Map the file to memory */
|
||||
int fd;
|
||||
size_t size;
|
||||
void *data = map(file, &fd, &size);
|
||||
if(!data) { err_pop(); return; }
|
||||
|
||||
/* If the file is named "asm-x.txt", use "x" as the table name */
|
||||
char *name = match_table_name(file, "asm", ".txt");
|
||||
|
||||
/* Parse the contents; the lexer in is [lexer-asm.l] and the parser is
|
||||
implemented as an automaton with basic error correction. */
|
||||
int count;
|
||||
struct asm_insn *ins = lex_asm(data, size, &count);
|
||||
|
||||
table_create("asm", name, asm_free_item, count, sizeof *ins, ins);
|
||||
|
||||
unmap(data, fd, size);
|
||||
err_pop();
|
||||
}
|
||||
|
||||
/* Global storage for asm_match() */
|
||||
static uint16_t asm_match_opcode;
|
||||
|
||||
/* asm_match(): Check if an instruction matches a pattern */
|
||||
int asm_match(void *item)
|
||||
{
|
||||
struct asm_insn *insn = item;
|
||||
return ((insn->bits ^ asm_match_opcode) & insn->arg_mask) == 0;
|
||||
}
|
||||
|
||||
/* asm_decode(): Match a 16-bit opcode against the assembly database */
|
||||
int asm_decode(uint16_t opcode, struct asm_match *match, int next)
|
||||
{
|
||||
asm_match_opcode = opcode;
|
||||
char const *table;
|
||||
struct asm_insn *insn = table_find("asm", asm_match, &table, next);
|
||||
if(!insn) return 1;
|
||||
|
||||
/* Set match details */
|
||||
match->insn = insn;
|
||||
match->table = table;
|
||||
|
||||
match->n = (opcode >> insn->n_sh) & insn->n_mask;
|
||||
match->m = (opcode >> insn->m_sh) & insn->m_mask;
|
||||
match->d = (opcode >> insn->d_sh) & insn->d_mask;
|
||||
match->i = (opcode >> insn->i_sh) & insn->i_mask;
|
||||
|
||||
return 0;
|
||||
}
|
268
fxos/disassembly.c
Normal file
268
fxos/disassembly.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Architecture we are disassembling for */
|
||||
static enum mpu mpu = MPU_GUESS;
|
||||
/* Current program counter */
|
||||
static uint32_t pc = 0;
|
||||
/* Data chunk under disassembly (whole file) */
|
||||
static uint8_t *data;
|
||||
static size_t len;
|
||||
/* Non-NULL when disassembling an OS */
|
||||
static struct os const *os = NULL;
|
||||
|
||||
/* pcdisp(): Compute the address of a PC-relative displacement
|
||||
@pc Current PC value
|
||||
@disp Displacement value (from opcode)
|
||||
@unit Number of bytes per step (1, 2 or 4), depends on instruction
|
||||
Returns the pointed location. */
|
||||
static uint32_t pcdisp(uint32_t pc, uint32_t disp, int unit)
|
||||
{
|
||||
pc += 4;
|
||||
if(unit == 4) pc &= ~3;
|
||||
|
||||
return pc + disp * unit;
|
||||
}
|
||||
|
||||
/* pcread(): Read data pointed through a PC-relative displacement
|
||||
@pc Current PC value
|
||||
@disp Displacement value (from opcode)
|
||||
@unit Number of bytes per set (also number of bytes read)
|
||||
@out If non-NULL, set to 1 if pointed address is out of the file
|
||||
Returns the value pointed at, an undefined value if out of bounds. */
|
||||
static uint32_t pcread(uint32_t pc, uint32_t disp, int unit, int *out)
|
||||
{
|
||||
/* Take physical addresses */
|
||||
uint32_t addr = pcdisp(pc, disp, unit) & 0x1fffffff;
|
||||
if(out) *out = (addr + unit > len);
|
||||
|
||||
uint32_t value = 0;
|
||||
while(unit--) value = (value << 8) | data[addr++];
|
||||
return value;
|
||||
}
|
||||
|
||||
/* matches(): Count number of matches for a single instruction
|
||||
@opcode 16-bit opcode value
|
||||
Returns the number of matching instructions in the database. */
|
||||
static int matches(uint16_t opcode)
|
||||
{
|
||||
struct asm_match match;
|
||||
int count = 0;
|
||||
|
||||
while(!asm_decode(opcode, &match, count))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void arg_output(int type, char const *literal,
|
||||
struct asm_match const *match, int opsize)
|
||||
{
|
||||
int n = match->n;
|
||||
int m = match->m;
|
||||
int d = match->d;
|
||||
int i = match->i;
|
||||
|
||||
/* Sign extensions of d to 8 and 12 bits */
|
||||
int32_t d8 = (int8_t)d;
|
||||
int32_t d12 = (d & 0x800) ? (int32_t)(d | 0xfffff000) : (d);
|
||||
/* Sign extension of i to 8 bits */
|
||||
int32_t i8 = (int8_t)i;
|
||||
|
||||
int out_of_bounds;
|
||||
uint32_t addr;
|
||||
uint32_t value;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case LITERAL:
|
||||
printf("%s", literal);
|
||||
break;
|
||||
case IMM:
|
||||
printf("#%d", i8);
|
||||
break;
|
||||
case RN:
|
||||
printf("r%d", n);
|
||||
break;
|
||||
case RM:
|
||||
printf("r%d", m);
|
||||
break;
|
||||
case JUMP8:
|
||||
value = pcdisp(pc, d8, 2);
|
||||
printf("<%x", value);
|
||||
if(os) analysis_short(os, value | 0x80000000);
|
||||
printf(">");
|
||||
break;
|
||||
case JUMP12:
|
||||
value = pcdisp(pc, d12, 2);
|
||||
printf("<%x", value);
|
||||
if(os) analysis_short(os, value | 0x80000000);
|
||||
printf(">");
|
||||
break;
|
||||
case PCDISP:
|
||||
addr = pcdisp(pc, d, opsize);
|
||||
value = pcread(pc, d, opsize, &out_of_bounds);
|
||||
|
||||
printf("<%x>", addr);
|
||||
if(out_of_bounds) printf("(out of bounds)");
|
||||
else
|
||||
{
|
||||
printf("(#0x%0*x", opsize * 2, value);
|
||||
if(os) analysis_short(os, value);
|
||||
printf(")");
|
||||
}
|
||||
|
||||
break;
|
||||
case AT_RN:
|
||||
printf("@r%d", n);
|
||||
break;
|
||||
case AT_RM:
|
||||
printf("@r%d", m);
|
||||
break;
|
||||
case AT_RMP:
|
||||
printf("@r%d+", m);
|
||||
break;
|
||||
case AT_RNP:
|
||||
printf("@r%d+", n);
|
||||
break;
|
||||
case AT_MRN:
|
||||
printf("@-r%d", n);
|
||||
break;
|
||||
case AT_DRN:
|
||||
printf("@(%d, r%d)", d * opsize, n);
|
||||
break;
|
||||
case AT_DRM:
|
||||
printf("@(%d, r%d)", d * opsize, m);
|
||||
break;
|
||||
case AT_R0RN:
|
||||
printf("@(r0, r%d)", n);
|
||||
break;
|
||||
case AT_R0RM:
|
||||
printf("@(r0, r%d)", m);
|
||||
break;
|
||||
case AT_DGBR:
|
||||
printf("@(%d, gbr)", d * opsize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void instruction_output(uint16_t opcode, struct asm_match const *match)
|
||||
{
|
||||
char const *mnemonic = match->insn->mnemonic;
|
||||
printf("%6x: %04x %s", pc, opcode, mnemonic);
|
||||
|
||||
/* Find out operation size */
|
||||
|
||||
size_t n = strlen(mnemonic);
|
||||
int opsize = 0;
|
||||
|
||||
if(n >= 3 && mnemonic[n-2] == '.')
|
||||
{
|
||||
int c = mnemonic[n-1];
|
||||
opsize = (c == 'b') + 2 * (c == 'w') + 4 * (c == 'l');
|
||||
}
|
||||
|
||||
/* Output arguments */
|
||||
|
||||
if(!match->insn->arg1) return;
|
||||
printf("%*s", (int)(8-n), "");
|
||||
arg_output(match->insn->arg1, match->insn->literal1, match, opsize);
|
||||
|
||||
if(!match->insn->arg2) return;
|
||||
printf(", ");
|
||||
arg_output(match->insn->arg2, match->insn->literal2, match, opsize);
|
||||
}
|
||||
|
||||
static void instruction_single(uint16_t opcode)
|
||||
{
|
||||
struct asm_match match;
|
||||
asm_decode(opcode, &match, 0);
|
||||
instruction_output(opcode, &match);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void instruction_conflicts(uint16_t opcode, int count)
|
||||
{
|
||||
struct asm_match match;
|
||||
printf("\n # conflicts[%d] on <%x>(%04x)\n", count, pc, opcode);
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
asm_decode(opcode, &match, i);
|
||||
instruction_output(opcode, &match);
|
||||
printf(" # table '%s'\n", match.table);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* disassembly_os(): Disassemble an address or a syscall */
|
||||
void disassembly_os(struct os const *src, struct disassembly const *opt)
|
||||
{
|
||||
/* Initialize this file's global state */
|
||||
mpu = src->mpu;
|
||||
pc = opt->start;
|
||||
data = src->data;
|
||||
len = src->len;
|
||||
os = src;
|
||||
|
||||
/* Override MPU guesses if user requested a specific platform */
|
||||
if(opt->mpu != MPU_GUESS) mpu = opt->mpu;
|
||||
|
||||
/* Handle situations where the start address is a syscall */
|
||||
if(opt->syscall)
|
||||
{
|
||||
pc = os_syscall(os, opt->start);
|
||||
if(pc == (uint32_t)-1)
|
||||
{
|
||||
err("syscall 0x%04x does not exist", opt->start);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Take physical addresses */
|
||||
pc &= 0x1fffffff;
|
||||
|
||||
/* Cut the length if it reaches past the end of the file */
|
||||
uint32_t limit = (pc + opt->len) & ~1;
|
||||
if(limit > os->len) limit = os->len;
|
||||
|
||||
/* Enforce alignment of PC */
|
||||
if(pc & 1)
|
||||
{
|
||||
err("address is not 2-aligned, skipping 1 byte");
|
||||
pc += 1;
|
||||
}
|
||||
|
||||
uint8_t *data = os->data;
|
||||
|
||||
while(pc < limit)
|
||||
{
|
||||
if(os)
|
||||
{
|
||||
int syscall = os_syscall_find(os, pc | 0x80000000);
|
||||
if(syscall == -1)
|
||||
syscall = os_syscall_find(os, pc | 0xa0000000);
|
||||
if(syscall != -1)
|
||||
{
|
||||
struct sys_call const *s = sys_find(syscall);
|
||||
printf("\n<%x %%%03x", pc, syscall);
|
||||
if(s) printf(" %s", s->name);
|
||||
printf(">\n");
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t opcode = (data[pc] << 8) | data[pc + 1];
|
||||
int count = matches(opcode);
|
||||
|
||||
if(count == 0) printf("%6x: %04x\n", pc, opcode);
|
||||
else if(count == 1) instruction_single(opcode);
|
||||
else instruction_conflicts(opcode, count);
|
||||
|
||||
pc += 2;
|
||||
}
|
||||
}
|
84
fxos/errors.c
Normal file
84
fxos/errors.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
#include <errors.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define MAX 32
|
||||
|
||||
/* Array of context strings. */
|
||||
static char const *context[MAX] = { NULL };
|
||||
/* Number of active elements. */
|
||||
static int elements = 0;
|
||||
|
||||
/* push(): Push an element in the context buffer
|
||||
@el New element
|
||||
Returns non-zero if the buffer is full. */
|
||||
static int push(char const *el)
|
||||
{
|
||||
if(elements >= MAX - 2) return 1;
|
||||
context[elements++] = el;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* err_context(): Push one or more context elements */
|
||||
int err_context(char const *context, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, context);
|
||||
int x = 0;
|
||||
|
||||
/* Delimiter between calls to err_context(), for err_pop() */
|
||||
x |= push(NULL);
|
||||
x |= push(context);
|
||||
|
||||
while(1)
|
||||
{
|
||||
char const *el = va_arg(args, char const *);
|
||||
if(!el) break;
|
||||
x |= push(el);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* err_pop(): Pop back context elements */
|
||||
void err_pop(void)
|
||||
{
|
||||
/* Clear everything until the last NULL delimiter */
|
||||
while(--elements >= 0 && context[elements])
|
||||
{
|
||||
context[elements] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void err_debug(void)
|
||||
{
|
||||
for(int i = 0; i < MAX; i++) fprintf(stderr, "%s: ", context[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* errf(): Emit an error message */
|
||||
void errf(int flags, char const *str, ...)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
|
||||
for(int i = 0; i <= MAX-2 && (context[i] || context[i+1]); i++)
|
||||
{
|
||||
if(context[i]) fprintf(stderr, "%s: ", context[i]);
|
||||
}
|
||||
|
||||
vfprintf(stderr, str, args);
|
||||
|
||||
if(flags & ERR_ERRNO)
|
||||
{
|
||||
fprintf(stderr, ": %s", strerror(saved_errno));
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
}
|
63
fxos/errors.h
Normal file
63
fxos/errors.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
//---
|
||||
// errors: Error message management
|
||||
//
|
||||
// An attempt at producing elaborate error messages providing context from
|
||||
// multiple function calls, with a small amount of code.
|
||||
//
|
||||
// Basically, caller functions define context and message parameters
|
||||
// before doing anything risky. When an error occurs in a sub-function,
|
||||
// the context is used to prepend relevant information and fill in the
|
||||
// error message where relevant.
|
||||
//
|
||||
// This means that the caller functions must know it advance what kind of
|
||||
// messages can be emitted to accurately set the context. Although it
|
||||
// would work through library calls, it is not very suitable. It's rather
|
||||
// meant for the logic of applications.
|
||||
//---
|
||||
|
||||
#ifndef FXOS_ERRORS
|
||||
#define FXOS_ERRORS
|
||||
|
||||
/* Error levels */
|
||||
#define ERR_CRIT 0x01 /* Aborts part or whole of the program's task */
|
||||
#define ERR_ERR 0x02 /* Unexpected behavior */
|
||||
#define ERR_WARN 0x03 /* Internal consistency issues */
|
||||
#define ERR_LOG 0x04 /* Internal logging */
|
||||
/* Error flags */
|
||||
#define ERR_ERRNO 0x10
|
||||
|
||||
/* err_context(): Push one or more context elements
|
||||
@context Context string, must live until it is popped by err_pop()
|
||||
@... More contexts, same requirements as the first (NULL-terminated)
|
||||
Returns non-zero if the deepest context level (at least 15) is reached. */
|
||||
int err_context(char const *context, ...);
|
||||
|
||||
/* err_pop(): Pop back context elements
|
||||
Pops back all context elements that were added by the previous call to
|
||||
err_context(), no matter their number. */
|
||||
void err_pop(void);
|
||||
|
||||
/* errf(): Emit an error message
|
||||
Error message is printed via fprintf() and supports the same format. All the
|
||||
arguments are passed directly.
|
||||
|
||||
Available flags are any combination of at most one error level:
|
||||
ERR_CRIT -- Unrecoverable error
|
||||
ERR_ERR -- Normal error
|
||||
ERR_WARN -- Warning
|
||||
ERR_LOG -- Logging
|
||||
and any of these boolean flags:
|
||||
ERR_ERRNO -- Also print strerror(errno) as a suffix (as perror()).
|
||||
|
||||
Error levels might be used later on for filtering. Messages without level
|
||||
will always be displayed.
|
||||
|
||||
@flags An OR-combination of the previous flags, or 0
|
||||
@str Error messages
|
||||
@... Arguments to format [str] through fprintf() */
|
||||
void errf(int flags, char const *str, ...);
|
||||
|
||||
/* err(): Short error function */
|
||||
#define err(str, ...) errf(0, str __VA_OPT__(,) __VA_ARGS__)
|
||||
|
||||
#endif /* FXOS_ERRORS */
|
446
fxos/fxos.h
446
fxos/fxos.h
|
@ -6,149 +6,405 @@
|
|||
#define FX_FXOS
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Microprocessor platforms */
|
||||
enum mpu
|
||||
{
|
||||
mpu_unknown = 0,
|
||||
mpu_sh7705 = 1,
|
||||
mpu_sh7305 = 2,
|
||||
enum mpu {
|
||||
MPU_GUESS = 0,
|
||||
MPU_SH7705 = 1,
|
||||
MPU_SH7305 = 2,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Data tables (tables.c)
|
||||
** Memory (memory.c)
|
||||
*/
|
||||
|
||||
/* tables_add_asm(): Append an instruction table to the table list
|
||||
This function adds a new instruction table to fetch instructions from; it
|
||||
will be consulted if searching any of the previously-declared tables fails.
|
||||
|
||||
@filename Name of instruction table file
|
||||
Returns non-zero on error (and prints a message on stderr) */
|
||||
int tables_add_asm(const char *filename);
|
||||
|
||||
/* tables_add_syscall(): Append a syscall table to the table list
|
||||
This function adds a new syscall table to fetch syscalls information from;
|
||||
if will be consulted if searching any of the previously-declared tables
|
||||
fails.
|
||||
|
||||
@filename Name of instruction table file
|
||||
Returns non-zero on error (and prints a message on stderr) */
|
||||
int tables_add_syscall(const char *filename);
|
||||
|
||||
|
||||
/*
|
||||
** RAM dumps (ram.c)
|
||||
*/
|
||||
|
||||
/* Region for a single RAM dump */
|
||||
/* struct region: A valid memory region for at least one platform */
|
||||
struct region
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
void *data;
|
||||
uint32_t start; /* Start address */
|
||||
uint32_t end; /* End address */
|
||||
char const *name; /* Name, used to identify RAM dump files */
|
||||
enum mpu platform; /* Platform hint or MPU_GUESS */
|
||||
};
|
||||
|
||||
/* RAM dump */
|
||||
struct ram_sh7705
|
||||
{
|
||||
struct region RAM; /* Usual RAM (256k) */
|
||||
/* memory_region(): Find the region where an address is located
|
||||
Returns NULL if the address points to no valid memory. This function rejects
|
||||
addresses of peripheral registers in P3 or P4 space and only heeds for
|
||||
contiguous RAM or ROM areas.
|
||||
|
||||
@address 32-bit virtual memory address
|
||||
Returns a region description matching the address, NULL if none is known.*/
|
||||
struct region const *memory_region(uint32_t address);
|
||||
|
||||
/*
|
||||
** General table storage (tables.c)
|
||||
*/
|
||||
|
||||
/* struct table: Parametric data table */
|
||||
struct table {
|
||||
char const *type; /* Table type, set by user */
|
||||
char *name; /* Table name, also set by user */
|
||||
void (*free_item)(void *); /* Function to free individual items */
|
||||
|
||||
int count; /* Number of items in the table */
|
||||
size_t size; /* Size of each item */
|
||||
void *items; /* Table data */
|
||||
};
|
||||
struct ram_sh7305
|
||||
{
|
||||
struct region RAM; /* Usual RAM (512k) */
|
||||
struct region IL; /* On-chip instruction storage (16k) */
|
||||
struct region RS; /* On-chip generic storage (2k) */
|
||||
|
||||
/* table_available(): Whether a table can be allocated
|
||||
Returns non-zero if there is space left for a new table, zero if not. */
|
||||
int table_available(void);
|
||||
|
||||
/* table_create(): Create a new table
|
||||
Allocates a new table inside the global storage. The created table can be
|
||||
searched immediately with table_find().
|
||||
|
||||
@type Table type, expectedly a string constant
|
||||
@name Name string, this module takes ownership and will free() it
|
||||
@free_item Function to use to destroy items in the future
|
||||
@count Number of items
|
||||
@size Size of each item
|
||||
@items Full data array */
|
||||
void table_create(char const *type, char *name, void (*free_item)(void *),
|
||||
int count, size_t size, void *items);
|
||||
|
||||
/* table_find(): Find matching entries in the database tables
|
||||
|
||||
This function traverses all the tables of type @type and returns all the
|
||||
elements [e] such that [match(e)] is non-zero.
|
||||
|
||||
The search starts with [next=0] and returns the first match; further calls
|
||||
with [next!=0] will return more matching elements until no more are found
|
||||
(in which case this function returns NULL) or this function is called again
|
||||
with [next=0] to start a new search.
|
||||
|
||||
@type Table filter by type
|
||||
@match Match function
|
||||
@name Set to matching table name, if not NULL
|
||||
@next Set it to 0 on the first call, and non-zero after that
|
||||
Returns a match if one is found, NULL otherwise. */
|
||||
void *table_find(char const *type, int (*match)(void *), char const **name,
|
||||
int next);
|
||||
|
||||
|
||||
/*
|
||||
** Assembly tables (asm.c, lexer-asm.l)
|
||||
** These tables reference all assembler instructions used by fxos to
|
||||
** disassemble code. In case of conflict, fxos will disassemble the same
|
||||
** opcode several times.
|
||||
*/
|
||||
|
||||
/* struct asm_insn: Entry of an instruction table */
|
||||
struct asm_insn {
|
||||
uint16_t bits; /* Opcode; arbitrary values for arguments */
|
||||
uint16_t arg_mask; /* 1 for constant bits, 0 for arguments */
|
||||
|
||||
/* Position of the arguments */
|
||||
uint8_t n_sh, m_sh, d_sh, i_sh;
|
||||
/* Masks indicating the length of arguments */
|
||||
uint16_t n_mask, m_mask, d_mask, i_mask;
|
||||
|
||||
char *mnemonic; /* NUL-terminated mnemonic */
|
||||
|
||||
int arg1; /* asm_arg member */
|
||||
int arg2; /* asm_arg member */
|
||||
|
||||
char *literal1; /* When arg1 == LITERAL, argument string */
|
||||
char *literal2; /* When arg2 == LITERAL, argument string */
|
||||
};
|
||||
|
||||
/* enum asm_arg: Argument variants */
|
||||
enum asm_arg {
|
||||
LITERAL=1, /* Literal string, eg. "vbr" or "@(r0, gbr)" */
|
||||
IMM, RN, RM, /* "#imm", "rn", "rm" */
|
||||
JUMP8, JUMP12, /* Jump from displacement (PC + disp) */
|
||||
PCDISP, /* PC-displacement with data */
|
||||
AT_RN, AT_RM, /* "@rn", "@rm" */
|
||||
AT_RMP, AT_RNP, AT_MRN, /* Post-increment and pre-decrement */
|
||||
AT_DRN, AT_DRM, /* Displacement structure addressing */
|
||||
AT_R0RN, AT_R0RM, /* r0 structure addressing */
|
||||
AT_DGBR, /* GBR addressing */
|
||||
};
|
||||
|
||||
/* struct asm_match: Matching of a 16-bit code against an instruction
|
||||
Specifies the source instruction and the value of the parameters. The value
|
||||
of [m], [n], [d] or [i] is unspecified for parameters that are not used in
|
||||
the matched instruction's opcode. */
|
||||
struct asm_match {
|
||||
/* Matching instruction */
|
||||
struct asm_insn const *insn;
|
||||
|
||||
char const *table; /* Table name */
|
||||
int m, n, d, i; /* Parameter assignment */
|
||||
};
|
||||
|
||||
/* asm_load(): Load an assembly table
|
||||
Loads all instructions described by @file into a table named "x" is @file's
|
||||
basename is on the form "asm-x.txt" and the whole basename otherwise. The
|
||||
resulting table is available immediately to use with asm_match().
|
||||
|
||||
Skips every row that does not conform to the file's syntax after printing a
|
||||
message to stderr.
|
||||
|
||||
@file Input file path */
|
||||
void asm_load(char const *file);
|
||||
|
||||
/* asm_decode(): Match a 16-bit opcode against the assembly database
|
||||
This function searches matches of a 16-bit instruction code inside the
|
||||
instruction database. Depending on the database files currently loaded,
|
||||
there can be several matches; this function uses static variables to
|
||||
maintain state information through several calls.
|
||||
|
||||
First call this function with [next] set to 0. If there is no match, the
|
||||
call will return non-zero and [*match] will be left unchanged. Otherwise,
|
||||
the first matching instruction will be described in [*match], the call will
|
||||
return 0 and internal static variables will be reset.
|
||||
|
||||
Repeatedly call this function with [next != 0] to get further matches. The
|
||||
search ends when there are no more matches, in which case this function
|
||||
returns non-zero and [*match] is left unchanged. Any non-zero value for
|
||||
[next] is suitable.
|
||||
|
||||
The name of the table providing the match is set in [match->table]. Please
|
||||
bear in mind, though, that table names do not uniquely identify tables.
|
||||
|
||||
@opcode 16-bit opcode to be matched against the database
|
||||
@match Set to a description of the matching instruction (must not be NULL)
|
||||
@next Set it to 0 on the first call, and non-zero after that
|
||||
Returns 0 if a match is found, non-zero otherwise. */
|
||||
int asm_decode(uint16_t opcode, struct asm_match *match, int next);
|
||||
|
||||
/* asm_quit(): Unload all assembly tables
|
||||
Releases all memory held by the assembly table database. */
|
||||
void asm_quit(void);
|
||||
|
||||
/* lex_asm(): Assembly table lexer and parser
|
||||
Lexes and parses string @data of length @length, allocating and filling an
|
||||
instruction array whose size is stored in [*count] if @count is non-NULL.
|
||||
Prints messages to stderr for every syntax error in the file.
|
||||
|
||||
@data Input memory, not NUL-terminated (typically a memory-mapped file)
|
||||
@length Length of input string
|
||||
@count Set to number of successfully decoded instructions if non-NULL
|
||||
Returns a free()able array of decoded instructions. */
|
||||
struct asm_insn *lex_asm(void *data, size_t length, int *count);
|
||||
|
||||
|
||||
/*
|
||||
** Syscall tables (sys.c)
|
||||
*/
|
||||
|
||||
/* struct sys_call: Entry of a syscall table */
|
||||
struct sys_call {
|
||||
uint32_t number; /* Syscall number */
|
||||
char *name; /* Symbol or function name */
|
||||
char *descr; /* Prototype or description */
|
||||
};
|
||||
|
||||
/* sys_load(): Load a syscall table
|
||||
Loads a syscall description table. If @file is named "sys-x.txt" then the
|
||||
table name is set to "x", otherwise @file's basename.
|
||||
Prints syntax errors and skips invalid lines.
|
||||
|
||||
@file Input file path */
|
||||
void sys_load(char const *path);
|
||||
|
||||
/* sys_find(): Find information on a given syscall number
|
||||
Traverse the syscall tables currently loaded and returns the first entry
|
||||
matching the provided syscall number, if any is found.
|
||||
|
||||
@number Syscall number
|
||||
Returns a description of the syscall, NULL if none was found. */
|
||||
struct sys_call const *sys_find(uint32_t number);
|
||||
|
||||
/* sys_quit(): Release memory held by the syscall tables */
|
||||
void sys_quit(void);
|
||||
|
||||
/* lex_sys(): Syscall table lexer and parser
|
||||
Lexes and parses string @data of length @len, allocating and filling a
|
||||
syscall array whose size is stored in [*count] if @count is not NULL.
|
||||
Prints syntax errors on stderr.
|
||||
|
||||
@data Input memory (typically memory-mapped file)
|
||||
@len Length of input
|
||||
@count Set to number of decoded entries if not NULL
|
||||
Returns a free()able table of decoded syscall entries. */
|
||||
struct sys_call *lex_sys(void *data, size_t len, int *count);
|
||||
|
||||
|
||||
/*
|
||||
** Peripheral register tables (reg.c)
|
||||
*/
|
||||
|
||||
/* struct reg_address: Entry of a peripheral register table */
|
||||
struct reg_address {
|
||||
uint32_t address; /* Register address */
|
||||
char *name; /* Typically an upper-case dotted specifier */
|
||||
};
|
||||
|
||||
|
||||
/* reg_load(): Load a peripheral register table
|
||||
Loads a peripheral register listing. If @file is named "reg-x.txt" then the
|
||||
table name is set to "x", otherwise @file's basename.
|
||||
Prints syntax errors and skips invalid lines. Loaded data is available
|
||||
immediately through reg_find().
|
||||
|
||||
@file Input file path */
|
||||
void reg_load(char const *path);
|
||||
|
||||
/* reg_find(): Find information on a given peripheral register address
|
||||
Looks up the loaded tables and returns the first entry matching the given
|
||||
address (if any).
|
||||
|
||||
@address Any input address
|
||||
Returns a pointer to the matching register, NULL if none was found. */
|
||||
struct reg_address const *reg_find(uint32_t address);
|
||||
|
||||
/* reg_quit(): Release memory held by the peripheral register tables */
|
||||
void reg_quit(void);
|
||||
|
||||
/* lex_reg(): Peripheral register table lexer and parser
|
||||
Lexes and parses @data (of length @length). Allocates and fills a register
|
||||
description array and stores its size in [*count] if @count is not NULL.
|
||||
Prints messages on stderr if there are syntax errors.
|
||||
|
||||
@data Input string (needs not be NUL-terminated)
|
||||
@len Length of input
|
||||
@count Set to the number of decoded register addresses, if not NULL
|
||||
Returns a free()able table with the decoded data. */
|
||||
struct reg_address *lex_reg(void *data, size_t len, int *count);
|
||||
|
||||
|
||||
/*
|
||||
** General OS operations (os.c)
|
||||
*/
|
||||
|
||||
/* struct os: Basic OS information */
|
||||
struct os {
|
||||
void *data; /* Operating system dump */
|
||||
size_t len; /* File length */
|
||||
int fd; /* Underlying file descriptor */
|
||||
|
||||
char version[15]; /* NUL-terminated OS version string */
|
||||
enum mpu mpu; /* User-provided or guessed MPU type */
|
||||
|
||||
uint32_t syscall_table; /* Syscall table address */
|
||||
int syscalls; /* Number of valid syscalls found */
|
||||
|
||||
uint32_t footer; /* Footer address (-1 if not found) */
|
||||
};
|
||||
|
||||
/* os_load(): Load an OS file and find out basic properties
|
||||
Guesses the MPU type, finds the syscall table and its size, finds the footer
|
||||
address.
|
||||
|
||||
@path File path
|
||||
@os Will be filled with loaded data and information
|
||||
Returns non-zero in case of loading error or file format error. */
|
||||
int os_load(char const *path, struct os *os);
|
||||
|
||||
/* os_syscall(): Get the address of a syscall entry
|
||||
Does not check bounds, only returns (uint32_t)-1 if the requested entry of
|
||||
the table is past the end of the file.
|
||||
|
||||
@os Source OS
|
||||
@syscall Syscall entry number
|
||||
Returns the syscall address. */
|
||||
uint32_t os_syscall(struct os const *os, int syscall);
|
||||
|
||||
/* os_syscall_find(): Find a syscall which points to an address
|
||||
This function looks for a syscall entry (among the ones that point to valid
|
||||
memory) whose value is @entry.
|
||||
|
||||
@os Loaded OS structure
|
||||
@entry Researched value
|
||||
Returns a syscall ID if some is found, -1 otherwise. */
|
||||
int os_syscall_find(struct os const *os, uint32_t entry);
|
||||
|
||||
/* os_free(): Free an OS file opened with os_load()
|
||||
@os Loaded OS structure */
|
||||
void os_free(struct os const *os);
|
||||
|
||||
|
||||
/*
|
||||
** File identification (info.c)
|
||||
*/
|
||||
|
||||
/* Info options */
|
||||
struct info
|
||||
{
|
||||
/* OS file (0) or binary file (1) */
|
||||
int binary;
|
||||
/* Force underlying architecture */
|
||||
enum mpu mpu;
|
||||
/* info_os(): Print general information on an OS file
|
||||
|
||||
/* RAM dumps, if any */
|
||||
union {
|
||||
struct ram_sh7705 ram3;
|
||||
struct ram_sh7305 ram4;
|
||||
};
|
||||
};
|
||||
This function prints the OS metadata, traverses the syscall table, and
|
||||
shows a few details of known binary regions such as the footer.
|
||||
|
||||
@os Input OS file */
|
||||
void info_os(struct os const *os);
|
||||
|
||||
/* info_binary(): Print general information on a binary file
|
||||
|
||||
This function tries to determine the platform by looking for SH4-only
|
||||
instructions or SH7705 and SH7305-specific registers addresses. The analysis
|
||||
results are printed on stdout.
|
||||
|
||||
@data Input file data (memory-mapped)
|
||||
@len Length of input */
|
||||
void info_binary(void *data, size_t len);
|
||||
|
||||
|
||||
/*
|
||||
** Disassembling (disassembly.c)
|
||||
*/
|
||||
|
||||
/* Disassembly options */
|
||||
/* struct disassembly: Disassembly options */
|
||||
struct disassembly
|
||||
{
|
||||
/* OS file (0) or binary file (1) */
|
||||
int binary;
|
||||
/* Force underlying architecture */
|
||||
enum mpu mpu;
|
||||
int binary; /* OS file (0) or binary file (1) */
|
||||
enum mpu mpu; /* Force architecture (or MPU_GUESS) */
|
||||
|
||||
/* RAM dumps, if any */
|
||||
union {
|
||||
struct ram_sh7705 ram3;
|
||||
struct ram_sh7305 ram4;
|
||||
};
|
||||
|
||||
/* Start address */
|
||||
uint32_t start;
|
||||
/* Length of disassembled region */
|
||||
uint32_t length;
|
||||
uint32_t start; /* Start address or syscall ID */
|
||||
int syscall; /* Non-zero if [start] is a syscall ID */
|
||||
uint32_t len; /* Length of disassembled region */
|
||||
};
|
||||
|
||||
/* disassembly_os(): Disassemble an address or a syscall
|
||||
Produces a disassembly listing of the program on stdout, annotated with
|
||||
every piece of information that can be extracted from the OS.
|
||||
|
||||
@os Operating system image to disassemble
|
||||
@opt Disassembly region and options */
|
||||
void disassembly_os(struct os const *os, struct disassembly const *opt);
|
||||
|
||||
|
||||
/*
|
||||
** Blind analysis (analysis.c)
|
||||
*/
|
||||
|
||||
/* Analysis options */
|
||||
/* analysis_short(): Print a one-line summary for an address
|
||||
Prints a list of space-separated elements summarizing the information that
|
||||
can be found about the provided value (typically an address). This summary
|
||||
is often inserted in disassembled code as annotation.
|
||||
|
||||
@os Source OS
|
||||
@value Analyzed value, often an address */
|
||||
void analysis_short(struct os const *os, uint32_t value);
|
||||
|
||||
/* struct analysis: In-depth analysis options */
|
||||
struct analysis
|
||||
{
|
||||
/* Force underlying architecture */
|
||||
enum mpu mpu;
|
||||
|
||||
/* RAM dumps, if any */
|
||||
union {
|
||||
struct ram_sh7705 ram3;
|
||||
struct ram_sh7305 ram4;
|
||||
};
|
||||
|
||||
/* Analysis mode */
|
||||
enum {
|
||||
ANALYSIS_FULL = 0,
|
||||
ANALYSIS_SYSCALL = 1,
|
||||
ANALYSIS_ADDRESS = 2,
|
||||
ANALYSIS_REGISTER = 3,
|
||||
ANALYSIS_SYSCALL = 0x01,
|
||||
ANALYSIS_ADDRESS = 0x02,
|
||||
ANALYSIS_REGISTER = 0x04,
|
||||
|
||||
ANALYSIS_FULL = 0x07,
|
||||
} type;
|
||||
|
||||
/* Max number of printed occurrences */
|
||||
int occurrences;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Utility functions (util.c)
|
||||
*/
|
||||
|
||||
/* integer(): Convert base 8, 10 or 16 into integers
|
||||
Prints an error message and sets *error to 1 in case of conversion error or
|
||||
overflow.
|
||||
|
||||
@str Original integer representation ("10", "0x1f", "07")
|
||||
@error Set to 1 on error, otherwise unchanged (can be NULL)
|
||||
Returns result of conversion (valid if *error is not 1) */
|
||||
long long integer(const char *str, int *error);
|
||||
|
||||
#endif /* FX_FXOS */
|
||||
|
|
120
fxos/info.c
Normal file
120
fxos/info.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <endian.h>
|
||||
|
||||
char const *info_str =
|
||||
"Header information:\n"
|
||||
" Bootcode timestamp (DateA) (0x8000ffb0) : %s\n"
|
||||
" Serial number (0x8000ffd0) : %s\n"
|
||||
" Bootcode checksum (0x8000fffc) : 0x%s\n"
|
||||
" OS version (0x80010020) : %s\n";
|
||||
|
||||
char const *footer_str =
|
||||
"\nFooter information:\n"
|
||||
" Detected footer address : 0x8%07x\n"
|
||||
" Langdata entries found : %d\n"
|
||||
" OS date (DateO) (0x8%07x)" " : %s\n"
|
||||
" OS checksum (0x8%07x)" " : 0x%s\n";
|
||||
|
||||
char const *syscall_str =
|
||||
"\nSyscall information:\n"
|
||||
" Syscall table address (0x8001007c) : 0x%08x\n"
|
||||
" Entries that point to valid memory : 0x%x\n"
|
||||
" First seemingly invalid entry : 0x%08x\n"
|
||||
" Syscall entries outside ROM:\n";
|
||||
|
||||
char const *syscall_nonrom_str =
|
||||
" %%%04x -> 0x%08x (%s memory)\n";
|
||||
|
||||
/* extract_str(): Extract a string from the OS file
|
||||
This function checks offsets and bounds and writes "(eof)" if the provided
|
||||
file is too small for the tested offset. */
|
||||
static void extract_str(struct os const * os, uint32_t address, size_t size,
|
||||
char *dst)
|
||||
{
|
||||
if(address + size > os->len)
|
||||
{
|
||||
strcpy(dst, "(eof)");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dst, os->data + address, size);
|
||||
dst[size] = 0;
|
||||
}
|
||||
|
||||
/* extract_int(): Extract a string from the OS file */
|
||||
static void extract_int(struct os const *os, uint32_t address, char *dst)
|
||||
{
|
||||
if(address + 4 > os->len)
|
||||
{
|
||||
strcpy(dst, "(eof)");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t x;
|
||||
memcpy(&x, os->data + address, 4);
|
||||
x = be32toh(x);
|
||||
sprintf(dst, "%08x", x);
|
||||
}
|
||||
|
||||
/* info_os(): Print general information on an OS file */
|
||||
void info_os(struct os const *os)
|
||||
{
|
||||
void *data = os->data;
|
||||
size_t len = os->len;
|
||||
|
||||
char bios_timestamp[15];
|
||||
extract_str(os, 0xffb0, 14, bios_timestamp);
|
||||
|
||||
char serial[9];
|
||||
extract_str(os, 0xffd0, 8, serial);
|
||||
|
||||
char bios_checksum[9];
|
||||
extract_int(os, 0xfffc, bios_checksum);
|
||||
|
||||
printf(info_str, bios_timestamp, serial, bios_checksum, os->version);
|
||||
|
||||
if(os->footer == (uint32_t)-1)
|
||||
{
|
||||
printf("\nFooter could not be found.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t addr = os->footer + 8;
|
||||
int langdata = 0;
|
||||
|
||||
while(addr + 8 < len && !memcmp(data + addr, "Langdata", 8))
|
||||
{
|
||||
langdata++;
|
||||
addr += 0x30;
|
||||
}
|
||||
|
||||
char os_timestamp[15];
|
||||
extract_str(os, addr, 14, os_timestamp);
|
||||
|
||||
char os_checksum[9];
|
||||
extract_int(os, addr + 0x18, os_checksum);
|
||||
|
||||
printf(footer_str, os->footer, langdata, addr, os_timestamp,
|
||||
addr + 0x18, os_checksum);
|
||||
}
|
||||
|
||||
printf(syscall_str, os->syscall_table, os->syscalls,
|
||||
os_syscall(os, os->syscalls));
|
||||
|
||||
int total = 0;
|
||||
for(int i = 0; i < os->syscalls; i++)
|
||||
{
|
||||
uint32_t e = os_syscall(os, i);
|
||||
struct region const *r = memory_region(e);
|
||||
if(!r || !strcmp(r->name, "ROM")) continue;
|
||||
|
||||
printf(syscall_nonrom_str, i, e, r->name);
|
||||
total++;
|
||||
}
|
||||
|
||||
if(!total) printf(" (none)\n");
|
||||
}
|
187
fxos/lexer-asm.l
Normal file
187
fxos/lexer-asm.l
Normal file
|
@ -0,0 +1,187 @@
|
|||
%{
|
||||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <util.h>
|
||||
|
||||
/* Text value for parser */
|
||||
static char *yylval;
|
||||
|
||||
%}
|
||||
|
||||
%option prefix="asm"
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
|
||||
code ^[01nmdi]{16}
|
||||
literal [^ ,\t\n]+|[^ ,\t\n(]*"("[^")"\n]*")"[^ ,\t\n]*
|
||||
|
||||
space [ \t]+
|
||||
|
||||
%%
|
||||
|
||||
^#[^\n]* ;
|
||||
{space} ;
|
||||
, ;
|
||||
[\n] yylineno++;
|
||||
|
||||
{code} { yylval = strdup(yytext); return 0; }
|
||||
^.{0,16} { err("%d: invalid opcode at start of line", yylineno); }
|
||||
|
||||
"#imm" { return IMM; }
|
||||
"rn" { return RN; }
|
||||
"rm" { return RM; }
|
||||
"jump8" { return JUMP8; }
|
||||
"jump12" { return JUMP12; }
|
||||
"pcdisp" { return PCDISP; }
|
||||
"@rn" { return AT_RN; }
|
||||
"@rm" { return AT_RM; }
|
||||
"@rm+" { return AT_RMP; }
|
||||
"@rn+" { return AT_RNP; }
|
||||
"@-rn" { return AT_MRN; }
|
||||
"@(disp,"[ ]*"rn)" { return AT_DRN; }
|
||||
"@(disp,"[ ]*"rm)" { return AT_DRM; }
|
||||
"@(r0,"[ ]*"rn)" { return AT_R0RN; }
|
||||
"@(r0,"[ ]*"rm)" { return AT_R0RM; }
|
||||
"@(disp",[ ]*"gbr)" { return AT_DGBR; }
|
||||
{literal} { yylval = strdup(yytext); return LITERAL; }
|
||||
|
||||
<<EOF>> { return -1; }
|
||||
|
||||
%%
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* set_code(): Build an efficient representation of an opcode
|
||||
Takes a 16-byte string as argument, representing the parameterized opcode,
|
||||
and computes a bit-based representation inside the assembly structure.
|
||||
|
||||
@code 16-bit opcode made of '0', '1', 'm', 'n', 'd' and 'i'
|
||||
@insn Instruction object */
|
||||
void set_code(char const *code, struct asm_insn *insn)
|
||||
{
|
||||
insn->bits = insn->arg_mask = 0;
|
||||
insn->n_sh = insn->n_mask = 0;
|
||||
insn->m_sh = insn->m_mask = 0;
|
||||
insn->d_sh = insn->d_mask = 0;
|
||||
insn->i_sh = insn->i_mask = 0;
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
int c = code[i];
|
||||
|
||||
/* Constant bits */
|
||||
if(c == '0' || c == '1')
|
||||
{
|
||||
insn->bits = (insn->bits << 1) | (c - '0');
|
||||
insn->arg_mask <<= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Argument bits */
|
||||
insn->bits <<= 1;
|
||||
insn->arg_mask = (insn->arg_mask << 1) | 1;
|
||||
|
||||
if(c == 'n')
|
||||
{
|
||||
insn->n_sh = 15 - i;
|
||||
insn->n_mask = (insn->n_mask << 1) | 1;
|
||||
}
|
||||
if(c == 'm')
|
||||
{
|
||||
insn->m_sh = 15 - i;
|
||||
insn->m_mask = (insn->m_mask << 1) | 1;
|
||||
}
|
||||
if(c == 'd')
|
||||
{
|
||||
insn->d_sh = 15 - i;
|
||||
insn->d_mask = (insn->d_mask << 1) | 1;
|
||||
}
|
||||
if(c == 'i')
|
||||
{
|
||||
insn->i_sh = 15 - i;
|
||||
insn->i_mask = (insn->i_mask << 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
insn->arg_mask = ~insn->arg_mask;
|
||||
}
|
||||
|
||||
/* lex_asm(): Assembly table lexer and parser */
|
||||
struct asm_insn *lex_asm(void *data, size_t length, int *count)
|
||||
{
|
||||
/* First count the number of instruction codes */
|
||||
|
||||
YY_BUFFER_STATE buf = yy_scan_bytes(data, length);
|
||||
yylineno = 1;
|
||||
|
||||
int total = 0, t;
|
||||
while((t = yylex()) != -1)
|
||||
{
|
||||
total += (t == 0);
|
||||
if(t == 0 || t == LITERAL) free(yylval);
|
||||
}
|
||||
|
||||
yy_delete_buffer(buf);
|
||||
|
||||
/* Allocate a large enough instruction array */
|
||||
|
||||
struct asm_insn *table = calloc(total, sizeof *table);
|
||||
if(!table)
|
||||
{
|
||||
errf(ERR_ERRNO, "cannot allocate memory for database");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lex all instructions and fill in the array */
|
||||
|
||||
buf = yy_scan_bytes(data, length);
|
||||
yylineno = 1;
|
||||
|
||||
struct asm_insn *insn = table - 1;
|
||||
int line = -1;
|
||||
int named = 1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
t = yylex();
|
||||
|
||||
if(yylineno != line || t == 0 || t == -1)
|
||||
{
|
||||
/* Finalize current instruction */
|
||||
if(!named) err("%d: unnamed instruction", line);
|
||||
insn++;
|
||||
}
|
||||
if(t == -1) break;
|
||||
|
||||
if(t == 0)
|
||||
{
|
||||
set_code(yylval, insn);
|
||||
free(yylval);
|
||||
line = yylineno;
|
||||
named = 0;
|
||||
}
|
||||
else if(t == LITERAL && !named)
|
||||
{
|
||||
insn->mnemonic = yylval;
|
||||
named = 1;
|
||||
}
|
||||
else if(!named)
|
||||
{
|
||||
err("%d: missing mnemonic", line);
|
||||
}
|
||||
else if(!insn->arg1)
|
||||
{
|
||||
insn->arg1 = t;
|
||||
if(t == LITERAL) insn->literal1 = yylval;
|
||||
}
|
||||
else if(!insn->arg2)
|
||||
{
|
||||
insn->arg2 = t;
|
||||
if(t == LITERAL) insn->literal2 = yylval;
|
||||
}
|
||||
}
|
||||
|
||||
yy_delete_buffer(buf);
|
||||
if(count) *count = insn - table;
|
||||
return table;
|
||||
}
|
117
fxos/lexer-reg.l
Normal file
117
fxos/lexer-reg.l
Normal file
|
@ -0,0 +1,117 @@
|
|||
%{
|
||||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <util.h>
|
||||
|
||||
/* Values for tokens generated by the lexer */
|
||||
static union {
|
||||
char *text;
|
||||
long long integer;
|
||||
} yylval;
|
||||
|
||||
/* Token list */
|
||||
#define NUMBER 0
|
||||
#define SYMBOL 1
|
||||
|
||||
%}
|
||||
|
||||
%option prefix="reg"
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
|
||||
decimal 0|[1-9][0-9]*
|
||||
octal 0[0-7]+
|
||||
hexa 0x[0-9a-fA-F]+
|
||||
number {decimal}|{octal}|{hexa}
|
||||
|
||||
symbol [^0-9 \t\n][^\n]*
|
||||
|
||||
space [ \t]+
|
||||
|
||||
%%
|
||||
|
||||
^#[^\n]* ;
|
||||
{space} ;
|
||||
[\n] yylineno++;
|
||||
|
||||
{number} { yylval.integer = integer(yytext, NULL); return NUMBER; }
|
||||
{symbol} { yylval.text = strdup(yytext); return SYMBOL; }
|
||||
|
||||
<<EOF>> return -1;
|
||||
|
||||
%%
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* lex_reg(): Peripheral register table lexer and parser */
|
||||
struct reg_address *lex_reg(void *data, size_t len, int *count)
|
||||
{
|
||||
/* Count number of register descriptions (upper bound) */
|
||||
|
||||
YY_BUFFER_STATE buf = yy_scan_bytes(data, len);
|
||||
yylineno = 1;
|
||||
|
||||
int total = 0, t;
|
||||
while((t = yylex()) != -1)
|
||||
{
|
||||
total += (t == NUMBER);
|
||||
if(t == SYMBOL) free(yylval.text);
|
||||
}
|
||||
|
||||
yy_delete_buffer(buf);
|
||||
|
||||
/* Allocate a large enough register array */
|
||||
|
||||
struct reg_address *table = calloc(total, sizeof *table);
|
||||
if(!table)
|
||||
{
|
||||
errf(ERR_ERRNO, "cannot allocate memory for database");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lex all instructions and fill in the array */
|
||||
|
||||
buf = yy_scan_bytes(data, len);
|
||||
yylineno = 1;
|
||||
|
||||
struct reg_address *reg = table - 1;
|
||||
int line = -1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
t = yylex();
|
||||
|
||||
if(t == NUMBER || t == -1)
|
||||
{
|
||||
/* Finalize current instruction */
|
||||
if(reg >= table && !reg->name)
|
||||
err("%d: unnamed register", line);
|
||||
else reg++;
|
||||
}
|
||||
if(t == -1) break;
|
||||
|
||||
if(t == NUMBER)
|
||||
{
|
||||
reg->address = yylval.integer;
|
||||
line = yylineno;
|
||||
}
|
||||
else if(t == SYMBOL && reg < table)
|
||||
{
|
||||
err("%d: expected register address", yylineno);
|
||||
free(yylval.text);
|
||||
}
|
||||
else if(t == SYMBOL && !reg->name)
|
||||
{
|
||||
reg->name = yylval.text;
|
||||
}
|
||||
else if(t == SYMBOL)
|
||||
{
|
||||
err("%d: excess names for 0x%08x\n", reg->address);
|
||||
free(yylval.text);
|
||||
}
|
||||
}
|
||||
|
||||
yy_delete_buffer(buf);
|
||||
if(count) *count = reg - table;
|
||||
return table;
|
||||
}
|
123
fxos/lexer-sys.l
Normal file
123
fxos/lexer-sys.l
Normal file
|
@ -0,0 +1,123 @@
|
|||
%{
|
||||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <util.h>
|
||||
|
||||
/* Values for tokens generated by the lexer */
|
||||
static union {
|
||||
char *text;
|
||||
long long integer;
|
||||
} yylval;
|
||||
|
||||
/* Token list */
|
||||
#define NUMBER 0
|
||||
#define TEXT 1
|
||||
|
||||
%}
|
||||
|
||||
%option prefix="sys"
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
|
||||
decimal 0|[1-9][0-9]*
|
||||
octal 0[0-7]+
|
||||
hexa 0x[0-9a-fA-F]+
|
||||
number {decimal}|{octal}|{hexa}
|
||||
|
||||
space [ \t]+
|
||||
|
||||
%%
|
||||
|
||||
^#[^\n]* ;
|
||||
{space} ;
|
||||
[\n] yylineno++;
|
||||
|
||||
{number} { yylval.integer = integer(yytext, NULL); return NUMBER; }
|
||||
[^ \t\n0-9].* { yylval.text = strdup(yytext); return TEXT; }
|
||||
|
||||
<<EOF>> return -1;
|
||||
|
||||
%%
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* lex_sys(): Syscall table lexer and parser */
|
||||
struct sys_call *lex_sys(void *data, size_t len, int *count)
|
||||
{
|
||||
/* Count the number of syscalls */
|
||||
|
||||
YY_BUFFER_STATE buf = yy_scan_bytes(data, len);
|
||||
yylineno = 1;
|
||||
|
||||
int total = 0, t;
|
||||
while((t = yylex()) != -1)
|
||||
{
|
||||
total += (t == NUMBER);
|
||||
if(t == TEXT) free(yylval.text);
|
||||
}
|
||||
|
||||
yy_delete_buffer(buf);
|
||||
|
||||
/* Allocate a large enough syscall array */
|
||||
|
||||
struct sys_call *table = calloc(total, sizeof *table);
|
||||
if(!table)
|
||||
{
|
||||
errf(ERR_ERRNO, "cannot allocate memory for database");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lex all instructions and fill in the array */
|
||||
|
||||
buf = yy_scan_bytes(data, len);
|
||||
yylineno = 1;
|
||||
|
||||
struct sys_call *call = table - 1;
|
||||
int line = -1;
|
||||
int named = 1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
t = yylex();
|
||||
|
||||
if(t == NUMBER || t == -1)
|
||||
{
|
||||
/* Finalize current instruction */
|
||||
if(!named) err("%d: unnamed syscall", line);
|
||||
else call++;
|
||||
}
|
||||
if(t == -1) break;
|
||||
|
||||
if(t == NUMBER)
|
||||
{
|
||||
call->number = yylval.integer;
|
||||
line = yylineno;
|
||||
named = 0;
|
||||
}
|
||||
else if(t == TEXT && call < table)
|
||||
{
|
||||
err("%d: expected syscall id", yylineno);
|
||||
free(yylval.text);
|
||||
}
|
||||
else if(t == TEXT && named == 0)
|
||||
{
|
||||
call->name = yylval.text;
|
||||
named = 1;
|
||||
}
|
||||
else if(t == TEXT && named == 1)
|
||||
{
|
||||
call->descr = yylval.text;
|
||||
named = 2;
|
||||
}
|
||||
else if(t == TEXT)
|
||||
{
|
||||
err("%d: excess qualifiers for syscall 0x%03x", line,
|
||||
call->number);
|
||||
free(yylval.text);
|
||||
}
|
||||
}
|
||||
|
||||
yy_delete_buffer(buf);
|
||||
if(count) *count = call - table;
|
||||
return table;
|
||||
}
|
354
fxos/main.c
354
fxos/main.c
|
@ -4,144 +4,253 @@
|
|||
#include <getopt.h>
|
||||
|
||||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <util.h>
|
||||
|
||||
static const char *help_string =
|
||||
static char const *help_string =
|
||||
"usage: %1$s info (<os file> | -b <binary file>)\n"
|
||||
" %1$s disasm <os file> (-a <address> | -s <syscall id>) [options...]\n"
|
||||
" %1$s disasm -b <binary file> [options...]\n"
|
||||
" %1$s analyze [-f|-s|-a|-r] <number> <os file> [options...]\n"
|
||||
" %1$s analyze [-f] [-s] [-a] [-r] <number> <os file> [options...]\n"
|
||||
"\n"
|
||||
"fxos disassembles or analyzes binary and OS files for efficient reverse-\n"
|
||||
"engineering. It currently only supports fx9860g binaries.\n"
|
||||
"fxos is a reverse-engineering tool to disassemble and analyze fx9860g-like\n"
|
||||
"OS dumps, providing efficient annotations through an editable database.\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" info Identify an OS image: version, platform, date, checksums...\n"
|
||||
" Identify the architecture of a binary file.\n"
|
||||
" disasm Disassemble and annotate code with relative address targets,\n"
|
||||
" syscall invocations and hints about memory structure.\n"
|
||||
" analyze Dig an address or syscall number, finding syscall call graph,\n"
|
||||
" analyze Dig an address or syscall number, finding syscall references,\n"
|
||||
" 4-aligned occurrences, memory region and probable role.\n"
|
||||
"\n"
|
||||
"General options:\n"
|
||||
" -b Disassemble any binary file, not an OS file\n"
|
||||
" -3, --sh3 Assume SH3 OS and platform (default: guess)\n"
|
||||
" -4, --sh4 Assume SH4 OS and platform (default: guess)\n"
|
||||
" --ram <folder> Read RAM dumps from <folder>\n"
|
||||
" --table-asm <file> Read more instruction patterns in <file>\n"
|
||||
" --table-call <file> Read more syscall prototypes in <file>\n"
|
||||
" -b Work with an arbitrary binary file, not an OS\n"
|
||||
"\n"
|
||||
"Disassembly region options:\n"
|
||||
"Table extensions:\n"
|
||||
" --table-asm <file> Use instruction codes and mnemonics from <file>\n"
|
||||
" --table-sys <file> Use syscall prototypes and descriptions from <file>\n"
|
||||
" --table-reg <file> Use peripheral register addresses from <file>\n"
|
||||
"\n"
|
||||
"Disassembly options:\n"
|
||||
" -a <address> Start disassembling at this address\n"
|
||||
" -s <syscall id> Start disassembling at this syscall's address\n"
|
||||
" -l <length> Length of region\n"
|
||||
" -3, --sh3 Assume SH3 OS and platform (default: guess)\n"
|
||||
" -4, --sh4 Assume SH4 OS and platform (default: guess)\n"
|
||||
"\n"
|
||||
"Analysis modes:\n"
|
||||
" -f, --full Find everything that can be known about <number>\n"
|
||||
" -s, --syscall <number> is a syscall ID\n"
|
||||
" -a, --address <number> is a code/data address in ROM or RAM\n"
|
||||
" -r, --register <number> is a register or peripheral address\n"
|
||||
" -f, --full Run all analysis passes on <number> (same as -sar)\n"
|
||||
" -s, --syscall Run syscall ID analysis\n"
|
||||
" -a, --address Run code/data address analyis\n"
|
||||
" -r, --register Run peripheral register analysis\n"
|
||||
"\n"
|
||||
"Analysis options:\n"
|
||||
" --occurrences <num> Show at most <num> occurrences (integer or \"all\")\n";
|
||||
" --occurrences <num> Show at most <num> occurrences (integer or \"all\")\n"
|
||||
"\n"
|
||||
"All numbers support base prefixes '0' (octal) and '0x' (hexadecimal).\n";
|
||||
|
||||
/* "Low-level" command-line option set */
|
||||
struct options
|
||||
#define OPT_ASM 1
|
||||
#define OPT_SYS 2
|
||||
#define OPT_REG 3
|
||||
#define OPT_OCC 4
|
||||
|
||||
/*
|
||||
** "info" command
|
||||
*/
|
||||
|
||||
int main_info(int argc, char **argv)
|
||||
{
|
||||
const char *input;
|
||||
int error=0, option=0, binary=0;
|
||||
|
||||
int target;
|
||||
const char *ram;
|
||||
struct option const longs[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
};
|
||||
|
||||
const char *a;
|
||||
const char *s;
|
||||
size_t l;
|
||||
|
||||
int f;
|
||||
int r;
|
||||
const char *occ;
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int command = 0, error = 0;
|
||||
struct options opt = { 0 };
|
||||
/* For string -> int conversions, first non-int character */
|
||||
|
||||
|
||||
/* Get command name */
|
||||
if(argc >= 2)
|
||||
while(option >= 0 && option != '?')
|
||||
switch((option = getopt_long(argc, argv, "hb", longs, NULL)))
|
||||
{
|
||||
if(!strcmp(argv[1], "info")) command = 'i';
|
||||
if(!strcmp(argv[1], "disasm")) command = 'd';
|
||||
if(!strcmp(argv[1], "analyze")) command = 'a';
|
||||
|
||||
if(!command && argv[1][0] != '-')
|
||||
{
|
||||
fprintf(stderr, "invalid operation: '%s'\n", argv[1]);
|
||||
fprintf(stderr, "Try '%s --help'.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(command) argv[1] = "";
|
||||
case 'h':
|
||||
err(help_string, argv[0]);
|
||||
break;
|
||||
case 'b':
|
||||
binary = 1;
|
||||
break;
|
||||
case '?':
|
||||
error = 1;
|
||||
}
|
||||
|
||||
enum {
|
||||
OPT_RAM = 1,
|
||||
OPT_ASM = 2,
|
||||
OPT_CALL = 3,
|
||||
OPT_OCC = 4,
|
||||
};
|
||||
const struct option longs[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "sh3", no_argument, NULL, '3' },
|
||||
{ "sh4", no_argument, NULL, '4' },
|
||||
{ "ram", required_argument, NULL, OPT_RAM },
|
||||
{ "table-asm", required_argument, NULL, OPT_ASM },
|
||||
{ "table-call", required_argument, NULL, OPT_CALL },
|
||||
{ "full", no_argument, NULL, 'f' },
|
||||
{ "syscall", no_argument, NULL, 's' },
|
||||
{ "address", no_argument, NULL, 'a' },
|
||||
{ "register", no_argument, NULL, 'r' },
|
||||
{ "occurrences", required_argument, NULL, OPT_OCC },
|
||||
if(error) return 1;
|
||||
char const *path = argv[optind + 1];
|
||||
|
||||
if(!path)
|
||||
{
|
||||
err(help_string, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err_context(path, NULL);
|
||||
|
||||
struct os os;
|
||||
if(os_load(path, &os)) { err_pop(); return 1; }
|
||||
|
||||
if(binary)
|
||||
{
|
||||
err("TODO: Binary file info x_x");
|
||||
}
|
||||
else
|
||||
{
|
||||
info_os(&os);
|
||||
}
|
||||
|
||||
os_free(&os);
|
||||
err_pop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** "disasm" command
|
||||
*/
|
||||
|
||||
int main_disassembly(int argc, char **argv)
|
||||
{
|
||||
int error=0, option=0;
|
||||
|
||||
/* First load some of fxos' default resources */
|
||||
asm_load(FXSDK_PREFIX "/share/fxsdk/asm-sh3.txt");
|
||||
asm_load(FXSDK_PREFIX "/share/fxsdk/asm-sh4.txt");
|
||||
sys_load(FXSDK_PREFIX "/share/fxsdk/sys-simlo.txt");
|
||||
sys_load(FXSDK_PREFIX "/share/fxsdk/sys-lephe.txt");
|
||||
reg_load(FXSDK_PREFIX "/share/fxsdk/reg-sh7305.txt");
|
||||
reg_load(FXSDK_PREFIX "/share/fxsdk/reg-simlo.txt");
|
||||
|
||||
struct disassembly opt = { 0 };
|
||||
opt.mpu = MPU_GUESS;
|
||||
opt.len = 0x20;
|
||||
|
||||
struct option const longs[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "sh3", no_argument, NULL, '3' },
|
||||
{ "sh4", no_argument, NULL, '4' },
|
||||
{ "table-asm", required_argument, NULL, OPT_ASM },
|
||||
{ "table-sys", required_argument, NULL, OPT_SYS },
|
||||
{ "table-reg", required_argument, NULL, OPT_REG },
|
||||
};
|
||||
|
||||
int option = 0;
|
||||
while(option >= 0 && option != '?')
|
||||
switch((option = getopt_long(argc, argv, "hb34a::s::l:fr",longs,NULL)))
|
||||
switch((option = getopt_long(argc, argv, "hb34a:s:l:", longs, NULL)))
|
||||
{
|
||||
case 'h':
|
||||
err(help_string, argv[0]);
|
||||
break;
|
||||
case 'b':
|
||||
opt.binary = 1;
|
||||
break;
|
||||
case '3':
|
||||
opt.mpu = MPU_SH7705;
|
||||
break;
|
||||
case '4':
|
||||
opt.mpu = MPU_SH7305;
|
||||
break;
|
||||
case OPT_ASM:
|
||||
asm_load(optarg);
|
||||
break;
|
||||
case OPT_SYS:
|
||||
printf("TODO: Load additional syscall tables x_x\n");
|
||||
break;
|
||||
case OPT_REG:
|
||||
printf("TODO: Load additional register tables x_x\n");
|
||||
break;
|
||||
case 'a':
|
||||
case 's':
|
||||
opt.start = integer(optarg, &error);
|
||||
opt.syscall = (option == 's');
|
||||
break;
|
||||
case 'l':
|
||||
opt.len = integer(optarg, &error);
|
||||
break;
|
||||
case '?':
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if(error) return 1;
|
||||
char const *path = argv[optind + 1];
|
||||
|
||||
if(!path)
|
||||
{
|
||||
err(help_string, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err_context(path, NULL);
|
||||
|
||||
if(opt.binary)
|
||||
{
|
||||
printf("TODO: Disassembly binary x_x");
|
||||
err_pop();
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct os os;
|
||||
if(os_load(path, &os)) { err_pop(); return 1; }
|
||||
|
||||
disassembly_os(&os, &opt);
|
||||
|
||||
os_free(&os);
|
||||
err_pop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** "analyze" command
|
||||
*/
|
||||
|
||||
int main_analyze(int argc, char **argv)
|
||||
{
|
||||
int error=0, option=0;
|
||||
struct analysis opt = { 0 };
|
||||
|
||||
struct option const longs[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "table-asm", required_argument, NULL, OPT_ASM },
|
||||
{ "table-sys", required_argument, NULL, OPT_SYS },
|
||||
{ "table-reg", required_argument, NULL, OPT_REG },
|
||||
{ "full", no_argument, NULL, 'f' },
|
||||
{ "syscall", no_argument, NULL, 's' },
|
||||
{ "address", no_argument, NULL, 'a' },
|
||||
{ "register", no_argument, NULL, 'r' },
|
||||
{ "occurrences", required_argument, NULL, OPT_OCC },
|
||||
};
|
||||
|
||||
while(option >= 0 && option != '?')
|
||||
switch((option = getopt_long(argc,argv,"hfsar", longs, NULL)))
|
||||
{
|
||||
case 'h':
|
||||
fprintf(stderr, help_string, argv[0]);
|
||||
return 0;
|
||||
case '3':
|
||||
case '4':
|
||||
opt.target = option;
|
||||
break;
|
||||
case OPT_RAM:
|
||||
opt.ram = optarg;
|
||||
break;
|
||||
case OPT_ASM:
|
||||
tables_add_asm(optarg);
|
||||
asm_load(optarg);
|
||||
break;
|
||||
case OPT_CALL:
|
||||
tables_add_syscall(optarg);
|
||||
case OPT_SYS:
|
||||
// sys_load(optarg);
|
||||
break;
|
||||
case OPT_REG:
|
||||
// reg_load(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
opt.f = 1;
|
||||
opt.type = ANALYSIS_FULL;
|
||||
break;
|
||||
case 's':
|
||||
opt.s = optarg;
|
||||
opt.type |= ANALYSIS_SYSCALL;
|
||||
break;
|
||||
case 'a':
|
||||
opt.a = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
opt.l = integer(optarg, &error);
|
||||
opt.type |= ANALYSIS_ADDRESS;
|
||||
break;
|
||||
case 'r':
|
||||
opt.r = 1;
|
||||
opt.type |= ANALYSIS_REGISTER;
|
||||
break;
|
||||
case OPT_OCC:
|
||||
opt.occ = optarg;
|
||||
opt.occurrences = integer(optarg, &error);
|
||||
break;
|
||||
case '?':
|
||||
error = 1;
|
||||
|
@ -149,35 +258,44 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if(error) return 1;
|
||||
opt.input = argv[optind];
|
||||
|
||||
if(!opt.input)
|
||||
{
|
||||
fprintf(stderr, help_string, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load default tables (user-specified tables will override them) */
|
||||
tables_add_asm (FXSDK_PREFIX "/share/assembly-sh3.txt");
|
||||
tables_add_syscall(FXSDK_PREFIX "/share/syscalls.txt");
|
||||
|
||||
/* Change interpretation of arguments depending on mode */
|
||||
|
||||
printf("Operation is '%c'\n", command);
|
||||
printf(" input=%s\n", opt.input);
|
||||
printf(" target='%c'\n", opt.target);
|
||||
printf(" ram=%s\n", opt.ram);
|
||||
printf(" a=%s\n", opt.a);
|
||||
printf(" s=%s\n", opt.s);
|
||||
printf(" l=%zu\n", opt.l);
|
||||
printf(" f=%d\n", opt.f);
|
||||
printf(" r=%d\n", opt.r);
|
||||
printf(" occ=%s\n", opt.occ);
|
||||
|
||||
/* TODO: Execution procedure:
|
||||
TODO: 1. Identify architecture
|
||||
TODO: 2. Load RAM data, syscall tables, peripheral modules, etc
|
||||
TODO: 3. Execute command */
|
||||
/* If no analysis mode was specified, do everything */
|
||||
if(!opt.type) opt.type = ANALYSIS_FULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Program entry
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if(argc < 2)
|
||||
{
|
||||
err(help_string, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *cmd = argv[1];
|
||||
argv[1] = "";
|
||||
|
||||
/* Switch on command name */
|
||||
if(!strcmp(cmd, "info"))
|
||||
return main_info(argc, argv);
|
||||
else if(!strcmp(cmd, "disasm"))
|
||||
return main_disassembly(argc, argv);
|
||||
else if(!strcmp(cmd, "analyze"))
|
||||
return main_analyze(argc, argv);
|
||||
|
||||
else if(!strcmp(cmd, "-?") || !strcmp(cmd, "-h") ||
|
||||
!strcmp(cmd, "--help"))
|
||||
{
|
||||
err(help_string, argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err("invalid operation '%s'", cmd);
|
||||
err("Try '%s --help'.", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
|
38
fxos/memory.c
Normal file
38
fxos/memory.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <fxos.h>
|
||||
|
||||
/* Shared by all platforms (though ROM is 4M on most) */
|
||||
|
||||
static struct region ROM = { 0x80000000, 0x807fffff, "ROM", MPU_GUESS };
|
||||
static struct region RAM = { 0x88000000, 0x88040000, "RAM", MPU_GUESS };
|
||||
|
||||
static struct region P2_ROM = { 0xa0000000, 0xa07fffff, "P2 ROM", MPU_GUESS };
|
||||
static struct region P2_RAM = { 0xa8000000, 0xa8040000, "P2 RAM", MPU_GUESS };
|
||||
|
||||
/* SH7305 only */
|
||||
|
||||
static struct region RS = { 0xfd800000, 0xfd8007ff, "RS", MPU_SH7305 };
|
||||
static struct region IL = { 0xe5200000, 0xe5203fff, "IL", MPU_SH7305 };
|
||||
static struct region XRAM = { 0xe5007000, 0xe5008fff, "XRAM", MPU_SH7305 };
|
||||
static struct region YRAM = { 0xe5017000, 0xe5018fff, "YRAM", MPU_SH7305 };
|
||||
|
||||
/* A summary */
|
||||
static struct region *regions[] = {
|
||||
&ROM, &RAM, &P2_ROM, &P2_RAM, &IL, &RS, NULL,
|
||||
};
|
||||
|
||||
/* memory_in(): Check if an address if inside a given region */
|
||||
static int memory_in(uint32_t address, struct region const *reg)
|
||||
{
|
||||
return reg && address >= reg->start && address <= reg->end;
|
||||
}
|
||||
|
||||
/* memory_region(): Find the region where an address is located */
|
||||
struct region const *memory_region(uint32_t address)
|
||||
{
|
||||
for(int i = 0; regions[i]; i++)
|
||||
{
|
||||
if(memory_in(address, regions[i])) return regions[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
91
fxos/os.c
Normal file
91
fxos/os.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include <endian.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <util.h>
|
||||
|
||||
/* os_load(): Load an OS file and find out basic properties */
|
||||
int os_load(char const *path, struct os *os)
|
||||
{
|
||||
if(!path || !os) return 1;
|
||||
|
||||
os->data = map(path, &os->fd, &os->len);
|
||||
if(!os->data) return 1;
|
||||
if(os->len < 0x10080)
|
||||
{
|
||||
err("too small for the OS format I know (min. 0x10080 bytes)",
|
||||
os->len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get the OS version */
|
||||
|
||||
memcpy(os->version, os->data + 0x10020, 14);
|
||||
os->version[14] = 0;
|
||||
|
||||
/* Guess the MPU type (or assume SH7305). Until version 03.00, the last
|
||||
digit of the version number indicated the presence of an SH7305 */
|
||||
|
||||
os->mpu = MPU_SH7305;
|
||||
if(!strncmp(os->version, "02.", 3) && os->version[13] == '0')
|
||||
os->mpu = MPU_SH7705;
|
||||
|
||||
/* Find the syscall table address */
|
||||
|
||||
memcpy(&os->syscall_table, os->data + 0x1007c, 4);
|
||||
os->syscall_table = be32toh(os->syscall_table);
|
||||
|
||||
/* Count the number of valid syscall entries */
|
||||
|
||||
os->syscalls = 0;
|
||||
while(memory_region(os_syscall(os, os->syscalls))) os->syscalls++;
|
||||
|
||||
/* Find the footer address (last occurrence of "CASIOABSLangdata") */
|
||||
|
||||
char const *signature = "CASIOABSLangdata";
|
||||
void *occ = NULL, *next = memmem(os->data, os->len, signature, 16);
|
||||
void *end = os->data + os->len;
|
||||
|
||||
while(next)
|
||||
{
|
||||
occ = next;
|
||||
next = memmem(next + 1, end - (next + 1), signature, 16);
|
||||
}
|
||||
|
||||
os->footer = (occ) ? (occ - os->data) : (uint32_t)-1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* os_syscall(): Get the address of a syscall entry */
|
||||
uint32_t os_syscall(struct os const *os, int syscall)
|
||||
{
|
||||
uint32_t table_entry = (os->syscall_table & 0x1fffffff) + 4 * syscall;
|
||||
if(table_entry + 4 > os->len) return (uint32_t)-1;
|
||||
|
||||
uint32_t address;
|
||||
memcpy(&address, os->data + table_entry, 4);
|
||||
address = be32toh(address);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
/* os_syscall_find(): Find a syscall which points to an address */
|
||||
int os_syscall_find(struct os const *os, uint32_t entry)
|
||||
{
|
||||
/* Try to make this slightly quicker */
|
||||
uint32_t table_entry = (os->syscall_table & 0x1fffffff);
|
||||
entry = htobe32(entry);
|
||||
|
||||
uint32_t *entries = os->data + table_entry;
|
||||
for(int i = 0; i < os->syscalls; i++) if(entries[i] == entry) return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* os_free(): Free an OS file opened with os_load() */
|
||||
void os_free(struct os const *os)
|
||||
{
|
||||
if(os && os->data) unmap(os->data, os->fd, os->len);
|
||||
}
|
114
fxos/reg-sh7305.txt
Normal file
114
fxos/reg-sh7305.txt
Normal file
|
@ -0,0 +1,114 @@
|
|||
# T6K11 interface
|
||||
0xb4000000 T6K11.REG
|
||||
0xb4010000 T6K11.DATA
|
||||
|
||||
# Exception handling
|
||||
0xff000020 TRA
|
||||
0xff000024 EXPEVT
|
||||
0xff000028 INTEVT
|
||||
0xff2f0004 EXPMASK
|
||||
|
||||
# Memory Management Unit
|
||||
0xff000000 MMU.PTEH
|
||||
0xff000004 MMU.PTEL
|
||||
0xff00000c MMU.TEA
|
||||
0xff000010 MMU.MMUCR
|
||||
0xff000034 MMU.PTEA
|
||||
0xff000070 MMU.PASCR
|
||||
0xff000078 MMU.IRMCR
|
||||
|
||||
# Interrupt controller
|
||||
0xa4140000 INTC.ICR0
|
||||
0xa414001c INTC.ICR1
|
||||
0xa4140010 INTC.INTPRI00
|
||||
0xa4140024 INTC.INTREQ00
|
||||
0xa4140044 INTC.INTMSK00
|
||||
0xa4140064 INTC.INTMSKCLR00
|
||||
0xa41400c0 INTC.NMIFCR
|
||||
0xa4700000 INTC.USERIMSK
|
||||
0xa4080000 INTC.IPRA
|
||||
0xa4080004 INTC.IPRB
|
||||
0xa4080008 INTC.IPRC
|
||||
0xa408000c INTC.IPRD
|
||||
0xa4080010 INTC.IPRE
|
||||
0xa4080014 INTC.IPRF
|
||||
0xa4080018 INTC.IPRG
|
||||
0xa408001c INTC.IPRH
|
||||
0xa4080020 INTC.IPRI
|
||||
0xa4080024 INTC.IPRJ
|
||||
0xa4080028 INTC.IPRK
|
||||
0xa408002c INTC.IPRL
|
||||
0xa4080080 INTC.IMR0
|
||||
0xa4080084 INTC.IMR1
|
||||
0xa4080088 INTC.IMR2
|
||||
0xa408008c INTC.IMR3
|
||||
0xa4080090 INTC.IMR4
|
||||
0xa4080094 INTC.IMR5
|
||||
0xa4080098 INTC.IMR6
|
||||
0xa408009c INTC.IMR7
|
||||
0xa40800a0 INTC.IMR8
|
||||
0xa40800a4 INTC.IMR9
|
||||
0xa40800a8 INTC.IMR10
|
||||
0xa40800ac INTC.IMR11
|
||||
0xa40800b0 INTC.IMR12
|
||||
0xa40800c0 INTC.IMCR0
|
||||
0xa40800c4 INTC.IMCR1
|
||||
0xa40800c8 INTC.IMCR2
|
||||
0xa40800cc INTC.IMCR3
|
||||
0xa40800d0 INTC.IMCR4
|
||||
0xa40800d4 INTC.IMCR5
|
||||
0xa40800d8 INTC.IMCR6
|
||||
0xa40800dc INTC.IMCR7
|
||||
0xa40800e0 INTC.IMCR8
|
||||
0xa40800e4 INTC.IMCR9
|
||||
0xa40800e8 INTC.IMCR10
|
||||
0xa40800ec INTC.IMCR11
|
||||
0xa40800f0 INTC.IMCR12
|
||||
|
||||
# Direct Memory Access Controller: TODO
|
||||
|
||||
# Reset and power-down modes
|
||||
0xa4150020 POWER.STBCR
|
||||
0xa4150030 POWER.MSTPCR0
|
||||
0xa4150034 POWER.MSTPCR1
|
||||
0xa4150038 POWER.MSTPCR2
|
||||
0xa4150040 POWER.BAR
|
||||
|
||||
# Real-Time Clock
|
||||
0xa465fec0 RTC.R64CNT
|
||||
0xa465fec2 RTC.RSECCNT
|
||||
0xa465fec4 RTC.RMINCNT
|
||||
0xa465fec6 RTC.RHRCNT
|
||||
0xa465fec8 RTC.RWKCNT
|
||||
0xa465feca RTC.RDAYCNT
|
||||
0xa465fecc RTC.RMONCNT
|
||||
0xa465fece RTC.RYRCNT
|
||||
0xa465fed0 RTC.RSECAR
|
||||
0xa465fed2 RTC.RMINAR
|
||||
0xa465fed4 RTC.RHRAR
|
||||
0xa465fed6 RTC.RWKAR
|
||||
0xa465fed8 RTC.RDAYAR
|
||||
0xa465feda RTC.RMONAR
|
||||
0xa465fedc RTC.RCR1
|
||||
0xa465fede RTC.RCR2
|
||||
0xa465fee0 RTC.RYRAR
|
||||
0xa465fee4 RTC.RCR3
|
||||
|
||||
# User Break Controller
|
||||
0xff200000 UBC.CBR0
|
||||
0xff200004 UBC.CRR0
|
||||
0xff200008 UBC.CAR0
|
||||
0xff20000c UBC.CAMR0
|
||||
0xff200020 UBC.CBR1
|
||||
0xff200024 UBC.CRR1
|
||||
0xff200028 UBC.CAR1
|
||||
0xff20002c UBC.CAMR1
|
||||
0xff200030 UBC.CDR1
|
||||
0xff200034 UBC.CDMR1
|
||||
0xff200038 UBC.CETR1
|
||||
0xff200600 UBC.CCMFR
|
||||
0xff200620 UBC.CBCR
|
||||
|
||||
# RCLK Watchdog Timer
|
||||
0xa4520000 RWDT.RWTCNT
|
||||
0xA4520004 RWDT.RWTCSR
|
141
fxos/reg-simlo.txt
Normal file
141
fxos/reg-simlo.txt
Normal file
|
@ -0,0 +1,141 @@
|
|||
# Processor version
|
||||
0xff2f0000 CPUOPM
|
||||
0xff000030 PVR
|
||||
0xff000040 CVR
|
||||
0xff000044 PRR
|
||||
|
||||
# Key Scan Interface
|
||||
0xa44b0000 KEYSC.DATA
|
||||
0xa44b000c KEYSC.UCNTREG
|
||||
0xa44b000e KEYSC.AUTOFIXREG
|
||||
0xa44b0010 KEYSC.UMODEREG
|
||||
0xa44b0012 KEYSC.USTATEREG
|
||||
0xa44b0014 KEYSC.UINTREG
|
||||
0xa44b0016 KEYSC.UWSETREG
|
||||
0xa44b0018 KEYSC.UINTERVALREG
|
||||
0xa44b001a KEYSC.OUTPINSET
|
||||
0xa44b001c KEYSC.INPINSET
|
||||
|
||||
# Timer Unit
|
||||
0xa4490004 TMU.TSTR
|
||||
0xa4490008 TMU0.TCOR
|
||||
0xa449000c TMU0.TCNT
|
||||
0xa4490010 TMU0.TCR
|
||||
0xa4490014 TMU1.TCOR
|
||||
0xa4490018 TMU1.TCNT
|
||||
0xa449001c TMU1.TCR
|
||||
0xa4490020 TMU2.TCOR
|
||||
0xa4490024 TMU2.TCNT
|
||||
0xa4490028 TMU2.TCR
|
||||
|
||||
# Serial Communication Interface
|
||||
0xa4410000 SCIF.SCSMR
|
||||
0xa4410004 SCIF.SCBRR
|
||||
0xa4410008 SCIF.SCSCR
|
||||
0xa441000c SCIF.SCFTDR
|
||||
0xa4410010 SCIF.SCFSR
|
||||
0xa4410014 SCIF.SCFRDR
|
||||
0xa4410018 SCIF.SCFCR
|
||||
0xa441001c SCIF.SCFDR
|
||||
0xa4410024 SCIF.SCLSR
|
||||
|
||||
# Pin Function Controller
|
||||
0xa4050100 PFC.PACR
|
||||
0xa4050102 PFC.PBCR
|
||||
0xa4050104 PFC.PCCR
|
||||
0xa4050106 PFC.PDCR
|
||||
0xa4050108 PFC.PECR
|
||||
0xa405010a PFC.PFCR
|
||||
0xa405010c PFC.PGCR
|
||||
0xa405010e PFC.PHCR
|
||||
0xa4050110 PFC.PJCR
|
||||
0xa4050112 PFC.PKCR
|
||||
0xa4050114 PFC.PLCR
|
||||
0xa4050116 PFC.PMCR
|
||||
0xa4050118 PFC.PNCR
|
||||
0xa405014c PFC.PPCR
|
||||
0xa405011a PFC.PQCR
|
||||
0xa405011c PFC.PRCR
|
||||
0xa405011e PFC.PSCR
|
||||
0xa4050140 PFC.PTCR
|
||||
0xa4050142 PFC.PUCR
|
||||
0xa4050144 PFC.PVCR
|
||||
0xa405014e PFC.PSELA
|
||||
0xa4050150 PFC.PSELB
|
||||
0xa4050152 PFC.PSELC
|
||||
0xa4050154 PFC.PSELD
|
||||
0xa4050156 PFC.PSELE
|
||||
0xa405015e PFC.PSELF
|
||||
0xa40501c8 PFC.PSELG
|
||||
0xa40501d6 PFC.PSELH
|
||||
0xa4050158 PFC.HIZCRA
|
||||
0xa405015a PFC.HIZCRB
|
||||
0xa405015c PFC.HIZCRC
|
||||
0xa4050180 PFC.MSELCRA
|
||||
0xa4050182 PFC.MSELCRB
|
||||
0xa4050184 PFC.DRVCRD
|
||||
0xa4050186 PFC.DRVCRA
|
||||
0xa4050188 PFC.DRVCRB
|
||||
0xa405018a PFC.DRVCRC
|
||||
0xa40501c3 PFC.PULCRBSC
|
||||
0xa40501c5 PFC.PULCRTRST
|
||||
0xa4050190 PFC.PULCRA
|
||||
0xa4050191 PFC.PULCRB
|
||||
0xa4050192 PFC.PULCRC
|
||||
0xa4050193 PFC.PULCRD
|
||||
0xa4050194 PFC.PULCRE
|
||||
0xa4050195 PFC.PULCRF
|
||||
0xa4050196 PFC.PULCRG
|
||||
0xa4050197 PFC.PULCRH
|
||||
0xa4050198 PFC.PULCRJ
|
||||
0xa4050199 PFC.PULCRK
|
||||
0xa405019a PFC.PULCRL
|
||||
0xa405019b PFC.PULCRM
|
||||
0xa405019c PFC.PULCRN
|
||||
0xa40501c6 PFC.PULCRP
|
||||
0xa405019d PFC.PULCRQ
|
||||
0xa405019e PFC.PULCRR
|
||||
0xa405019f PFC.PULCRS
|
||||
0xa40501c0 PFC.PULCRT
|
||||
0xa40501c1 PFC.PULCRU
|
||||
0xa40501c2 PFC.PULCRV
|
||||
|
||||
# Bus State Controller
|
||||
0xfec10000 BSC.CMNCR
|
||||
0xfec10004 BSC.CS0BCR
|
||||
0xfec10008 BSC.CS2BCR
|
||||
0xfec1000c BSC.CS3BCR
|
||||
0xfec10010 BSC.CS4BCR
|
||||
0xfec10014 BSC.CS5ABCR
|
||||
0xfec10018 BSC.CS5BBCR
|
||||
0xfec1001c BSC.CS6ABCR
|
||||
0xfec10020 BSC.CS6BBCR
|
||||
0xfec10024 BSC.CS0WCR
|
||||
0xfec10028 BSC.CS2WCR
|
||||
0xfec1002c BSC.CS3WCR
|
||||
0xfec10030 BSC.CS4WCR
|
||||
0xfec10034 BSC.CS5AWCR
|
||||
0xfec10038 BSC.CS5BWCR
|
||||
0xfec1003c BSC.CS6AWCR
|
||||
0xfec10040 BSC.CS6BWCR
|
||||
0xfec10044 BSC.SDCR
|
||||
0xfec10048 BSC.RTCSR
|
||||
0xfec1004c BSC.RTCNT
|
||||
0xfec10050 BSC.RTCOR
|
||||
0xfec14000 BSC.SDMR2
|
||||
0xfec15000 BSC.SDMR3
|
||||
|
||||
# Clock Pulse Generator
|
||||
0xa4150000 CPG.FRQCR
|
||||
0xa4150008 CPG.FCLKCR
|
||||
0xa4150010 CPG.DDCLKCR
|
||||
0xa4150014 CPG.USBCLKCR
|
||||
0xa4150024 CPG.PLLCR
|
||||
0xa4150028 CPG.PLL2CR
|
||||
0xa415003c CPG.SPUCLKCR
|
||||
0xa4150044 CPG.SSCGCR
|
||||
0xa4150050 CPG.FLLFRQ
|
||||
0xa4150060 CPG.LSTATS
|
||||
|
||||
# More addresses are around on Casiopeia.
|
||||
# See http://www.casiopeia.net/forum/viewtopic.php?f=11&t=1756#p14588.
|
58
fxos/reg.c
Normal file
58
fxos/reg.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <string.h>
|
||||
#include <util.h>
|
||||
|
||||
/* reg_free_item(): Free a peripheral register item */
|
||||
static void reg_free_item(void *item)
|
||||
{
|
||||
struct reg_address *reg = item;
|
||||
free(reg->name);
|
||||
}
|
||||
|
||||
/* reg_load(): Load a peripheral register table */
|
||||
void reg_load(char const *file)
|
||||
{
|
||||
err_context("register", file, NULL);
|
||||
if(!table_available())
|
||||
{
|
||||
err("too many tables, skipping");
|
||||
err_pop();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Map the file to memory */
|
||||
int fd;
|
||||
size_t size;
|
||||
void *data = map(file, &fd, &size);
|
||||
if(!data) { err_pop(); return; }
|
||||
|
||||
/* If the file is named "reg-x.txt", use "x" as the table name */
|
||||
char *name = match_table_name(file, "reg", ".txt");
|
||||
|
||||
/* Parse the contents */
|
||||
int count;
|
||||
struct reg_address *regs = lex_reg(data, size, &count);
|
||||
|
||||
table_create("reg", name, reg_free_item, count, sizeof *regs, regs);
|
||||
|
||||
unmap(data, fd, size);
|
||||
err_pop();
|
||||
}
|
||||
|
||||
/* Global storage for reg_match() */
|
||||
static uint32_t reg_match_address;
|
||||
|
||||
/* reg_match(): Search routine for reg_find() */
|
||||
static int reg_match(void *item)
|
||||
{
|
||||
struct reg_address *reg = item;
|
||||
return reg->address == reg_match_address;
|
||||
}
|
||||
|
||||
/* reg_find(): Find information on a given peripheral register address */
|
||||
struct reg_address const *reg_find(uint32_t address)
|
||||
{
|
||||
reg_match_address = address;
|
||||
return table_find("reg", reg_match, NULL, 0);
|
||||
}
|
7
fxos/sys-lephe.txt
Normal file
7
fxos/sys-lephe.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
0x000 sys_init
|
||||
0x004 tlb_init
|
||||
void tlb_init(void)
|
||||
0x025 t6k11_read_datareg
|
||||
uint8_t t6k11_read_datareg(void)
|
||||
0x3fc tlb_map
|
||||
void tlb_map(int shifted_vpn, int way, uint32_t data_field)
|
656
fxos/sys-simlo.txt
Normal file
656
fxos/sys-simlo.txt
Normal file
|
@ -0,0 +1,656 @@
|
|||
0x001 vbr_tlb_error
|
||||
0x002 vbr_cpu_address
|
||||
0x003 vbr_tlb_exception
|
||||
0x005 App_RegisterAddins
|
||||
int App_RegisterAddins(void)
|
||||
0x009 App_FindFreeAddinSlot
|
||||
int FindFreeAddinSlot(void)
|
||||
0x00a App_GetAddinHeaderAddr
|
||||
int GetAddindHeaderAddr(int addin_no, int offset, void *result)
|
||||
0x00e App_GetAddindEstrip
|
||||
int App_GetAddindEstrip(int addin_no, int estrip_no, void *result)
|
||||
0x013 GlibAddinAplExecutionCheck
|
||||
0x014 GlibGetAddinLibInfo
|
||||
0x015 GlibGetOSVersionInfo
|
||||
int GlibGetOSVersionInfo(char *a, char *b, short *c, short *d)
|
||||
0x018 MMU_FlushCache
|
||||
0x01b DD_Clear
|
||||
0x01c Bdisp_WriteGraph_VRAM
|
||||
0x01d Bdisp_WriteGraph_DD
|
||||
0x01e Bdisp_WriteGraph_DDVRAM
|
||||
0x022 Bdisp_ReadArea_VRAM
|
||||
0x023 Bdisp_ReadArea_DD
|
||||
0x024 Bdisp_GetDisp_DD
|
||||
0x025 DD_Read
|
||||
0x026 DD_ReadFromPage
|
||||
0x027 DD_WriteToPage
|
||||
0x028 Bdisp_PutDisp_DD
|
||||
0x02a Bdisp_DrawShapeToVRAM
|
||||
0x02f Bdisp_DrawShapeToVRAM
|
||||
0x030 Bdisp_DrawLineVRAM
|
||||
0x031 Bdisp_ClearLineVRAM
|
||||
0x032 Bdisp_DrawShapeToDD
|
||||
0x033 Bdisp_DrawShapeToVRAM_DD
|
||||
0x034 Bdisp_DrawShapeToDD
|
||||
0x035 Bdisp_DrawShapeToVRAM_DD
|
||||
0x039 RTC_Reset
|
||||
void RTC_Reset(unsigned int mode)
|
||||
0x03a RTC_GetTime
|
||||
void RTC_GetTime(uint *hour, uint *minute, uint *second, uint *millisecond)
|
||||
0x03b RTC_GetTicks
|
||||
int RTC_GetTicks(void)
|
||||
0x03c RTC_Elapsed_ms
|
||||
int RTC_Elapsed_ms(int start_value, int duration_ms)
|
||||
0x05c Num_UIntToBCD
|
||||
0x05d Num_BCDToUInt
|
||||
|
||||
0x118 Timer_Install
|
||||
int Timer_Install(int timerID, void *handler, int elapse), also known as Bcre_cychdr
|
||||
0x119 Timer_Deinstall
|
||||
int Timer_Deinstall(int timerID), also known as Bdel_cychdr
|
||||
0x11a Timer_Start
|
||||
int Timer_Start(int timerID)
|
||||
0x11b Timer_Stop
|
||||
int Timer_Stop(int timerID)
|
||||
0x11f Bdisp_PutDispArea_DD
|
||||
0x12d DD_Poweroff
|
||||
0x130 Wait_ms
|
||||
0x132 DD_SetContrast
|
||||
0x133 DD_SetFRS
|
||||
0x134 DD_SetBias
|
||||
0x135 GetVRAMAddress
|
||||
0x136 GetCharacterGlyph
|
||||
0x137 GetCharacterMiniGlyph
|
||||
0x138 Cursor_SetPosition
|
||||
int Cursor_SetPosition(char column, char row)
|
||||
0x139 Cursor_SetFlashStyle
|
||||
int Cursor_SetFlashStyle(short flashStyle)
|
||||
0x13a Cursor_SetFlashMode
|
||||
void Cursor_SetFlashMode(long flashMode)
|
||||
0x13b Cursor_GetSettings
|
||||
uint Cursor_GetSettings(uint *settingsArray)
|
||||
0x13c Print_OS
|
||||
void Print_OS(unsigned char *msg, int type)
|
||||
0x142 Bdisp_AllClr_DD
|
||||
0x143 Bdisp_AllClr_VRAM
|
||||
0x144 Bdisp_AllClr_DDVRAM
|
||||
0x145 Bdisp_GetDisp_VRAM
|
||||
0x146 Bdisp_SetPoint_VRAM
|
||||
0x147 Bdisp_SetPoint_DD
|
||||
0x148 Bdisp_SetPoint_DDVRAM
|
||||
0x149 Bdisp_GetPoint_VRAM
|
||||
0x14a Bdisp_AreaClr_DD
|
||||
0x14b Bdisp_AreaClr_VRAM
|
||||
0x14c Bdisp_AreaClr_DDVRAM
|
||||
0x14d Bdisp_AreaReverseVRAM
|
||||
0x150 PrintXY
|
||||
void PrintXY(int x, int y, unsigned char *msg, int type)
|
||||
0x153 Disp_Save
|
||||
0x154 Disp_Restore
|
||||
0x155 Disp_GetPtr
|
||||
0x156 PopUpWin
|
||||
0x158 Disp_Manage
|
||||
0x159 System_UpdateOS
|
||||
0x15d PrintCR
|
||||
0x15f atoi
|
||||
0x160 LongToAsc
|
||||
int LongToAsc(int value, unsigned char *dest, int digits)
|
||||
0x161 LongToAscHex
|
||||
int LongToAscHex(int value, unsigned char *dest, int digits)
|
||||
0x162 pc_toupper
|
||||
void pc_toupper(char *str)
|
||||
0x163 pc_tolower
|
||||
void pc_tolower(char *str)
|
||||
0x172 strcmp
|
||||
0x173 strcmp
|
||||
0x175 some_datatable
|
||||
0x176 DiagnosticMode
|
||||
0x18a InvertMem
|
||||
void InvertMem(void *memoryrange, int count)
|
||||
0x19f SMEM_Optimization
|
||||
void SMEM_Optimization(void)
|
||||
0x1a9 GUI_ProgressBar
|
||||
0x1b7 Get8x8BitmapPointer_1
|
||||
0x1b8 Get8x8BitmapPointer_2
|
||||
0x1b9 Get8x8BitmapPointer_3
|
||||
0x1ba Get8x8BitmapPointer_4
|
||||
0x1bb Get8x8BitmapPointer_5
|
||||
0x1bc Get8x8BitmapPointer_6
|
||||
0x1bd Get8x8BitmapPointer_7
|
||||
|
||||
0x20e StorageMemory_GetFilePos
|
||||
int StorageMemory_GetFilePos(int handle, int *pos)
|
||||
0x236 RebootOS
|
||||
0x23d RTC_TriggerAlarm
|
||||
void RTC_TriggerAlarm(void)
|
||||
0x23e RTC_SetDateTime
|
||||
void RTC_SetDateTime(unsigned char *[7] time)
|
||||
0x241 Keyboard_ClrBuffer
|
||||
0x242 Bkey_Set_RepeatTime
|
||||
0x243 Bkey_Get_RepeatTime
|
||||
0x244 Bkey_Set_RepeatTime_Default
|
||||
0x245 Keyboard_EnableAutoRepeat
|
||||
0x246 Keyboard_DisableAutoRepeat
|
||||
0x247 Keyboard_GetKeyWait
|
||||
0x248 Keyboard_PutKeycode
|
||||
0x249 Keyboard_GetKeyDownTime
|
||||
short Keyboard_GetKeyDownTime(void)
|
||||
0x24a Keyboard_IsAnyKeyDown
|
||||
int Keyboard_IsAnyKeyDown(short *matrixcode)
|
||||
0x24b Keyboard_IsSpecialKeyDown
|
||||
int Keyboard_IsSpecialKeyDown(short *matrixcode)
|
||||
0x24c Keyboard_IsSpecialKeyDown
|
||||
int Keyboard_IsSpecialKeyDown(short *matrixcode)
|
||||
0x24d Keyboard_KeyDown
|
||||
int Keyboard_KeyDown(void)
|
||||
0x24e Keyboard_SecondaryInterruptHandler
|
||||
0x24f Keyboard_PutKeymatrixCode
|
||||
int Keyboard_PutKeymatrixCode(short *matrixcode)
|
||||
0x251 Keyboard_TimerHandler
|
||||
0x25e Keyboard_PrimaryInterruptHandler
|
||||
0x268 GetFKeyIconPointer
|
||||
void GetFKeyIconPointer(int fkeyno, unsigned char *bitmap)
|
||||
0x284 BCD_GetNaN
|
||||
int BCD_GetNaN(unsigned char *value, unsigned char *result)
|
||||
0x285 Serial_Open_57600
|
||||
int Serial_Open_57600(void)
|
||||
0x286 BCD_AnsToSerial
|
||||
0x28d Comm_Open
|
||||
int Comm_Open(unsigned short parameters)
|
||||
0x28e Comm_Close
|
||||
0x28f Comm_WaitForAnyBuffer
|
||||
int Comm_WaitForAnyBuffer(int timeout_ms, int P2, int *P3)
|
||||
0x290 Comm_ReadOneByte
|
||||
int Comm_ReadOneByte(unsigned char *result)
|
||||
0x291 Comm_TransmitOneByte
|
||||
0x292 Comm_WaitForAndReadNBytes
|
||||
int Comm_WaitForAndReadNBytes(char *buffer, int bytes)
|
||||
0x293 Comm_TransmitNBytes
|
||||
0x294 Comm_ClearReceiveBuffer
|
||||
0x295 Comm_ClearTransmitBuffer
|
||||
0x296 Comm_IsValidPacketAvailable
|
||||
int Comm_IsValidPacketAvailable(unsigned char *result)
|
||||
0x298 Comm_IsOpen
|
||||
0x299 Comm_GetCurrentSelector
|
||||
int Comm_GetCurrentSelector(void)
|
||||
0x2a1 HexToByte
|
||||
int HexToByte(short *hex, char *result)
|
||||
0x2a2 HexToWord
|
||||
int HexToWord(int *hex, short *result)
|
||||
0x2a3 ByteToHex
|
||||
0x2a4 WordToHex
|
||||
0x2a5 Comm_Padding_5C
|
||||
0x2a6 Comm_ReversePadding_5C
|
||||
0x2a7 AscHexToNibble
|
||||
void AscHexToNibble(char hex, char *result)
|
||||
0x2a8 NibbleToAscHex
|
||||
0x2a9 strlen
|
||||
0x2aa slow_memcpy
|
||||
0x2ab Serial_Open2
|
||||
int Serial_Open2(unsigned short parameters)
|
||||
0x2af Comm_Spy0thByte
|
||||
int Comm_Spy0thByte(unsigned char *result)
|
||||
0x2db Comm_ProcessInPacket
|
||||
int Comm_ProcessInPacket(TReceivePacketDesc *rpd)
|
||||
0x2e1 Comm_PrepareAckPacket
|
||||
int Comm_PrepareAckPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
|
||||
0x2e2 Comm_PrepareErrorPacket
|
||||
void Comm_PrepareErrorPacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||
0x2e3 Comm_PrepareTerminatePacket
|
||||
void Comm_PrepareTerminatePacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||
0x2e4 Comm_PrepareRoleswapPacket
|
||||
void Comm_PrepareRoleswapPacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||
0x2e5 Comm_PrepareCheckPacket
|
||||
void Comm_PrepareCheckPacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||
0x2e6 Comm_PrepareCommandPacket
|
||||
int Comm_PrepareCommandPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
|
||||
0x2e7 Comm_PrepareDataPacket
|
||||
int Comm_PrepareDataPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
|
||||
0x2ee System_GetOSVersion
|
||||
void System_GetOSVersion(unsigned char *version)
|
||||
|
||||
0x35e memset_range
|
||||
0x35f memset
|
||||
0x363 MCS_CreateDirectory
|
||||
int MCS_CreateDirectory(unsigned char *dir, char *dirno)
|
||||
0x364 MCS_WriteItem
|
||||
int MCS_WriteItem(unsigned char *dir, unsigned char *item, short itemType, int data_length, int buffer)
|
||||
0x366 MCS_DeleteDirectory
|
||||
int MCS_DeleteDirectory(unsigned char *dir)
|
||||
0x367 MCS_DeleteItem
|
||||
int MCS_DeleteItem(unsigned char *dir, unsigned char *item)
|
||||
0x368 MCS_GetState
|
||||
int MCS_GetState(int *maxspace, int *currentload, int *remainingspace)
|
||||
0x369 MCS_GetSystemDirectoryInfo
|
||||
int MCS_GetSystemDirectoryInfo(unsigned char *dir, unsigned int *pdir, char *dirno)
|
||||
0x370 MCS_RenameItem
|
||||
int MCS_RenameItem(unsigned char *srcdir, unsigned char *srcitem, unsigned char *tgtdir, int tgtitem)
|
||||
0x371 MCS_OverwriteData
|
||||
int MCS_OverwriteData(unsigned char *dir, unsigned char *item, int write_offset, int bytes_to_write, void *buffer)
|
||||
0x372 MCS_GetItemData
|
||||
int MCS_GetItemData(unsigned char *dir, unsigned char *item, int offset, int bytes_to_read, void *buffer)
|
||||
0x373 MCS_RenameDirectory
|
||||
int MCS_RenameDirectory(unsigned char *oldname, unsigned char *newname)
|
||||
0x374 BMCSRenameVariable
|
||||
0x375 MCS_SearchDirectory
|
||||
int MCS_SearchDirectory(unsigned char *dir, TMainMemoryDirectoryEntry *dir, char *dirno)
|
||||
0x376 MCS_SearchDirectoryItem
|
||||
int MCS_SearchDirectoryItem(unsigned char *dir, unsigned char *item, char *flags_0, TDirectoryItem *item, int *data, int *data_length)
|
||||
0x37c MCS_GetFirstDataPointerByDirno
|
||||
int MCS_GetFirstDataPointerByDirno(char *dirno, void *pdata)
|
||||
0x37d MCS_GetDirectoryEntryByNumber
|
||||
int MCS_GetDirectoryEntryByNumber(char dirno, TMainMemoryDirectoryEntry *pdir)
|
||||
0x37e MCS_SearchItem
|
||||
int MCS_SearchItem(unsigned char *item, TMainMemoryDirectoryEntry *pdir, unsigned short *itemno)
|
||||
0x37f MCS_str8cpy
|
||||
int MCS_str8cpy(unsigned char *source, unsigned char *target, int mode)
|
||||
0x380 MCS_GetDirectoryEntryAddress
|
||||
void MCS_GetDirectoryEntryAddress(void *directory_entry_address)
|
||||
0x381 MCS_GetCurrentBottomAddress
|
||||
void MCS_GetCurrentBottomAddress(void *current_bottom_address)
|
||||
0x383 MCS_GetCapa
|
||||
int MCS_GetCapa(int *current_bottom)
|
||||
0x392 MCS_GetMainMemoryStart
|
||||
int MCS_GetMainMemoryStart(void)
|
||||
0x3dc Setup_GetInfo
|
||||
int Setup_GetInfo(unsigned char *, int, TSetupInfo *info), where the first arguments are used only in fx-CG 10/20
|
||||
0x3ea the start of a datatable ***
|
||||
0x3ed Interrupt_SetOrClrStatusFlags
|
||||
int Interrupt_SetOrClrStatusFlags(int flagmask, int set)
|
||||
0x3ee Interrupt_QueryStatusFlags
|
||||
int Interrupt_QueryStatusFlags(int flagmask, int clear)
|
||||
0x3f4 PowerOff
|
||||
0x3f5 ClearMainMemory
|
||||
0x3f6 SH7337_TMU_Stop
|
||||
0x3f7 SH7337_TMU_int_handler
|
||||
0x3fa Hmem_SetMMU
|
||||
void Hmem_SetMMU(int virtualPageNumber, int physicalPageNumber, int pageManagement)
|
||||
0x3fb MMU_ConfigureAndFlush
|
||||
void MMU_ConfigureAndFlush(void)
|
||||
0x3fc TLB_SetAddressValue
|
||||
void TLB_SetAddressValue(int entryAddress, int way, int value)
|
||||
0x3fe GetStackPtr
|
||||
0x3ff MMU_FlushCache
|
||||
|
||||
0x400 MMU_ConfigureAndEnable
|
||||
void MMU_ConfigureAndEnable(void)
|
||||
0x404 GetPhysicalROMstart
|
||||
0x405 GetPhysicalRAMstart
|
||||
0x409 Serial_ResetAndDisable
|
||||
void *Serial_ResetAndDisable(void)
|
||||
0x40a Serial_GetInterruptHandler
|
||||
void *Serial_GetInterruptHandler(void)
|
||||
0x40b Serial_SetInterruptHandler
|
||||
int Serial_SetInterruptHandler(int type, void *handler)
|
||||
0x40c Serial_ReadOneByte
|
||||
int Serial_ReadOneByte(unsigned char *result)
|
||||
0x40d Serial_ReadNBytes
|
||||
int Serial_ReadNBytes(unsigned char *result, int max_size, short *actually_transferred)
|
||||
0x40e Serial_BufferedTransmitOneByte
|
||||
int Serial_BufferedTransmitOneByte(unsigned char byte)
|
||||
0x40f Serial_BufferedTransmitNBytes
|
||||
int Serial_BufferedTransmitNBytes(unsigned char *bytes, int requested_count)
|
||||
0x410 Serial_DirectTransmitOneByte
|
||||
int Serial_DirectTransmitOneByte(unsigned char byte)
|
||||
0x411 Serial_GetReceivedBytesAvailable
|
||||
int Serial_GetReceivedBytesAvailable(void)
|
||||
0x412 Serial_GetFreeTransmitSpace
|
||||
int Serial_GetFreeTransmitSpace(void)
|
||||
0x413 Serial_ClearReceiveBuffer
|
||||
int Serial_ClearReceiveBuffer(void)
|
||||
0x414 Serial_ClearTransmitBuffer
|
||||
int Serial_ClearTransmitBuffer(void)
|
||||
0x418 Serial_Open
|
||||
int Serial_Open(unsigned char *mode)
|
||||
0x419 Serial_Close(int mode)
|
||||
0x41b Serial_CallReceiveIntErrorResetHandler
|
||||
void *Serial_CallReceiveIntErrorResetHandler(void)
|
||||
0x41c Serial_CallReceiveIntHandler
|
||||
void *Serial_CallReceiveIntHandler(void)
|
||||
0x41d Serial_CallTransmitIntErrorResetHandler
|
||||
void *Serial_CallTransmitIntErrorResetHandler(void)
|
||||
0x41e Serial_CallTransmitIntHandler
|
||||
void *Serial_CallTransmitIntHandler(void)
|
||||
0x420 OS_inner_Sleep
|
||||
0x422 Serial_SpyNthByte
|
||||
int Serial_SpyNthByte(int byteno_to_spy, unsigned char *result)
|
||||
0x423 Serial_GetStatus
|
||||
void Serial_GetStatus(unsigned int *serial_status)
|
||||
0x425 Serial_IsOpen
|
||||
int Serial_IsOpen(void)
|
||||
0x429 Bfile_identify_device_OS
|
||||
int Bfile_identify_device_OS(const FONTCHARACTER *filename)
|
||||
0x42c Bfile_OpenFile_OS
|
||||
0x42d Bfile_CloseFile_OS
|
||||
0x42e Bfile_GetMediaFree_OS
|
||||
0x42f Bfile_GetFileSize_OS
|
||||
0x431 Bfile_SeekFile_OS
|
||||
0x432 Bfile_ReadFile_OS
|
||||
0x434 Bfile_CreateEntry_OS
|
||||
0x435 Bfile_WriteFile_OS
|
||||
0x438 Bfile_RenameEntry
|
||||
0x439 Bfile_DeleteEntry
|
||||
0x43b Bfile_FindFirst
|
||||
0x43c Bfile_FindNext
|
||||
0x43d Bfile_FindClose
|
||||
0x44e memcpy
|
||||
0x44f memcmp
|
||||
0x450 Bfile_GetFilenameLength
|
||||
int Bfile_GetFilenameLength(const FONTCHARACTER *filename)
|
||||
0x451 Bfile_Name_cmp
|
||||
0x452 Bfile_Name_cpy
|
||||
0x453 Bfile_Name_ncpy
|
||||
0x456 Bfile_NameToStr_ncpy
|
||||
void Bfile_NameToStr_ncpy(char *dest, FONTCHARACTER *src, int n)
|
||||
0x457 Bfile_StrToName_ncpy
|
||||
void Bfile_StrToName_ncpy(FONTCHARACTER *dest, char *src, int n)
|
||||
0x462 GetAppName
|
||||
char *GetAppName(char *dest)
|
||||
0x463 SetAppName
|
||||
int SetAppName(char *src)
|
||||
0x464 CmpAppName
|
||||
int CmpAppName(char *name)
|
||||
0x465 GetIntPtrContent
|
||||
int GetIntPtrContent(unsigned char *ptr)
|
||||
0x467 LongToAscHex
|
||||
int LongToAscHex(int value, char *dest, int digits)
|
||||
0x468 hasSDOption
|
||||
0x469 Battery_DisplayLowStatus
|
||||
int Battery_DisplayLowStatus(int delayflag)
|
||||
0x46b App_BuiltInCount
|
||||
int App_BuiltInCount(void)
|
||||
0x476 Battery_IsLow
|
||||
int Battery_IsLow(void)
|
||||
0x477 EnableGetkeyToMainFunctionReturn
|
||||
void EnableGetkeyToMainFunctionReturn(void)
|
||||
0x478 DisableGetkeyToMainFunctionReturn
|
||||
void DisableGetkeyToMainFunctionReturn(void)
|
||||
0x47f SetAutoPowerOffTime
|
||||
0x480 GetAutoPowerOffTime
|
||||
0x486 GetdatatablePtr
|
||||
0x48d SetAutoPowerOffFlag
|
||||
0x48e GetAutoPowerOffFlag
|
||||
0x492 Battery_IsLow
|
||||
int Battery_IsLow(int delayflag)
|
||||
0x494 CallbackAtQuitMainFunction
|
||||
0x495 Battery_DisplayLowStatus
|
||||
int Battery_DisplayLowStatus(int delayflag)
|
||||
0x499 Heap_SetTopChunk
|
||||
int Heap_SetTopChunk(int size)
|
||||
0x49a App_Start
|
||||
int App_Start(int r4, int r5, int index, int force)
|
||||
0x49c Battery_GetStatus
|
||||
int Battery_GetStatus(int delayflag)
|
||||
0x49e RebootOS
|
||||
0x4a0 AUX_DisplayErrorMessage
|
||||
void AUX_DisplayErrorMessage(void)
|
||||
0x4ad USB_InterruptHandler
|
||||
0x4ae USB_TimerHandler
|
||||
void USB_TimerHandler(void)
|
||||
0x4b0 AUX_DisplayFKeyIcons
|
||||
void AUX_DisplayFKeyIcons(void)
|
||||
0x4cb Keyboard_RemapFKeyCode
|
||||
void Keyboard_RemapFKeyCode(int mode, TFKeyDef *source)
|
||||
0x4d1 AUX_DisplayFKeyIcon
|
||||
void AUX_DisplayFKeyIcon(int pos, unsigned char *bitmap)
|
||||
0x4dc char Setup_GetEntry(unsigned int index)
|
||||
0x4dd Setup_SetEntry
|
||||
char *Setup_SetEntry(unsigned int index, char setting)
|
||||
0x4de Setup_GetEntryPtr
|
||||
char *Setup_GetEntryPtr(unsigned int index)
|
||||
0x4df Alpha_GetData
|
||||
char *Alpha_GetData(char var, char *dest)
|
||||
0x4e0 Alpha_SetData
|
||||
char *Alpha_SetData(char var, char *src)
|
||||
0x4e1 Alpha_ClearAll
|
||||
void Alpha_ClearAll(void)
|
||||
0x4e6 HourGlass
|
||||
void HourGlass(void)
|
||||
0x4e9 LocalizeStringID
|
||||
0x4f5 BCD_ToStrAsNumber1
|
||||
int BCD_ToStrAsNumber1(char *data, char *string)
|
||||
0x4f6 BCD_ToStrAsNumber2
|
||||
int BCD_ToStrAsNumber2(char *data, char *string)
|
||||
|
||||
0x500 BCDToInternal
|
||||
int BCDToInternal(TBCDinternal *target, TBCDvalue *source)
|
||||
0x518 Setup_GetEntry_3E
|
||||
0x519 Setup_GetEntry_40
|
||||
0x51a Setup_SetEntry_3E
|
||||
0x51b Setup_SetEntry_40
|
||||
0x531 MB_IsLead
|
||||
int MB_IsLead(char c)
|
||||
0x533 MB_ElementCount
|
||||
int MB_ElementCount(char *str)
|
||||
0x534 MB_ByteCount
|
||||
int MB_ByteCount(char *str)
|
||||
0x536 MB_strcat
|
||||
char *MB_strcat(char *dest, char *src)
|
||||
0x537 MB_strncat
|
||||
char *MB_strncat(char *dest, char *src, int bytes)
|
||||
0x538 MB_strcpy
|
||||
char *MB_strcpy(char *dest, char *src)
|
||||
0x53c MB_GetSecondElemPtr
|
||||
char *MB_GetSecondElemPtr(char *str)
|
||||
0x53d MB_GetElement
|
||||
short MB_GetElement(char *str)
|
||||
0x53e MB_CopyToHeap
|
||||
char *MB_CopyToHeap(char *src)
|
||||
0x53f memcmp
|
||||
0x541 itoa
|
||||
0x542 to_uppercase
|
||||
0x543 to_lowercase
|
||||
0x544 BCD_0
|
||||
0x545 BCD_1
|
||||
0x546 BCD_2
|
||||
0x547 BCD_10
|
||||
0x548 BCD_1/3
|
||||
0x549 BCD_0.5
|
||||
0x54a BCD_32767
|
||||
0x54b BCD_-32768
|
||||
0x54c BCD_65536
|
||||
0x54d BCD_0x7fffffff
|
||||
0x54e BCD_-2Gi
|
||||
0x54f BCD_4Gi
|
||||
0x550 BCD_pi
|
||||
0x551 BCD_2pi
|
||||
0x552 BCD_pi/2
|
||||
0x553 BCD_e
|
||||
0x554 BCD_5
|
||||
0x5a6 BCD_SetAsInt
|
||||
int BCD_SetAsInt(int input, TBCDValue *result)
|
||||
0x5af BCD_pi/4
|
||||
0x5b0 BCD_ln(10)
|
||||
0x5b1 BCD_ln(2)
|
||||
0x5b2 BCD_9.99e+99
|
||||
0x5b3 BCD_-9.99e+99
|
||||
0x5b4 BCD_9.99999999999999e+99
|
||||
0x5b5 BCD_227.85
|
||||
0x5b6 BCD_sqrt(2)
|
||||
0x5b7 BCD_sqrt(2)/2
|
||||
0x5b8 BCD_506.6282746310
|
||||
|
||||
0x645 CalculateExpression
|
||||
void CalculateExpression(char **formula, char opcode[2], TBCDValue *result, int p4)
|
||||
0x64a CalculateExpression0
|
||||
0x652 PRGM_NextOpcode
|
||||
void PRGM_NextOpcode(char opcode[2], char **program)
|
||||
0x6a6 PRGM_IsEndOfLine
|
||||
int PRGM_IsEndOfLine(char *opcode)
|
||||
0x6c4 Keyboard_PRGM_GetKey
|
||||
int Keyboard_PRGM_GetKey(TBCDValue *result)
|
||||
0x6d4 Alpha_GetData2
|
||||
int Alpha_GetData2(char var, char *dest)
|
||||
|
||||
0x713 Print_ClearLine
|
||||
0x763 Bdisp_DrawRectangle
|
||||
void Bdisp_DrawRectangle(int x1, int y1, int x2, int y2)
|
||||
0x7fc OpcodeToStr
|
||||
int OpcodeToStr(unsigned short opcode, unsigned char *string)
|
||||
|
||||
0x804 CLIP_Store
|
||||
int CLIP_Store(unsigned char *buffer, int length)
|
||||
0x807 locate
|
||||
0x808 Print
|
||||
0x809 PrintRev
|
||||
0x80a PrintC
|
||||
0x80b PrintRevC
|
||||
0x80c PrintLine
|
||||
0x80d PrintRLine
|
||||
0x80e Cursor_GetFlashStyle
|
||||
int Cursor_GetFlashStyle(void)
|
||||
0x80f Cursor_GetSettings
|
||||
int Cursor_GetSettings(struct CursorSettings *settings)
|
||||
0x811 Cursor_SetFlashOn
|
||||
void Cursor_SetFlashOn(char flash_style)
|
||||
0x812 Cursor_SetFlashOff
|
||||
void Cursor_SetFlashOff(void)
|
||||
0x813 SaveDisp
|
||||
0x814 RestoreDisp
|
||||
0x829 MCS_CreateDirectory
|
||||
unsigned char *MCS_CreateDirectory(unsigned char *dir)
|
||||
0x82a MCS_PutInternalItem
|
||||
int MCS_PutInternalItem(char dirtype, unsigned char *item, int data_len, void *buffer)
|
||||
0x82b MCSPutVar2
|
||||
int MCSPutVar2(unsigned char *dir, unsigned char *item, int data_len, void *buffer)
|
||||
0x830 MCSOvwDat2
|
||||
int MCSOvwDat2(unsigned char *dir, unsigned char *item, int bytes_to_write, void *buffer, int write_offset)
|
||||
0x832 MCS_OverwriteOpenItem
|
||||
int MCS_OverwriteOpenItem(int bytes_to_write, void *buffer, int write_offset)
|
||||
0x833 MCS_ClearInternalDirectory
|
||||
int MCS_ClearInternalDirectory(char dirtype)
|
||||
0x834 MCS_ClearDirectory
|
||||
int MCS_ClearDirectory(unsigned char *dir)
|
||||
0x835 MCS_DeleteInternalItem
|
||||
int MCS_DeleteInternalItem(char dirtype, unsigned char *dir)
|
||||
0x836 MCSDelVar2
|
||||
int MCSDelVar2(unsigned char *dir, unsigned char *item)
|
||||
0x83a MCS_GotoInternalItem
|
||||
int MCS_GotoInternalItem(char dirtype, unsigned char *item, int direction)
|
||||
0x83b MCS_OpenMainMemoryItem
|
||||
int MCS_OpenMainMemoryItem(unsigned char *dir, unsigned char *item, char direction)
|
||||
0x83c MCS_GotoHandleNeighbour
|
||||
int MCS_GotoHandleNeighbour(char direction)
|
||||
0x83d MCS_CheckOpenedItem
|
||||
int MCS_CheckOpenedItem(char *dirtype, int *data_len)
|
||||
0x83e MCS_GetOpenItem
|
||||
int MCS_GetOpenItem(unsigned char *item)
|
||||
0x83f MCS_OpenInternalDirectoryItem
|
||||
int MCS_OpenInternalDirectoryItem(char dirtype, unsigned char *item, int *data_len)
|
||||
0x840 MCSGetDlen2
|
||||
int MCSGetDlen2(unsigned char *dir, unsigned char *item, int *data_len)
|
||||
0x841 MCSGetData1
|
||||
int MCSGetData1(int offset, int len_to_copy, void *buffer)
|
||||
0x843 MCS_MapMCS_Result
|
||||
int MCS_MapMCS_Result(void)
|
||||
0x844 MCSGetCapa
|
||||
0x84d MCS_OpenAlphaMemItem
|
||||
int MCS_OpenAlphaMemItem(char variablename, int *data_len, void *data_ptr)
|
||||
0x852 MCS_DirtypeToItemtype
|
||||
int MCS_DirtypeToItemtype(char dirtype)
|
||||
0x853 MCS_ItemtypeToDirtype
|
||||
int MCS_ItemtypeToDirtype(char itemtype)
|
||||
0x863 MCS_DirtypeToName
|
||||
unsigned char *MCS_DirtypeToName(char dirtype)
|
||||
0x866 MCS_MapError
|
||||
int MCS_MapError(int error_in)
|
||||
0x869 Alpha_ClearAllAndAns
|
||||
void Alpha_ClearAllAndAns(void)
|
||||
0x86f MCS_DeleteDirectoryItems
|
||||
void MCS_DeleteDirectoryItems(unsigned char *dir)
|
||||
0x8db EditExpression
|
||||
int EditExpression(int mode, short key, int row, TBCDValue *value, char *editbuffer, short editbufferlen, char *pretext, int mode2)
|
||||
0x8dc EditValue
|
||||
int EditValue(int mode, short key, int row, TBCDValue *value, char *pretext)
|
||||
0x8e6 EditMBStringCtrl
|
||||
void EditMBStringCtrl(unsigned char *, int xposmax, void *, void *, void *, int, int)
|
||||
0x8ea DisplayMBString
|
||||
void DisplayMBString(unsigned char *, int, int xpos, int x, int y)
|
||||
0x8ec EditMBStringChar
|
||||
void EditMBStringChar(unsigned char *, int xposmax, int xpos, int char)
|
||||
0x8f7 DisplayMBString2
|
||||
void DisplayMBString2(int, unsigned char *, int, int xpos, int zero, int x, int y, int, int, int)
|
||||
0x8fe PopupWin
|
||||
void PopupWin(int nlines)
|
||||
|
||||
0x901 DisplayMessageBox
|
||||
void DisplayMessageBox(int height, unsigned char *message)
|
||||
0x905 DisplayErrorMessage
|
||||
void DisplayErrorMessage(int id)
|
||||
0x90b SetShiftAlphaState
|
||||
0x90c GetInsOverwriteState
|
||||
0x90d SetInsOverwriteState
|
||||
0x90e ClrShiftAlphaState
|
||||
0x90f GetKey
|
||||
int GetKey(unsigned int *keycode)
|
||||
0x910 PutKey
|
||||
int PutKey(int keycode, int mode)
|
||||
0x91b GetShiftAlphaState
|
||||
0x924 TestMode
|
||||
void TestMode(void)
|
||||
0x954 DisplayErrorMessage
|
||||
0x985 App_CONICS
|
||||
0x998 App_DYNA
|
||||
0x9ad PrintXY
|
||||
0x9df App_EACT
|
||||
0x9e1 App_Equation
|
||||
0x9e2 App_EQUA
|
||||
0x9f5 App_Program
|
||||
|
||||
0xa00 App_FINANCE
|
||||
0xa1f Keyboard_RemapFKeyCode
|
||||
void Keyboard_RemapFKeyCode(TKeyDef *workspace, TKeyDef *source, int mode)
|
||||
0xa35 AUX_DisplayMessage
|
||||
0xa48 App_GRAPH_TABLE
|
||||
0xa4a App_LINK
|
||||
0xa6a App_Optimization
|
||||
0xa6b App_Memory
|
||||
0xa75 App_RECUR
|
||||
0xa97 App_RUN_MAT_EXE
|
||||
0xaae App_RUN_MAT
|
||||
0xac6 App_STAT
|
||||
0xac8 App_SYSTEM
|
||||
0xacc free
|
||||
0xacd malloc
|
||||
0xace memcmp
|
||||
0xacf smart_memcpy
|
||||
0xad0 memset
|
||||
0xad4 strcat
|
||||
0xad5 smart_strcmp
|
||||
0xad6 strlen
|
||||
0xad7 strncat
|
||||
0xad8 strncmp
|
||||
0xad9 strncpy
|
||||
0xada strrchr
|
||||
0xae8 CatalogDialog
|
||||
|
||||
0xc4f PrintMiniSd
|
||||
0xca7 OpcodeType
|
||||
int OpcodeType(char *);
|
||||
0xcb0 Basic_Send_Send38k
|
||||
0xcb1 Basic_Receive_Receive38k
|
||||
0xcb2 Basic_OpenComPort38k_CloseComPort38k
|
||||
0xcc4 InputNumber
|
||||
int InputNumber(unsigned char *heading, int maxlen, int mode)
|
||||
0xcc5 InputString
|
||||
int InputString(unsigned char *buffer, unsigned char *heading, int maxlen)
|
||||
0xccb GetRAMSize
|
||||
int GetRAMSize(void)
|
||||
0xcd0 another_diagnostic_dialog
|
||||
|
||||
0xd64 InputDateDialog
|
||||
int InputDateDialog(int *day, int *month, int *year, int *p4)
|
||||
0xd65 InputMonthDialog
|
||||
int InputMonthDialog(int *month, int *p2)
|
||||
0xd66 InputDayDialog
|
||||
int InputDayDialog(int *day, int *p2)
|
||||
0xd67 InputYearDialog
|
||||
int InputYearDialog(int *year, int *p2)
|
||||
0xdab StoreExpressionToGraphFuncMemory
|
||||
void StoreExpressionToGraphFuncMemory(int fun_no, int, char *expression)
|
||||
|
||||
0xe6b calloc
|
||||
0xe6c memmove
|
||||
0xe6d realloc
|
||||
0xe6e strchr
|
||||
0xe6f strstr
|
59
fxos/sys.c
Normal file
59
fxos/sys.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <util.h>
|
||||
#include <string.h>
|
||||
|
||||
/* sys_free_item(): Free a syscall description item */
|
||||
static void sys_free_item(void *item)
|
||||
{
|
||||
struct sys_call *call = item;
|
||||
free(call->name);
|
||||
free(call->descr);
|
||||
}
|
||||
|
||||
/* sys_load(): Load a syscall table */
|
||||
void sys_load(char const *file)
|
||||
{
|
||||
err_context("syscall", file, NULL);
|
||||
if(!table_available())
|
||||
{
|
||||
err("too many tables, skipping");
|
||||
err_pop();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Map the file to memory */
|
||||
int fd;
|
||||
size_t size;
|
||||
void *data = map(file, &fd, &size);
|
||||
if(!data) { err_pop(); return; }
|
||||
|
||||
/* If the file is named "sys-x.txt", use "x" as the table name */
|
||||
char *name = match_table_name(file, "sys", ".txt");
|
||||
|
||||
/* Parse the contents */
|
||||
int count;
|
||||
struct sys_call *calls = lex_sys(data, size, &count);
|
||||
|
||||
table_create("sys", name, sys_free_item, count, sizeof *calls, calls);
|
||||
|
||||
unmap(data, fd, size);
|
||||
err_pop();
|
||||
}
|
||||
|
||||
/* Global storage for the sys_match() function */
|
||||
static uint32_t sys_match_number;
|
||||
|
||||
/* sys_match(): Search routine for sys_find() */
|
||||
static int sys_match(void *item)
|
||||
{
|
||||
struct sys_call *call = item;
|
||||
return call->number == sys_match_number;
|
||||
}
|
||||
|
||||
/* sys_find(): Find information on a given syscall number */
|
||||
struct sys_call const *sys_find(uint32_t number)
|
||||
{
|
||||
sys_match_number = number;
|
||||
return table_find("sys", sys_match, NULL, 0);
|
||||
}
|
115
fxos/tables.c
115
fxos/tables.c
|
@ -1,59 +1,82 @@
|
|||
#include <stdlib.h>
|
||||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
#include <string.h>
|
||||
|
||||
/* A linked list of pointers (either file names or tables) */
|
||||
struct element
|
||||
/* Up to 128 tables can be defined */
|
||||
#define MAX 128
|
||||
static struct table db[MAX] = { 0 };
|
||||
/* Number of tables currently used */
|
||||
static int db_size = 0;
|
||||
|
||||
/* table_free(): Free a table and its contents
|
||||
@t Table pointer */
|
||||
static void table_free(struct table *t)
|
||||
{
|
||||
void *data;
|
||||
struct element *next;
|
||||
};
|
||||
if(!t) return;
|
||||
free(t->name);
|
||||
|
||||
/* list_append(): Append a pointer to a linked list
|
||||
Returns a pointer to the new node, NULL on error. */
|
||||
struct element *list_append(struct element **head, void *data)
|
||||
{
|
||||
struct element *el = malloc(sizeof *el);
|
||||
if(!el) return NULL;
|
||||
el->data = data;
|
||||
el->next = NULL;
|
||||
|
||||
while(*head) head = &((*head)->next);
|
||||
*head = el;
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
/* list_free(): Free a linked list */
|
||||
void list_free(struct element *head, void (*destructor)(void *))
|
||||
{
|
||||
struct element *next;
|
||||
while(head)
|
||||
if(t->items) for(int i = 0; i < t->count; i++)
|
||||
{
|
||||
destructor(head->data);
|
||||
next = head->next;
|
||||
free(head);
|
||||
head = next;
|
||||
t->free_item(t->items + i * t->size);
|
||||
}
|
||||
free(t->items);
|
||||
}
|
||||
|
||||
/* Table of assembly instruction listings */
|
||||
static struct element *tasm = NULL;
|
||||
/* Table of system call information listings */
|
||||
static struct element *tcall = NULL;
|
||||
|
||||
|
||||
/*
|
||||
** Public API
|
||||
*/
|
||||
|
||||
/* tables_add_asm(): Append an instruction table to the table list */
|
||||
int tables_add_asm(const char *filename)
|
||||
/* table_quit(): Destroy all allocated tables and release memory */
|
||||
__attribute__((destructor))
|
||||
static void table_quit(void)
|
||||
{
|
||||
return !list_append(&tasm, (void *)filename);
|
||||
for(int i = 0; i < db_size; i++) table_free(&db[i]);
|
||||
}
|
||||
|
||||
/* tables_add_syscall(): Append a syscall table to the table list */
|
||||
int tables_add_syscall(const char *filename)
|
||||
/* table_available(): Whether a table can be allocated */
|
||||
int table_available(void)
|
||||
{
|
||||
return !list_append(&tcall, (void *)filename);
|
||||
return db_size < MAX;
|
||||
}
|
||||
|
||||
/* table_create(): Create a new table */
|
||||
void table_create(char const *type, char *name, void (*free_item)(void *),
|
||||
int count, size_t size, void *items)
|
||||
{
|
||||
if(!table_available()) return;
|
||||
struct table *t = &db[db_size++];
|
||||
|
||||
t->type = type;
|
||||
t->name = name;
|
||||
t->free_item = free_item;
|
||||
t->count = count;
|
||||
t->size = size;
|
||||
t->items = items;
|
||||
}
|
||||
|
||||
/* table_find(): Find matching entries in the database tables */
|
||||
void *table_find(char const *type, int (*match)(void *), char const **name,
|
||||
int next)
|
||||
{
|
||||
static int table = 0;
|
||||
static int index = 0;
|
||||
if(!next) table = index = 0;
|
||||
|
||||
while(table < db_size)
|
||||
{
|
||||
struct table const *t = &db[table];
|
||||
|
||||
if(!strcmp(t->type, type))
|
||||
while(index < t->count)
|
||||
{
|
||||
void *entry = t->items + index * t->size;
|
||||
index++;
|
||||
if(match(entry))
|
||||
{
|
||||
if(name) *name = t->name;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
table++;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
72
fxos/util.c
72
fxos/util.c
|
@ -1,10 +1,18 @@
|
|||
#include <fxos.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <fxos.h>
|
||||
#include <errors.h>
|
||||
|
||||
/* integer(): Convert base 8, 10 or 16 into integers */
|
||||
long long integer(const char *str, int *error)
|
||||
long long integer(char const *str, int *error)
|
||||
{
|
||||
char *end;
|
||||
errno = 0;
|
||||
|
@ -28,3 +36,63 @@ long long integer(const char *str, int *error)
|
|||
|
||||
return ll;
|
||||
}
|
||||
|
||||
/* match_table_name(): Some specific matching on filenames */
|
||||
char *match_table_name(char const *path, char const *type, char const *suffix)
|
||||
{
|
||||
char const *base = strrchr(path, '/');
|
||||
base = (base) ? (base + 1) : (path);
|
||||
|
||||
size_t len = strlen(base);
|
||||
size_t len_t = strlen(type);
|
||||
size_t len_s = strlen(suffix);
|
||||
|
||||
if(len > len_t + len_s + 1
|
||||
&& !strncmp(type, base, len_t)
|
||||
&& base[len_t] == '-'
|
||||
&& !strcmp(suffix, base + len - len_s))
|
||||
{
|
||||
return strndup(base + len_t + 1, len - len_t - len_s - 1);
|
||||
}
|
||||
|
||||
return strdup(base);
|
||||
}
|
||||
|
||||
/* map(): Map a file to memory */
|
||||
void *map(char const *path, int *fd, size_t *size)
|
||||
{
|
||||
int x;
|
||||
struct stat statbuf;
|
||||
|
||||
*fd = open(path, O_RDONLY);
|
||||
if(*fd < 0)
|
||||
{
|
||||
errf(ERR_ERRNO, "cannot open file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x = fstat(*fd, &statbuf);
|
||||
if(x < 0)
|
||||
{
|
||||
errf(ERR_ERRNO, "cannot stat file");
|
||||
close(*fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size = statbuf.st_size;
|
||||
|
||||
void *data = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, *fd, 0);
|
||||
if(data == MAP_FAILED)
|
||||
{
|
||||
errf(ERR_ERRNO, "cannot map file");
|
||||
close(*fd);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/* unmap(): Unmap a file loaded with map() */
|
||||
void unmap(void *data, int fd, size_t size)
|
||||
{
|
||||
munmap(data, size);
|
||||
close(fd);
|
||||
}
|
||||
|
|
44
fxos/util.h
Normal file
44
fxos/util.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
//---
|
||||
// util: Utility functions
|
||||
//---
|
||||
|
||||
#ifndef FXOS_UTIL
|
||||
#define FXOS_UTIL
|
||||
|
||||
/* integer(): Convert base 8, 10 or 16 into integers
|
||||
Prints an error message and sets *error to 1 in case of conversion error or
|
||||
overflow.
|
||||
|
||||
@str Original integer representation ("10", "0x1f", "07")
|
||||
@error Set to 1 on error, otherwise unchanged (can be NULL)
|
||||
Returns result of conversion (valid if *error is not 1) */
|
||||
long long integer(const char *str, int *error);
|
||||
|
||||
/* match_table_name(): Some specific matching on filenames
|
||||
Returns the table name to associate with the file located at @path for a
|
||||
table of type @type, with file suffix @suffix.
|
||||
|
||||
Essentially if the basename of the file at @path is on the form
|
||||
{@type}-{x}{@suffix}
|
||||
then an malloc'ed copy of x is returned. Otherwise an malloc'ed copy of the
|
||||
basename is returned. */
|
||||
char *match_table_name(char const *path, char const *type, char const *suffix);
|
||||
|
||||
/* map(): Map a file to memory
|
||||
Maps a file given by its path to memory, and return the associated region,
|
||||
a file descriptor and the size.
|
||||
|
||||
@path File path
|
||||
@fd Will be set to fd of open file
|
||||
@size Will be set to file size
|
||||
Returns NULL no error, in which case the file is closed and [*fd] and
|
||||
[*size] are undefined; otherwise, returns a pointer to mapped data. */
|
||||
void *map(char const *path, int *fd, size_t *size);
|
||||
|
||||
/* unmap(): Unmap a file loaded with map()
|
||||
@data Region returned by map()
|
||||
@fd File descriptor set by map()
|
||||
@size Size set by map() */
|
||||
void unmap(void *data, int fd, size_t size);
|
||||
|
||||
#endif /* FXOS_UTIL */
|
Loading…
Reference in a new issue