rizin/test/db/analysis/tms320.c54x_32
Anton Kochkov fee84c7f5c librz/bin/coff: scale addresses on word-addressed TI targets
The C54x and C28x address 16-bit words, so their loadable section sizes
and every address in the file count words. Rizin's address space is
byte-based, so reading those unscaled mapped only half of each loadable
section and placed every symbol at half its true offset: _main in the
c54x emulateme object landed mid-instruction instead of on its prologue.

Scale section VAs, loadable section sizes and symbol addresses by the
target's address unit. Debug sections are byte streams even on these
targets and keep a scale of one, matching the loadable mask already used
for mapping. The C55x addresses program memory by byte and is left
alone; the ids were checked against the objects in rizin-testbins by
comparing each section's declared size against its extent in the file.

Branch and call targets on the C54x count program words too, and reached
analysis and RzIL unscaled. That went unnoticed while the sections were
half-mapped: the emulateme RzIL test ran from a mid-instruction address
whose decode happened to lift, so it pinned values produced by garbage.
Scale those as well and drive the test the way its C55x sibling does,
decrypting seckrit with the real key.

With the sections fully mapped, analysis now finds every routine the
c54x fixtures declare, so the function counts change.
2026-08-17 01:53:33 +08:00

425 lines
6.4 KiB
Text

NAME=c54x analysis: register profile (PC alias resolves)
FILE==
CMDS=<<EOF
e asm.arch=tms320
e analysis.cpu=c54x
arp~^=PC
EOF
EXPECT=<<EOF
=PC pc
EOF
RUN
NAME=c54x analysis: opcode classification (batched)
FILE=malloc://64
CMDS=<<EOF
e asm.arch=tms320
e analysis.cpu=c54x
wx 95f4 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^size
wx 73f00001 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
wx 73f20001 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
wx 74f00001 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
ao 1 @ 0~^fail
ao 1 @ 0~^stackptr
wx 45f82001 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
ao 1 @ 0~^fail
wx 45f92001 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
ao 1 @ 0~^fail
ao 1 @ 0~^stackptr
wx 816c2001 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
ao 1 @ 0~^fail
wx e2f4 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^fail
wx e3f4 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^fail
ao 1 @ 0~^stackptr
wx 00fc @ 0
ao 1 @ 0~^type
ao 1 @ 0~^stackptr
wx 00fe @ 0
ao 1 @ 0~^type
ao 1 @ 0~^stackptr
wx 45fc @ 0
ao 1 @ 0~^type
ao 1 @ 0~^fail
ao 1 @ 0~^stackptr
wx 45fd @ 0
ao 1 @ 0~^type
wx ebf4 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^stackptr
wx e0f7 @ 0
ao 1 @ 0~^type
wx c5f7 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^val
wx c5f4 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^val
wx e1f4 @ 0
ao 1 @ 0~^type
wx 0fec @ 0
ao 1 @ 0~^type
wx 72f00001 @ 0
ao 1 @ 0~^type
wx 8100 @ 0
ao 1 @ 0~^type
wx 8108 @ 0
ao 1 @ 0~^type
wx 8120 @ 0
ao 1 @ 0~^type
wx 8118 @ 0
ao 1 @ 0~^type
wx 811a @ 0
ao 1 @ 0~^type
wx 811c @ 0
ao 1 @ 0~^type
wx 81600500 @ 0
ao 1 @ 0~^type
wx 84f4 @ 0
ao 1 @ 0~^type
wx 93f4 @ 0
ao 1 @ 0~^type
wx 7ff4 @ 0
ao 1 @ 0~^type
wx e1f0 @ 0
ao 1 @ 0~^type
wx 91f4 @ 0
ao 1 @ 0~^type
wx 90f4 @ 0
ao 1 @ 0~^type
wx 85f4 @ 0
ao 1 @ 0~^type
wx 9ff4 @ 0
ao 1 @ 0~^type
wx b8f7 @ 0
ao 1 @ 0~^type
wx b9f6 @ 0
ao 1 @ 0~^type
wx 8110 @ 0
ao 1 @ 0~^type
wx 1148 @ 0
ao 1 @ 0~^type
wx 8180 @ 0
ao 1 @ 0~^type
wx 11770500 @ 0
ao 1 @ 0~^type
wx 114a @ 0
ao 1 @ 0~^type
ao 1 @ 0~^stackptr
wx 118a @ 0
ao 1 @ 0~^type
ao 1 @ 0~^stackptr
wx 814b @ 0
ao 1 @ 0~^type
ao 1 @ 0~^stackptr
wx 818b @ 0
ao 1 @ 0~^type
ao 1 @ 0~^stackptr
wx 059e @ 0
ao 1 @ 0~^type
wx 81740500 @ 0
ao 1 @ 0~^type
EOF
EXPECT=<<EOF
type: nop
size: 2
type: jmp
jump: 0x00000200
type: jmp
jump: 0x00000200
type: call
jump: 0x00000200
fail: 0x00000004
stackptr: 2
type: cjmp
jump: 0x00000240
fail: 0x00000004
type: ccall
jump: 0x00000240
fail: 0x00000004
stackptr: 2
type: cjmp
jump: 0x00000240
fail: 0x00000004
type: ujmp
fail: 0x00000002
type: ucall
fail: 0x00000002
stackptr: 2
type: ret
stackptr: -2
type: ret
stackptr: -2
type: cret
fail: 0x00000002
stackptr: -2
type: cmov
type: ret
stackptr: -2
type: swi
type: swi
val: 0x00000005
type: swi
val: 0x00000005
type: sync
type: rep
type: rep
type: add
type: sub
type: mul
type: and
type: or
type: xor
type: cmp
type: sub
type: not
type: sar
type: shl
type: rol
type: ror
type: mov
type: mov
type: or
type: and
type: load
type: load
type: store
type: store
type: push
stackptr: 2
type: pop
stackptr: -2
type: push
stackptr: 1
type: pop
stackptr: -1
type: store
type: load
EOF
RUN
NAME=c54x analysis: RzAnalysisOp operand fields (indirect branch/call)
FILE==
CMDS=<<EOF
e asm.arch=tms320
e analysis.cpu=c54x
# BACC a -- branch to address in accumulator; ireg=a, direction=exec
wx e2f4 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^ireg
ao 1 @ 0~^direction
# CALA a -- call address in accumulator; ireg=a, direction=exec, stackptr=2
wx e3f4 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^ireg
ao 1 @ 0~^direction
ao 1 @ 0~^stackop
ao 1 @ 0~^stackptr
# CALL 0x100 -- direct call; jump target + return-slot stack push
wx 74f00001 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
ao 1 @ 0~^direction
EOF
EXPECT=<<EOF
type: ujmp
ireg: a
direction: exec
type: ucall
ireg: a
direction: exec
stackop: inc
stackptr: 2
type: call
jump: 0x00000200
direction: exec
EOF
RUN
NAME=c54x analysis: RzAnalysisOp operand fields (memory load/store)
FILE==
CMDS=<<EOF
e asm.arch=tms320
e analysis.cpu=c54x
# LD *ar1, a -- indirect load; reg=a (dst), ireg=ar1 (pointer), read, refptr=2
wx 8110 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^reg
ao 1 @ 0~^ireg
ao 1 @ 0~^direction
ao 1 @ 0~^refptr
# STL a, *ar1 -- indirect store; reg=a (src), ireg=ar1, write
wx 8180 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^reg
ao 1 @ 0~^ireg
ao 1 @ 0~^direction
# LD @0x5, a -- direct (DP/SP-relative) load; reg=a, disp=0x5, read (no base reg)
wx 0510 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^reg
ao 1 @ 0~^disp
ao 1 @ 0~^direction
EOF
EXPECT=<<EOF
type: load
reg: a
ireg: ar1
direction: read
refptr: 2
type: store
reg: a
ireg: ar1
direction: write
type: load
reg: a
disp: 0x00000005
direction: read
EOF
RUN
NAME=c54x analysis: data immediate on op->val (and branch target does not leak)
FILE==
CMDS=<<EOF
e asm.arch=tms320
e analysis.cpu=c54x
# LD #0x1234, a -- the data immediate is recorded on op->val
wx 20f03412 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^val
# ADD #0x1234, b -- arithmetic immediate
wx 00f33412 @ 0
ao 1 @ 0~^val
# RPT #0xf -- repeat-count immediate
wx 0fec @ 0
ao 1 @ 0~^val
# FB 0x2010 -- far branch: the target belongs in jump and must NOT leak into val
wx 80f81020 @ 0
ao 1 @ 0~^type
ao 1 @ 0~^jump
ao 1 @ 0~^val
EOF
EXPECT=<<EOF
type: load
val: 0x00001234
val: 0x00001234
val: 0x0000000f
type: jmp
jump: 0x00004020
EOF
RUN
NAME=c54x analysis: named instruction id (op->id = C54X_INS_*)
CMDS=<<EOF
e asm.arch=tms320
e analysis.cpu=c54x
# The disassembler tags each instruction with a named C54X_INS_* id, which the
# analyzer surfaces on op->id. These are positions in the C54X_INS_* enum:
# NOP=1, B=2, CALL=4, RET=6, RESET=14, TRAP=15, INTR=16, IDLE=17, LD=23,
# PSHM=26, POPM=27, AND=35.
wx 95f4 @ 0
ao 1 @ 0~^id
wx 73f00001 @ 0
ao 1 @ 0~^id
wx 74f00001 @ 0
ao 1 @ 0~^id
wx 00fc @ 0
ao 1 @ 0~^id
wx e0f7 @ 0
ao 1 @ 0~^id
wx c5f4 @ 0
ao 1 @ 0~^id
wx c5f7 @ 0
ao 1 @ 0~^id
wx e1f4 @ 0
ao 1 @ 0~^id
wx 8110 @ 0
ao 1 @ 0~^id
wx 114a @ 0
ao 1 @ 0~^id
wx 118a @ 0
ao 1 @ 0~^id
wx 8118 @ 0
ao 1 @ 0~^id
EOF
EXPECT=<<EOF
id: 1
id: 2
id: 4
id: 6
id: 14
id: 15
id: 16
id: 17
id: 23
id: 26
id: 27
id: 35
EOF
RUN
NAME=c54x analysis: emulateme c54x dbg.coff -- arch/cpu + function discovery
FILE=bins/tms320/emulateme_nostd.ccsv5.c54x.ticoff2.dbg.coff
ARGS=-A
CMDS=<<EOF
iI~^arch
iI~^cpu
iI~^bintype
iI~^endian
afl~?
afl~sym._main$~?
EOF
EXPECT=<<EOF
arch tms320
cpu c54x
bintype coff
endian LE
13
1
EOF
RUN
NAME=c54x analysis: coff1 03_branches_calls.o -- control-flow functions discovered
FILE=bins/tms320/coff1/03_branches_calls.o
ARGS=-A
CMDS=<<EOF
iI~^arch
iI~^cpu
afl~?
EOF
EXPECT=<<EOF
arch tms320
cpu c54x
9
EOF
RUN
NAME=c54x analysis: coff1 08_far_mode_c548.o -- far-addressing code analyzed
FILE=bins/tms320/coff1/08_far_mode_c548.o
ARGS=-A
CMDS=<<EOF
iI~^cpu
afl~?
EOF
EXPECT=<<EOF
cpu c54x
5
EOF
RUN