ARM/THUMB instructions that change execution path?

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.

Parents
  • If you're lucky, you can place instructions that are used often in the beginning of the table

    You read my mind.

    But ARM's instruction set is not too complicated either.

    Assembly is not, but the encoding is.

    cccc0000000Sdddd(0)(0)(0)(0)mmmm1001nnnn  MUL{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.114
    cccc0000000Snnnnddddssss0TT1mmmm  AND{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.15
    cccc0000000SnnnnddddxxxxxTT0mmmm  AND{S}<c> <Rd>,<Rn>,<Rm>{,<sift>} A1A8.8.14
    cccc0000001Sddddaaaammmm1001nnnn  MLA{S}<c> <Rd>,<Rn>,<Rm>,<Ra> A1A8.8.100
    cccc0000001Snnnnddddssss0TT1mmmm  EOR{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.48
    cccc0000001SnnnnddddxxxxxTT0mmmm  EOR{S}<c> <Rd>,<Rn>,<Rm>{,<sift>} A1A8.8.47
    cccc00000100hhhhllllmmmm1001nnnn  UMAAL<c> <RdLo>,<RdHi>,<Rn>,<Rm> A1A8.8.255
    cccc0000010S1101ddddxxxxxTT0mmmm  SUB{S}<c> <Rd>,SP,<Rm>{,<sift>} A1A8.8.226
    cccc0000010Snnnnddddssss0TT1mmmm  SUB{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.224

    and:

    cccc0001100Snnnnddddssss0TT1mmmm  ORR{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.124
    cccc0001100SnnnnddddxxxxxTT0mmmm  ORR{S}<c> <Rd>,<Rn>,<Rm>{,<sift>} A1A8.8.123
    cccc00011010nnnndddd(1)(1)(1)(1)1001tttt  STREXD<c> <Rd>,<Rt>,<Rt2>,[<Rn>] A1A8.8.214
    cccc00011011nnnntttt(1)(1)(1)(1)1001(1)(1)(1)(1)  LDREXD<c> <Rt>,<Rt2>,[<Rn>] A1A8.8.77
    cccc0001101S(0)(0)(0)(0)dddd00000000mmmm  MOV{S}<c> <Rd>,<Rm> A1A8.8.104
    cccc0001101S(0)(0)(0)(0)dddd00000110mmmm  RRX{S}<c> <Rd>,<Rm> A1A8.8.151
    cccc0001101S(0)(0)(0)(0)ddddmmmm0001nnnn  LSL{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.95
    cccc0001101S(0)(0)(0)(0)ddddmmmm0011nnnn  LSR{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.97
    cccc0001101S(0)(0)(0)(0)ddddmmmm0101nnnn  ASR{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.17

    Oh, and for small assembly routines I've been using inline asm, like

    void rpi2_trap_handler()

    {

        // IRQs need to be enabled for serial I/O

        asm volatile (

                "push {r0}\n\t"

                "mrs r0, cpsr\n\t"

                "bic r0, #128 @ enable irqs\n\t"

                "msr cpsr, r0\n\t"

                "pop {r0}\n\t"

        );

        gdb_trap_handler();

    }

    :

Reply
  • If you're lucky, you can place instructions that are used often in the beginning of the table

    You read my mind.

    But ARM's instruction set is not too complicated either.

    Assembly is not, but the encoding is.

    cccc0000000Sdddd(0)(0)(0)(0)mmmm1001nnnn  MUL{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.114
    cccc0000000Snnnnddddssss0TT1mmmm  AND{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.15
    cccc0000000SnnnnddddxxxxxTT0mmmm  AND{S}<c> <Rd>,<Rn>,<Rm>{,<sift>} A1A8.8.14
    cccc0000001Sddddaaaammmm1001nnnn  MLA{S}<c> <Rd>,<Rn>,<Rm>,<Ra> A1A8.8.100
    cccc0000001Snnnnddddssss0TT1mmmm  EOR{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.48
    cccc0000001SnnnnddddxxxxxTT0mmmm  EOR{S}<c> <Rd>,<Rn>,<Rm>{,<sift>} A1A8.8.47
    cccc00000100hhhhllllmmmm1001nnnn  UMAAL<c> <RdLo>,<RdHi>,<Rn>,<Rm> A1A8.8.255
    cccc0000010S1101ddddxxxxxTT0mmmm  SUB{S}<c> <Rd>,SP,<Rm>{,<sift>} A1A8.8.226
    cccc0000010Snnnnddddssss0TT1mmmm  SUB{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.224

    and:

    cccc0001100Snnnnddddssss0TT1mmmm  ORR{S}<c> <Rd>,<Rn>,<Rm>,<type>,<Rs> A1A8.8.124
    cccc0001100SnnnnddddxxxxxTT0mmmm  ORR{S}<c> <Rd>,<Rn>,<Rm>{,<sift>} A1A8.8.123
    cccc00011010nnnndddd(1)(1)(1)(1)1001tttt  STREXD<c> <Rd>,<Rt>,<Rt2>,[<Rn>] A1A8.8.214
    cccc00011011nnnntttt(1)(1)(1)(1)1001(1)(1)(1)(1)  LDREXD<c> <Rt>,<Rt2>,[<Rn>] A1A8.8.77
    cccc0001101S(0)(0)(0)(0)dddd00000000mmmm  MOV{S}<c> <Rd>,<Rm> A1A8.8.104
    cccc0001101S(0)(0)(0)(0)dddd00000110mmmm  RRX{S}<c> <Rd>,<Rm> A1A8.8.151
    cccc0001101S(0)(0)(0)(0)ddddmmmm0001nnnn  LSL{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.95
    cccc0001101S(0)(0)(0)(0)ddddmmmm0011nnnn  LSR{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.97
    cccc0001101S(0)(0)(0)(0)ddddmmmm0101nnnn  ASR{S}<c> <Rd>,<Rn>,<Rm> A1A8.8.17

    Oh, and for small assembly routines I've been using inline asm, like

    void rpi2_trap_handler()

    {

        // IRQs need to be enabled for serial I/O

        asm volatile (

                "push {r0}\n\t"

                "mrs r0, cpsr\n\t"

                "bic r0, #128 @ enable irqs\n\t"

                "msr cpsr, r0\n\t"

                "pop {r0}\n\t"

        );

        gdb_trap_handler();

    }

    :

Children
No data