1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifndef COURGETTE_DISASSEMBLER_ELF_32_H_
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define COURGETTE_DISASSEMBLER_ELF_32_H_
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/basictypes.h"
9a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/memory/scoped_vector.h"
10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "courgette/assembly_program.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/disassembler.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/memory_allocator.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/types_elf.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace courgette {
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass AssemblyProgram;
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// A courgette disassembler for 32-bit ELF files.  This class is only a
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// partial implementation.  Subclasses implement the
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// architecture-specific parts of processing 32-bit ELF files.  Specifically,
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// RelToRVA processes entries in ELF relocation table,
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// ParseRelocationSection verifies the organization of the ELF
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// relocation table, and ParseRel32RelocsFromSection finds branch
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// targets by looking for relative jump/call opcodes in the particular
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// architecture's machine code.
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass DisassemblerElf32 : public Disassembler {
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
29a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // Different instructions encode the target rva differently.  This
30a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // class encapsulates this behavior.  public for use in unit tests.
31a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  class TypedRVA {
32a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch   public:
33a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    explicit TypedRVA(RVA rva) : rva_(rva), offset_(-1) {
34a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
35a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
36a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    virtual ~TypedRVA() { };
37a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
38a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    RVA rva() {
39a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      return rva_;
40a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
41a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
42a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    RVA relative_target() {
43a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      return relative_target_;
44a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
45a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
46a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    void set_relative_target(RVA relative_target) {
47a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      relative_target_ = relative_target;
48a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
49a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    size_t get_offset() {
51a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      return offset_;
52a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
53a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
54a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    void set_offset(size_t offset) {
55a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      offset_ = offset;
56a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
57a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Computes the relative jump's offset from the op in p.
59a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    virtual CheckBool ComputeRelativeTarget(const uint8* op_pointer) = 0;
60a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Emits the courgette instruction corresponding to the RVA type.
62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    virtual CheckBool EmitInstruction(AssemblyProgram* program,
63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                      RVA target_rva) = 0;
64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    virtual uint16 op_size() const = 0;
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
67a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    static bool IsLessThan(TypedRVA *a, TypedRVA *b) {
68a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      return a->rva() < b->rva();
69a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
70a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
71a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  private:
72a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const RVA rva_;
73a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    RVA relative_target_;
74a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    size_t offset_;
75a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  };
76a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
77a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch public:
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  explicit DisassemblerElf32(const void* start, size_t length);
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
80a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  virtual ~DisassemblerElf32() { };
81a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual ExecutableType kind() = 0;
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual e_machine_values ElfEM() = 0;
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Returns 'true' if the buffer appears to point to a valid ELF executable
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // for 32 bit. If ParseHeader() succeeds, other member
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // functions may be called.
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual bool ParseHeader();
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual bool Disassemble(AssemblyProgram* target);
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Public for unittests only
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<RVA> &Abs32Locations() { return abs32_locations_; }
95a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  ScopedVector<TypedRVA> &Rel32Locations() { return rel32_locations_; }
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch protected:
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uint32 DiscoverLength();
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Misc Section Helpers
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Half SectionHeaderCount() const {
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return section_header_table_size_;
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const Elf32_Shdr *SectionHeader(int id) const {
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    assert(id >= 0 && id < SectionHeaderCount());
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return section_header_table_ + id;
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const uint8 *SectionBody(int id) const {
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return OffsetToPointer(SectionHeader(id)->sh_offset);
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Word SectionBodySize(int id) const {
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return SectionHeader(id)->sh_size;
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Misc Segment Helpers
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Half ProgramSegmentHeaderCount() const {
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return program_header_table_size_;
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const Elf32_Phdr *ProgramSegmentHeader(int id) const {
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    assert(id >= 0 && id < ProgramSegmentHeaderCount());
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return program_header_table_ + id;
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The virtual memory address at which this program segment will be loaded
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Addr ProgramSegmentMemoryBegin(int id) const {
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return ProgramSegmentHeader(id)->p_vaddr;
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The number of virtual memory bytes for this program segment
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Word ProgramSegmentMemorySize(int id) const {
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return ProgramSegmentHeader(id)->p_memsz;
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Pointer into the source file for this program segment
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Addr ProgramSegmentFileOffset(int id) const {
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return ProgramSegmentHeader(id)->p_offset;
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Number of file bytes for this program segment. Is <= ProgramMemorySize.
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Word ProgramSegmentFileSize(int id) const {
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return ProgramSegmentHeader(id)->p_filesz;
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Misc address space helpers
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool IsValidRVA(RVA rva) const WARN_UNUSED_RESULT;
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Convert an ELF relocation struction into an RVA
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual CheckBool RelToRVA(Elf32_Rel rel, RVA* result)
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const WARN_UNUSED_RESULT = 0;
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Returns kNoOffset if there is no file offset corresponding to 'rva'.
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool RVAToFileOffset(RVA rva, size_t* result) const WARN_UNUSED_RESULT;
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RVA FileOffsetToRVA(size_t offset) const WARN_UNUSED_RESULT;
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool RVAsToOffsets(std::vector<RVA>* rvas /*in*/,
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          std::vector<size_t>* offsets /*out*/);
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
167a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  CheckBool RVAsToOffsets(ScopedVector<TypedRVA>* rvas /*in and out*/);
168a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Parsing Code used to really implement Disassemble
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool ParseFile(AssemblyProgram* target) WARN_UNUSED_RESULT;
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual CheckBool ParseRelocationSection(
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const Elf32_Shdr *section_header,
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        AssemblyProgram* program) WARN_UNUSED_RESULT = 0;
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool ParseProgbitsSection(
176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const Elf32_Shdr *section_header,
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::vector<size_t>::iterator* current_abs_offset,
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::vector<size_t>::iterator end_abs_offset,
179a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      ScopedVector<TypedRVA>::iterator* current_rel,
180a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      ScopedVector<TypedRVA>::iterator end_rel,
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      AssemblyProgram* program) WARN_UNUSED_RESULT;
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool ParseSimpleRegion(size_t start_file_offset,
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              size_t end_file_offset,
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              AssemblyProgram* program) WARN_UNUSED_RESULT;
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool ParseAbs32Relocs() WARN_UNUSED_RESULT;
187ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CheckBool CheckSection(RVA rva) WARN_UNUSED_RESULT;
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CheckBool ParseRel32RelocsFromSections() WARN_UNUSED_RESULT;
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual CheckBool ParseRel32RelocsFromSection(
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const Elf32_Shdr* section) WARN_UNUSED_RESULT = 0;
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Ehdr *header_;
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Shdr *section_header_table_;
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Half section_header_table_size_;
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Phdr *program_header_table_;
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf32_Half program_header_table_size_;
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Section header for default
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const char *default_string_section_;
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<RVA> abs32_locations_;
203a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  ScopedVector<TypedRVA> rel32_locations_;
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DISALLOW_COPY_AND_ASSIGN(DisassemblerElf32);
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace courgette
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif  // COURGETTE_DISASSEMBLER_ELF_32_H_
211