Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add support for ARM exception handler ABI #328

Merged
merged 22 commits into from
Aug 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added elftools/ehabi/__init__.py
Empty file.
1 change: 1 addition & 0 deletions elftools/ehabi/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
EHABI_INDEX_ENTRY_SIZE = 8
284 changes: 284 additions & 0 deletions elftools/ehabi/decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
# -------------------------------------------------------------------------------
# elftools: ehabi/decoder.py
#
# Decode ARM exception handler bytecode.
#
# LeadroyaL (leadroyal@qq.com)
# This code is in the public domain
# -------------------------------------------------------------------------------
from collections import namedtuple


class EHABIBytecodeDecoder(object):
""" Decoder of a sequence of ARM exception handler abi bytecode.

Reference:
https://github.com/llvm/llvm-project/blob/master/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
https://developer.arm.com/documentation/ihi0038/b/

Accessible attributes:

mnemonic_array:
MnemonicItem array.

Parameters:

bytecode_array:
Integer array, raw data of bytecode.

"""

def __init__(self, bytecode_array):
self._bytecode_array = bytecode_array
self._index = None
self.mnemonic_array = None
self._decode()

def _decode(self):
""" Decode bytecode array, put result into mnemonic_array.
"""
self._index = 0
self.mnemonic_array = []
while self._index < len(self._bytecode_array):
for mask, value, handler in self.ring:
if (self._bytecode_array[self._index] & mask) == value:
start_idx = self._index
mnemonic = handler(self)
end_idx = self._index
self.mnemonic_array.append(
MnemonicItem(self._bytecode_array[start_idx: end_idx], mnemonic))
break

def _decode_00xxxxxx(self):
# SW.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode,
# ((Opcode & 0x3f) << 2) + 4);
opcode = self._bytecode_array[self._index]
self._index += 1
return 'vsp = vsp + %u' % (((opcode & 0x3f) << 2) + 4)

def _decode_01xxxxxx(self):
# SW.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode,
# ((Opcode & 0x3f) << 2) + 4);
opcode = self._bytecode_array[self._index]
self._index += 1
return 'vsp = vsp - %u' % (((opcode & 0x3f) << 2) + 4)

gpr_register_names = ("r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc")

def _calculate_range(self, start, count):
return ((1 << (count + 1)) - 1) << start

def _printGPR(self, gpr_mask):
hits = [self.gpr_register_names[i] for i in range(32) if gpr_mask & (1 << i) != 0]
return '{%s}' % ', '.join(hits)

def _print_registers(self, vfp_mask, prefix):
hits = [prefix + str(i) for i in range(32) if vfp_mask & (1 << i) != 0]
return '{%s}' % ', '.join(hits)

def _decode_1000iiii_iiiiiiii(self):
op0 = self._bytecode_array[self._index]
self._index += 1
op1 = self._bytecode_array[self._index]
self._index += 1
# uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12);
# SW.startLine()
# << format("0x%02X 0x%02X ; %s",
# Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind");
# if (GPRMask)
# PrintGPR(GPRMask);
gpr_mask = (op1 << 4) | ((op0 & 0x0f) << 12)
if gpr_mask == 0:
return 'refuse to unwind'
else:
return 'pop %s' % self._printGPR(gpr_mask)

def _decode_10011101(self):
self._index += 1
return 'reserved (ARM MOVrr)'

def _decode_10011111(self):
self._index += 1
return 'reserved (WiMMX MOVrr)'

def _decode_1001nnnn(self):
# SW.startLine() << format("0x%02X ; vsp = r%u\n", Opcode, (Opcode & 0x0f));
opcode = self._bytecode_array[self._index]
self._index += 1
return 'vsp = r%u' % (opcode & 0x0f)

def _decode_10100nnn(self):
# SW.startLine() << format("0x%02X ; pop ", Opcode);
# PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4));
opcode = self._bytecode_array[self._index]
self._index += 1
return 'pop %s' % self._printGPR(self._calculate_range(4, opcode & 0x07))

def _decode_10101nnn(self):
# SW.startLine() << format("0x%02X ; pop ", Opcode);
# PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14));
opcode = self._bytecode_array[self._index]
self._index += 1
return 'pop %s' % self._printGPR(self._calculate_range(4, opcode & 0x07) | (1 << 14))

def _decode_10110000(self):
# SW.startLine() << format("0x%02X ; finish\n", Opcode);
self._index += 1
return 'finish'

def _decode_10110001_0000iiii(self):
# SW.startLine()
# << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
# ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
# if (((Opcode1 & 0xf0) == 0x00) && Opcode1)
# PrintGPR((Opcode1 & 0x0f));
self._index += 1 # skip constant byte
op1 = self._bytecode_array[self._index]
self._index += 1
if (op1 & 0xf0) != 0 or op1 == 0x00:
return 'spare'
else:
return 'pop %s' % self._printGPR((op1 & 0x0f))

def _decode_10110010_uleb128(self):
# SmallVector<uint8_t, 4> ULEB;
# do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80);
# uint64_t Value = 0;
# for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)
# Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI));
# OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2));
self._index += 1 # skip constant byte
uleb_buffer = [self._bytecode_array[self._index]]
self._index += 1
while self._bytecode_array[self._index] & 0x80 == 0:
uleb_buffer.append(self._bytecode_array[self._index])
self._index += 1
value = 0
for b in reversed(uleb_buffer):
value = (value << 7) + (b & 0x7F)
return 'vsp = vsp + %u' % (0x204 + (value << 2))

def _decode_10110011_sssscccc(self):
# these two decoders are equal
return self._decode_11001001_sssscccc()

def _decode_101101nn(self):
return self._spare()

def _decode_10111nnn(self):
# SW.startLine() << format("0x%02X ; pop ", Opcode);
# PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");
opcode = self._bytecode_array[self._index]
self._index += 1
return 'pop %s' % self._print_registers(self._calculate_range(8, opcode & 0x07), "d")

def _decode_11000110_sssscccc(self):
# SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
# uint8_t Start = ((Opcode1 & 0xf0) >> 4);
# uint8_t Count = ((Opcode1 & 0x0f) >> 0);
# PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR");
self._index += 1 # skip constant byte
op1 = self._bytecode_array[self._index]
self._index += 1
start = ((op1 & 0xf0) >> 4)
count = ((op1 & 0x0f) >> 0)
return 'pop %s' % self._print_registers(self._calculate_range(start, count), "wR")

def _decode_11000111_0000iiii(self):
# SW.startLine()
# << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
# ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
# if ((Opcode1 & 0xf0) == 0x00 && Opcode1)
# PrintRegisters(Opcode1 & 0x0f, "wCGR");
self._index += 1 # skip constant byte
op1 = self._bytecode_array[self._index]
self._index += 1
if (op1 & 0xf0) != 0 or op1 == 0x00:
return 'spare'
else:
return 'pop %s' % self._print_registers(op1 & 0x0f, "wCGR")

def _decode_11001000_sssscccc(self):
# SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
# uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4);
# uint8_t Count = ((Opcode1 & 0x0f) >> 0);
# PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
self._index += 1 # skip constant byte
op1 = self._bytecode_array[self._index]
self._index += 1
start = 16 + ((op1 & 0xf0) >> 4)
count = ((op1 & 0x0f) >> 0)
return 'pop %s' % self._print_registers(self._calculate_range(start, count), "d")

def _decode_11001001_sssscccc(self):
# SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
# uint8_t Start = ((Opcode1 & 0xf0) >> 4);
# uint8_t Count = ((Opcode1 & 0x0f) >> 0);
# PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
self._index += 1 # skip constant byte
op1 = self._bytecode_array[self._index]
self._index += 1
start = ((op1 & 0xf0) >> 4)
count = ((op1 & 0x0f) >> 0)
return 'pop %s' % self._print_registers(self._calculate_range(start, count), "d")

def _decode_11001yyy(self):
return self._spare()

def _decode_11000nnn(self):
# SW.startLine() << format("0x%02X ; pop ", Opcode);
# PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR");
opcode = self._bytecode_array[self._index]
self._index += 1
return 'pop %s' % self._print_registers(self._calculate_range(10, opcode & 0x07), "wR")

def _decode_11010nnn(self):
# these two decoders are equal
return self._decode_10111nnn()

def _decode_11xxxyyy(self):
return self._spare()

def _spare(self):
self._index += 1
return 'spare'

_DECODE_RECIPE_TYPE = namedtuple('_DECODE_RECIPE_TYPE', 'mask value handler')

ring = (
LeadroyaL marked this conversation as resolved.
Show resolved Hide resolved
_DECODE_RECIPE_TYPE(mask=0xc0, value=0x00, handler=_decode_00xxxxxx),
_DECODE_RECIPE_TYPE(mask=0xc0, value=0x40, handler=_decode_01xxxxxx),
_DECODE_RECIPE_TYPE(mask=0xf0, value=0x80, handler=_decode_1000iiii_iiiiiiii),
_DECODE_RECIPE_TYPE(mask=0xff, value=0x9d, handler=_decode_10011101),
_DECODE_RECIPE_TYPE(mask=0xff, value=0x9f, handler=_decode_10011111),
_DECODE_RECIPE_TYPE(mask=0xf0, value=0x90, handler=_decode_1001nnnn),
_DECODE_RECIPE_TYPE(mask=0xf8, value=0xa0, handler=_decode_10100nnn),
_DECODE_RECIPE_TYPE(mask=0xf8, value=0xa8, handler=_decode_10101nnn),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xb0, handler=_decode_10110000),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xb1, handler=_decode_10110001_0000iiii),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xb2, handler=_decode_10110010_uleb128),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xb3, handler=_decode_10110011_sssscccc),
_DECODE_RECIPE_TYPE(mask=0xfc, value=0xb4, handler=_decode_101101nn),
_DECODE_RECIPE_TYPE(mask=0xf8, value=0xb8, handler=_decode_10111nnn),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xc6, handler=_decode_11000110_sssscccc),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xc7, handler=_decode_11000111_0000iiii),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xc8, handler=_decode_11001000_sssscccc),
_DECODE_RECIPE_TYPE(mask=0xff, value=0xc9, handler=_decode_11001001_sssscccc),
_DECODE_RECIPE_TYPE(mask=0xc8, value=0xc8, handler=_decode_11001yyy),
_DECODE_RECIPE_TYPE(mask=0xf8, value=0xc0, handler=_decode_11000nnn),
_DECODE_RECIPE_TYPE(mask=0xf8, value=0xd0, handler=_decode_11010nnn),
_DECODE_RECIPE_TYPE(mask=0xc0, value=0xc0, handler=_decode_11xxxyyy),
)


class MnemonicItem(object):
""" Single mnemonic item.
"""

def __init__(self, bytecode, mnemonic):
self.bytecode = bytecode
self.mnemonic = mnemonic

def __repr__(self):
return '%s ; %s' % (' '.join(['0x%02x' % x for x in self.bytecode]), self.mnemonic)
Loading