Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically cause Undefined Instruction exception

I want to cause an ARM Cortex-M3 Undefined Instruction exception for the test of my test fixture. The IAR compiler supports this with inline assembly like this:

asm("udf.w #0");

Unfortunately the GNU CC inline assembler does not know this opcode for the NXP LPC177x8x. It writes the diagnostic:

ccw3kZ46.s:404: Error: bad instruction `udf.w #0'

How can I create a function that causes a Undefined Instruction exception?

like image 956
harper Avatar asked Apr 18 '13 11:04

harper


4 Answers

Some extra info...

One of GCC's builtins is

void __builtin_trap (void)

This function causes the program to exit abnormally. GCC implements this function by using a target-dependent mechanism (such as intentionally executing an illegal instruction) or by calling abort. The mechanism used may vary from release to release so you should not rely on any particular implementation.

Its implementation for ARMv7 is:

(define_insn "trap"
  [(trap_if (const_int 1) (const_int 0))]
  ""
  "*
  if (TARGET_ARM)
    return \".inst\\t0xe7f000f0\";
  else
    return \".inst\\t0xdeff\";
  "
  [(set (attr "length")
    (if_then_else (eq_attr "is_thumb" "yes")
              (const_int 2)
              (const_int 4)))
   (set_attr "type" "trap")
   (set_attr "conds" "unconditional")]
)

So for ARM mode gcc will generate 0x7f000f0 (f0 00 f0 07)and for other modes 0xdeff (ff de) (comes handy when disassembling / debugging).

Also note that:

these encodings match the UDF instruction that is defined in the most
recent edition of the ARM architecture reference manual.

Thumb: 0xde00 | imm8  (we chose 0xff for the imm8)
ARM: 0xe7f000f0 | (imm12 << 8) | imm4  (we chose to use 0 for both imms)

For LLVM __builtin_trap values generated are 0xe7ffdefe and 0xdefe:

case ARM::TRAP: {
  // Non-Darwin binutils don't yet support the "trap" mnemonic.
  // FIXME: Remove this special case when they do.
  if (!Subtarget->isTargetDarwin()) {
    //.long 0xe7ffdefe @ trap
    uint32_t Val = 0xe7ffdefeUL;
    OutStreamer.AddComment("trap");
    OutStreamer.EmitIntValue(Val, 4);
    return;
  }
  break;
}
case ARM::tTRAP: {
  // Non-Darwin binutils don't yet support the "trap" mnemonic.
  // FIXME: Remove this special case when they do.
  if (!Subtarget->isTargetDarwin()) {
    //.short 57086 @ trap
    uint16_t Val = 0xdefe;
    OutStreamer.AddComment("trap");
    OutStreamer.EmitIntValue(Val, 2);
    return;
  }
  break;
}
like image 88
auselen Avatar answered Nov 19 '22 04:11

auselen


There are different official undefined instructions in [1] (look for UDF; . below can be replaced with any hex digit):

  • 0xe7f...f. - ARM or A1 encoding (ARMv4T, ARMv5T, ARMv6, ARMv7, ARMv8)
  • 0xde.. - Thumb or T1 encoding (ARMv4T, ARMv5T, ARMv6, ARMv7, ARMv8)
  • 0xf7f.a... - Thumb2 or T2 encoding (ARMv6T2, ARMv7, ARMv8)
  • 0x0000.... - ARMv8-A permanently undefined

There are others, but these are probably as future-proof as it gets.

As for generating the code that triggers it, you can just use .short or .word, like this:

  • asm volatile (".short 0xde00\n"); /* thumb illegal instruction */
  • asm volatile (".word 0xe7f000f0\n"); /* arm illegal instruction */
  • asm volatile (".word 0xe7f0def0\n"); /* arm+thumb illegal instruction */

Note that the last one will decode to 0xdef0, 0xe7f0 in thumb context, and therefore also cause an undefined instruction exception.

[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.architecture.reference/index.html

[2] DDI0487D_b_armv8_arm.pdf

like image 38
domen Avatar answered Nov 19 '22 03:11

domen


Building on Masta79's answer:

There is a "permanently undefined" encoding listed in the ARMv7-M architecture reference manual - ARM DDI 0403D (documentation placeholder, registration required). The encoding is 0xf7fXaXXX (where 'X' is ignored). Of course instruction fetches are little-endian, so (without testing):

asm volatile (".word 0xf7f0a000\n");

should yield a guaranteed undefined instruction on any ARMv7-M or later processor.

like image 20
unixsmurf Avatar answered Nov 19 '22 04:11

unixsmurf


The thumb-16 version of the permanently undefined instruction is 0xDExx. So you can do this in your code to trigger the exception:

.inst 0xde00

Reference: ARMv7-M Architecture Reference Manual, section A5.2.6.

(Note that 0xF7Fx, 0xAxxx encoding is also permanently undefined, but is a 32-bit instruction.)

like image 38
JP Sugarbroad Avatar answered Nov 19 '22 03:11

JP Sugarbroad