Has anybody come across a list of ARM & THUMB instructions that cause deviation from the linear instruction stream?
I've been trying to figure out gdb-stub single stepping using software interrupts, and in single stepping you need to find
the next instruction(s) where the next breakpoint instruction needs to be set.
There are three cases:
1) current instruction doesn't change the execution path. Next instruction is the next word.
2) current instruction is a jump. The operand defines the next instruction address
3) current instruction is conditional branch. One possible next instruction is the next word, the other possible
instruction address is defined by the operand. (That includes conditional add with PC as the target, and the like).
To implement single stepping, I need to tell those cases apart and figure out how to find out the possible branching address.
I could go through manuals of numerous processors instruction by instruction and maybe I'd be done within the next couple of years,
or I could find a list of instructions to check, or a paper that explains how to "decode" the instructions in a useful way.
Also, there doesn't seem to be lots of sources of ARM gdb servers or stubs around that use software breakpoints.
Just to let possibly interested people to know:
I generated a list of encodings (both ARM and Thumb) for Cortex-A7.
The lists may still contain errors, like missing decodings or the like - they were awk-script generated from ARMv7-A/R ARM.
Since I didn't find that kind of lists in the net, I decided to make them.
The lists can be downloaded from https://github.com/turboscrew/rpi_stub (the files ARM_instructions.txt and Thumb_instructions.txt ).
They are text files to allow easier manipulation.
Good work, sir!
As far as I know, you're a pioneer in this area (eg. writing a bootloader debugger).
I was doing nicely until I had to start decoding that huge set of instructions.
Pretty laborous and slow.
Like the media instructions: I found that unsigned and signed parallel addition and subtractions instructions can be
handled similarly, like:
All patterns are similar except bit 22=1: unsigned, bits 21,20: 00=undef, 01=basic, 10=Q and 11=H.
That seems to be the same with all unsigned and signed parallel addition and subtractions instructions.
It's easier to see the patterns when you can just search and copy the instructions to another file (like the above)
and compare the bits of all the interesting instructions at once, and with patterns you can often unify the manipulation.
It would be nice to get the tables into excel or ods for even more flexible manipulation (moving columns around and sorting lines by some columns). Maybe one day.
[EDIT]
The web page somehow makes the lines into a table and wraps some cells.
It looks OK when writing/editing, but after posting it looks a bit weird.
[/EDIT]
I once wrote a debugger for 68xxx (it was back in 1988 I think).
There I had a mask and data for each kind of instruction.
Eg.
if((instr & mask) == data){ found; }
Here you will need to sort the table, so that masking will work correctly; otherwise, if your first entry's mask is 0x0000, then you'll always get the same result.
Of course it is a good idea ending the table with mask 0x0000 and data 0x0000; this way you'll find the instruction fairly quickly.
You could make a similar table and add a 'type' entry. For instance type could be 'add' and then a positive/negative, in order to merge add and subtract into one handler (that might simplify and shorten the code).
Having handler types and a mode field would perhaps also make it possible to simplify the code.
Opcodes usually come in 'families'. It may be a good idea to find out which instruction family the opcode belongs to first, then handle the remaining part of the instruction decoding after that, however, it may be quicker to just use the mask and data system, depending on the number of instructions.
Table approach may not be very good with ARM, because the instruction defining bits are not in constant places. Not even mostly, except the 3 bits after condition code, and sometimes a special register value makes another instruction.
Also, in this program, I don't care about the instruction as such, but just the 'next address' after the instruction.
Sometimes it's easier to execute than to 'simulate' the code:
unsigned int check_msr_reg(uint32_t instr)
{
unsigned int new_pc = rpi2_reg_context.reg.r15;
// if user mode, then can't even guess
tmp1 = (uint32_t) rpi2_reg_context.reg.cpsr;
if ((tmp1 & 0x1f) == 0) // user mode
// UNPREDICTABLE - whether banked or not
// the bits 15 - 0 are UNKNOWN
new_pc = INSTR_ADDR_UNDEF;
}
else
// privileged mode - both reg and banked reg
tmp2 = (instr & 0xffff0fff) | (1 << 12); // edit Rd = r1
iptr = (uint32_t *) mrs_regb;
*iptr = tmp2;
asm(
"push {r0, r1}\n\t"
"mrs r1, cpsr @ save cpsr\n\t"
"push {r1}\n\t"
"ldr r0, =tmp1 @ set cpsr\n\t"
"msr cpsr, r0 @ note: user mode is already excluded\n\t"
"mrs_regb: .word 0 @ execute instr with our registers\n\t"
"ldr r0, =tmp2\n\t"
"str r1, [r0] @ store result to tmp2\n\t"
"pop {r1} @ restore cpsr\n\t"
"msr cpsr, r1\n\t"
"pop {r0, r1}\n\t"
);
new_pc = (unsigned int) tmp2;
return new_pc;
In this project this far I've learned about ARM (never really used before), awk (never used it before) and inline assembly (accessing C variables). For some unknown reason, I haven't been keen to use the inline assembly extensions though.
Ah, yes. things are coming back to me.
My debugger usually ran on a 68000, but my MegaSTE had a 68010, so I wrote an instruction emulator. It could emulate 68010, 20, 30, 40 and CPU32 instructions (the latter was never tested, though).
-Sometimes it's also a lot faster to simulate instruction execution.
View all questions in Embedded forum