ARMEHABIPrinter.h revision 36b56886974eae4f9c5ebc96befd3e7bfe5de338
136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//
236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//
336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//                     The LLVM Compiler Infrastructure
436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//
536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// This file is distributed under the University of Illinois Open Source
636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// License. See LICENSE.TXT for details.
736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//
836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//===----------------------------------------------------------------------===//
936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
1036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#ifndef LLVM_READOBJ_ARMEHABI_PRINTER_H
1136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define LLVM_READOBJ_ARMEHABI_PRINTER_H
1236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
1336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "Error.h"
1436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "StreamWriter.h"
1536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Object/ELF.h"
1636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Object/ELFTypes.h"
1736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Support/ARMEHABI.h"
1836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Support/Debug.h"
1936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Support/Endian.h"
2036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Support/Format.h"
2136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Support/type_traits.h"
2236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
2336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesnamespace {
2436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename type_, size_t N>
2536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinessize_t countof(const type_ (&)[N]) {
2636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  return N;
2736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
2836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
2936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
3036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesnamespace llvm {
3136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesnamespace ARM {
3236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesnamespace EHABI {
3336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
3436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesclass OpcodeDecoder {
3536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  StreamWriter &SW;
3636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  raw_ostream &OS;
3736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
3836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  struct RingEntry {
3936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    uint8_t Mask;
4036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    uint8_t Value;
4136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI);
4236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  };
4336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  static const RingEntry Ring[];
4436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
4536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI);
4636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI);
4736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, unsigned &OI);
4836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10011101(const uint8_t *Opcodes, unsigned &OI);
4936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10011111(const uint8_t *Opcodes, unsigned &OI);
5036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI);
5136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI);
5236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI);
5336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10110000(const uint8_t *Opcodes, unsigned &OI);
5436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10110001_0000iiii(const uint8_t *Opcodes, unsigned &OI);
5536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10110010_uleb128(const uint8_t *Opcodes, unsigned &OI);
5636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10110011_sssscccc(const uint8_t *Opcodes, unsigned &OI);
5736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_101101nn(const uint8_t *Opcodes, unsigned &OI);
5836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI);
5936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11000110_sssscccc(const uint8_t *Opcodes, unsigned &OI);
6036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11000111_0000iiii(const uint8_t *Opcodes, unsigned &OI);
6136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11001000_sssscccc(const uint8_t *Opcodes, unsigned &OI);
6236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11001001_sssscccc(const uint8_t *Opcodes, unsigned &OI);
6336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI);
6436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI);
6536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI);
6636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI);
6736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
6836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void PrintGPR(uint16_t GPRMask);
6936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void PrintRegisters(uint32_t Mask, StringRef Prefix);
7036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
7136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinespublic:
7236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OpcodeDecoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {}
7336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length);
7436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines};
7536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
7636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesconst OpcodeDecoder::RingEntry OpcodeDecoder::Ring[] = {
7736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx },
7836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx },
7936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii },
8036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0x9d, &OpcodeDecoder::Decode_10011101 },
8136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0x9f, &OpcodeDecoder::Decode_10011111 },
8236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn },
8336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn },
8436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn },
8536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xb0, &OpcodeDecoder::Decode_10110000 },
8636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii },
8736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128 },
8836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc },
8936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn },
9036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn },
9136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc },
9236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii },
9336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc },
9436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc },
9536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy },
9636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn },
9736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn },
9836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  { 0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy },
9936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines};
10036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
10136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI) {
10236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
10336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; vsp = vsp + %u\n", Opcode,
10436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                           ((Opcode & 0x3f) << 2) + 4);
10536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
10636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI) {
10736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
10836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; vsp = vsp - %u\n", Opcode,
10936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                           ((Opcode & 0x3f) << 2) + 4);
11036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
11136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes,
11236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             unsigned &OI) {
11336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode0 = Opcodes[OI++ ^ 3];
11436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode1 = Opcodes[OI++ ^ 3];
11536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
11636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12);
11736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine()
11836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    << format("0x%02X 0x%02X ; %s",
11936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines              Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind");
12036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (GPRMask)
12136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    PrintGPR(GPRMask);
12236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
12336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
12436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes, unsigned &OI) {
12536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
12636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; reserved (ARM MOVrr)\n", Opcode);
12736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
12836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes, unsigned &OI) {
12936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
13036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; reserved (WiMMX MOVrr)\n", Opcode);
13136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
13236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI) {
13336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
13436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; vsp = r%u\n", Opcode, (Opcode & 0x0f));
13536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
13636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI) {
13736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
13836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; pop ", Opcode);
13936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4));
14036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
14136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
14236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI) {
14336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
14436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; pop ", Opcode);
14536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14));
14636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
14736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
14836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, unsigned &OI) {
14936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
15036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; finish\n", Opcode);
15136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
15236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes,
15336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             unsigned &OI) {
15436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode0 = Opcodes[OI++ ^ 3];
15536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode1 = Opcodes[OI++ ^ 3];
15636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
15736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine()
15836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
15936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines              ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
16036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (((Opcode1 & 0xf0) == 0x00) && Opcode1)
16136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    PrintGPR((Opcode1 & 0x0f));
16236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
16336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
16436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes,
16536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                            unsigned &OI) {
16636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
16736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X ", Opcode);
16836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
16936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SmallVector<uint8_t, 4> ULEB;
17036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80);
17136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
17236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)
17336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    OS << format("0x%02X ", ULEB[BI]);
17436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
17536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint64_t Value = 0;
17636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)
17736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI));
17836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
17936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2));
18036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
18136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes,
18236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             unsigned &OI) {
18336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode0 = Opcodes[OI++ ^ 3];
18436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode1 = Opcodes[OI++ ^ 3];
18536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
18636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Start = ((Opcode1 & 0xf0) >> 4);
18736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Count = ((Opcode1 & 0x0f) >> 0);
18836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
18936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
19036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
19136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, unsigned &OI) {
19236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
19336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; spare\n", Opcode);
19436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
19536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI) {
19636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
19736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; pop ", Opcode);
19836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");
19936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
20036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
20136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes,
20236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             unsigned &OI) {
20336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode0 = Opcodes[OI++ ^ 3];
20436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode1 = Opcodes[OI++ ^ 3];
20536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
20636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Start = ((Opcode1 & 0xf0) >> 4);
20736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Count = ((Opcode1 & 0x0f) >> 0);
20836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR");
20936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
21036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
21136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes,
21236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             unsigned &OI) {
21336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode0 = Opcodes[OI++ ^ 3];
21436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode1 = Opcodes[OI++ ^ 3];
21536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine()
21636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
21736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines              ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
21836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if ((Opcode1 & 0xf0) == 0x00 && Opcode1)
21936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      PrintRegisters(Opcode1 & 0x0f, "wCGR");
22036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
22136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
22236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes,
22336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             unsigned &OI) {
22436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode0 = Opcodes[OI++ ^ 3];
22536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode1 = Opcodes[OI++ ^ 3];
22636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
22736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4);
22836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Count = ((Opcode1 & 0x0f) >> 0);
22936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
23036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
23136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
23236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes,
23336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             unsigned &OI) {
23436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode0 = Opcodes[OI++ ^ 3];
23536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode1 = Opcodes[OI++ ^ 3];
23636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
23736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Start = ((Opcode1 & 0xf0) >> 4);
23836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Count = ((Opcode1 & 0x0f) >> 0);
23936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
24036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
24136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
24236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI) {
24336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
24436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; spare\n", Opcode);
24536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
24636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI) {
24736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
24836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; pop ", Opcode);
24936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR");
25036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
25136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
25236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI) {
25336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
25436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; pop ", Opcode);
25536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");
25636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '\n';
25736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
25836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI) {
25936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  uint8_t Opcode = Opcodes[OI++ ^ 3];
26036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  SW.startLine() << format("0x%02X      ; spare\n", Opcode);
26136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
26236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
26336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::PrintGPR(uint16_t GPRMask) {
26436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  static const char *GPRRegisterNames[16] = {
26536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
26636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    "fp", "ip", "sp", "lr", "pc"
26736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  };
26836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
26936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '{';
27036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  bool Comma = false;
27136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (unsigned RI = 0, RE = 17; RI < RE; ++RI) {
27236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (GPRMask & (1 << RI)) {
27336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (Comma)
27436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        OS << ", ";
27536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      OS << GPRRegisterNames[RI];
27636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      Comma = true;
27736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
27836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
27936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '}';
28036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
28136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
28236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) {
28336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '{';
28436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  bool Comma = false;
28536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (unsigned RI = 0, RE = 32; RI < RE; ++RI) {
28636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (VFPMask & (1 << RI)) {
28736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (Comma)
28836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        OS << ", ";
28936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      OS << Prefix << RI;
29036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      Comma = true;
29136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
29236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
29336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OS << '}';
29436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
29536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
29636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) {
29736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (unsigned OCI = Offset; OCI < Length + Offset; ) {
29836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    bool Decoded = false;
29936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    for (unsigned REI = 0, REE = countof(Ring); REI != REE && !Decoded; ++REI) {
30036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if ((Opcodes[OCI ^ 3] & Ring[REI].Mask) == Ring[REI].Value) {
30136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        (this->*Ring[REI].Routine)(Opcodes, OCI);
30236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        Decoded = true;
30336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        break;
30436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
30536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
30636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (!Decoded)
30736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.startLine() << format("0x%02X      ; reserved\n", Opcodes[OCI++ ^ 3]);
30836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
30936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
31036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
31136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
31236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesclass PrinterContext {
31336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  StreamWriter &SW;
31436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const object::ELFFile<ET> *ELF;
31536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
31636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  typedef typename object::ELFFile<ET>::Elf_Sym Elf_Sym;
31736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  typedef typename object::ELFFile<ET>::Elf_Shdr Elf_Shdr;
31836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
31936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  typedef typename object::ELFFile<ET>::Elf_Rel_Iter Elf_Rel_iterator;
32036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  typedef typename object::ELFFile<ET>::Elf_Sym_Iter Elf_Sym_iterator;
32136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  typedef typename object::ELFFile<ET>::Elf_Shdr_Iter Elf_Shdr_iterator;
32236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
32336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  static const size_t IndexTableEntrySize;
32436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
32536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  static uint64_t PREL31(uint32_t Address, uint32_t Place) {
32636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    uint64_t Location = Address & 0x7fffffff;
32736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (Location & 0x04000000)
32836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      Location |= (uint64_t) ~0x7fffffff;
32936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return Location + Place;
33036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
33136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
33236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const;
33336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex,
33436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                     off_t IndexTableOffset) const;
33536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
33636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const;
33736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void PrintExceptionTable(const Elf_Shdr *IT, const Elf_Shdr *EHT,
33836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                           uint64_t TableEntryOffset) const;
33936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const;
34036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
34136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinespublic:
34236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  PrinterContext(StreamWriter &Writer, const object::ELFFile<ET> *File)
34336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    : SW(Writer), ELF(File) {}
34436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
34536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  void PrintUnwindInformation() const;
34636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines};
34736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
34836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
34936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesconst size_t PrinterContext<ET>::IndexTableEntrySize = 8;
35036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
35136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
35236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen HinesErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(unsigned Section,
35336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                                         uint64_t Address) const {
35436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (Elf_Sym_iterator SI = ELF->begin_symbols(), SE = ELF->end_symbols();
35536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines       SI != SE; ++SI)
35636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (SI->st_shndx == Section && SI->st_value == Address &&
35736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        SI->getType() == ELF::STT_FUNC)
35836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return ELF->getSymbolName(SI);
35936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  return readobj_error::unknown_symbol;
36036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
36136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
36236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
36336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesconst typename object::ELFFile<ET>::Elf_Shdr *
36436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen HinesPrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex,
36536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                       off_t IndexTableOffset) const {
36636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// Iterate through the sections, searching for the relocation section
36736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// associated with the unwind index table section specified by
36836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// IndexSectionIndex.  Iterate the associated section searching for the
36936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// relocation associated with the index table entry specified by
37036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// IndexTableOffset.  The symbol is the section symbol for the exception
37136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// handling table.  Use this symbol to recover the actual exception handling
37236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// table.
37336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
37436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections();
37536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines       SI != SE; ++SI) {
37636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (SI->sh_type == ELF::SHT_REL && SI->sh_info == IndexSectionIndex) {
37736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      for (Elf_Rel_iterator RI = ELF->begin_rel(&*SI), RE = ELF->end_rel(&*SI);
37836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines           RI != RE; ++RI) {
37936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        if (RI->r_offset == static_cast<unsigned>(IndexTableOffset)) {
38036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines          typename object::ELFFile<ET>::Elf_Rela RelA;
38136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines          RelA.r_offset = RI->r_offset;
38236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines          RelA.r_info = RI->r_info;
38336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines          RelA.r_addend = 0;
38436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
38536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines          std::pair<const Elf_Shdr *, const Elf_Sym *> Symbol =
38636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines            ELF->getRelocationSymbol(&(*SI), &RelA);
38736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
38836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines          return ELF->getSection(Symbol.second);
38936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        }
39036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
39136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
39236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
39336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  return NULL;
39436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
39536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
39636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
39736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT,
39836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             const Elf_Shdr *EHT,
39936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                             uint64_t TableEntryOffset) const {
40036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(EHT);
40136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!Contents)
40236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return;
40336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
40436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// ARM EHABI Section 6.2 - The generic model
40536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///
40636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// An exception-handling table entry for the generic model is laid out as:
40736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///
40836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///  3 3
40936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///  1 0                            0
41036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// +-+------------------------------+
41136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// |0|  personality routine offset  |
41236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// +-+------------------------------+
41336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// |  personality routine data ...  |
41436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///
41536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///
41636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// ARM EHABI Section 6.3 - The ARM-defined compact model
41736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///
41836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// An exception-handling table entry for the compact model looks like:
41936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///
42036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///  3 3 2 2  2 2
42136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///  1 0 8 7  4 3                     0
42236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// +-+---+----+-----------------------+
42336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// |1| 0 | Ix | data for pers routine |
42436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// +-+---+----+-----------------------+
42536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// |  more personality routine data   |
42636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
42736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const support::ulittle32_t Word =
42836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    *reinterpret_cast<const support::ulittle32_t *>(Contents->data() + TableEntryOffset);
42936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
43036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (Word & 0x80000000) {
43136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    SW.printString("Model", StringRef("Compact"));
43236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
43336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    unsigned PersonalityIndex = (Word & 0x0f000000) >> 24;
43436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    SW.printNumber("PersonalityIndex", PersonalityIndex);
43536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
43636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    switch (PersonalityIndex) {
43736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    case AEABI_UNWIND_CPP_PR0:
43836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      PrintOpcodes(Contents->data() + TableEntryOffset, 3, 1);
43936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
44036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    case AEABI_UNWIND_CPP_PR1:
44136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    case AEABI_UNWIND_CPP_PR2:
44236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      unsigned AdditionalWords = (Word & 0x00ff0000) >> 16;
44336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      PrintOpcodes(Contents->data() + TableEntryOffset, 2 + 4 * AdditionalWords,
44436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                   2);
44536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
44636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
44736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  } else {
44836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    SW.printString("Model", StringRef("Generic"));
44936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
45036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    uint64_t Address = PREL31(Word, EHT->sh_addr);
45136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    SW.printHex("PersonalityRoutineAddress", Address);
45236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address))
45336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printString("PersonalityRoutineName", *Name);
45436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
45536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
45636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
45736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
45836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry,
45936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                      size_t Length, off_t Offset) const {
46036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ListScope OCC(SW, "Opcodes");
46136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length);
46236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
46336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
46436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
46536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
46636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                                         const Elf_Shdr *IT) const {
46736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(IT);
46836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!Contents)
46936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return;
47036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
47136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// ARM EHABI Section 5 - Index Table Entries
47236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// * The first word contains a PREL31 offset to the start of a function with
47336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///   bit 31 clear
47436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  /// * The second word contains one of:
47536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///   - The PREL31 offset of the start of the table entry for the function,
47636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///     with bit 31 clear
47736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///   - The exception-handling table entry itself with bit 31 set
47836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///   - The special bit pattern EXIDX_CANTUNWIND, indicating that associated
47936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ///     frames cannot be unwound
48036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
48136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const support::ulittle32_t *Data =
48236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    reinterpret_cast<const support::ulittle32_t *>(Contents->data());
48336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const unsigned Entries = IT->sh_size / IndexTableEntrySize;
48436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
48536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ListScope E(SW, "Entries");
48636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (unsigned Entry = 0; Entry < Entries; ++Entry) {
48736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    DictScope E(SW, "Entry");
48836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
48936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    const support::ulittle32_t Word0 =
49036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 0];
49136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    const support::ulittle32_t Word1 =
49236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 1];
49336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
49436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (Word0 & 0x80000000) {
49536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      errs() << "corrupt unwind data in section " << SectionIndex << "\n";
49636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      continue;
49736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
49836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
49936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    const uint64_t Offset = PREL31(Word0, IT->sh_addr);
50036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    SW.printHex("FunctionAddress", Offset);
50136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset))
50236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printString("FunctionName", *Name);
50336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
50436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (Word1 == EXIDX_CANTUNWIND) {
50536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printString("Model", StringRef("CantUnwind"));
50636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      continue;
50736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
50836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
50936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (Word1 & 0x80000000) {
51036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printString("Model", StringRef("Compact (Inline)"));
51136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
51236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      unsigned PersonalityIndex = (Word1 & 0x0f000000) >> 24;
51336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printNumber("PersonalityIndex", PersonalityIndex);
51436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
51536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1);
51636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    } else {
51736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      const Elf_Shdr *EHT =
51836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4);
51936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
52036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (ErrorOr<StringRef> Name = ELF->getSectionName(EHT))
52136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        SW.printString("ExceptionHandlingTable", *Name);
52236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
52336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr);
52436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printHex("TableEntryOffset", TableEntryOffset);
52536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
52636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      PrintExceptionTable(IT, EHT, TableEntryOffset);
52736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
52836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
52936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
53036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
53136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestemplate <typename ET>
53236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesvoid PrinterContext<ET>::PrintUnwindInformation() const {
53336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  DictScope UI(SW, "UnwindInformation");
53436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
53536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int SectionIndex = 0;
53636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections();
53736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines       SI != SE; ++SI, ++SectionIndex) {
53836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (SI->sh_type == ELF::SHT_ARM_EXIDX) {
53936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      const Elf_Shdr *IT = &(*SI);
54036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
54136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      DictScope UIT(SW, "UnwindIndexTable");
54236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
54336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printNumber("SectionIndex", SectionIndex);
54436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (ErrorOr<StringRef> SectionName = ELF->getSectionName(IT))
54536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        SW.printString("SectionName", *SectionName);
54636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      SW.printHex("SectionOffset", IT->sh_offset);
54736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
54836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      PrintIndexTable(SectionIndex, IT);
54936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
55036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
55136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
55236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
55336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
55436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
55536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
55636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#endif
55736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
558