1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "courgette/disassembler.h"
6
7#include <algorithm>
8#include <string>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/logging.h"
13
14#include "courgette/assembly_program.h"
15#include "courgette/courgette.h"
16#include "courgette/disassembler_elf_32_arm.h"
17#include "courgette/disassembler_elf_32_x86.h"
18#include "courgette/disassembler_win32_x64.h"
19#include "courgette/disassembler_win32_x86.h"
20#include "courgette/encoded_program.h"
21
22namespace courgette {
23
24////////////////////////////////////////////////////////////////////////////////
25
26Disassembler* DetectDisassembler(const void* buffer, size_t length) {
27  Disassembler* disassembler = NULL;
28
29  disassembler = new DisassemblerWin32X86(buffer, length);
30  if (disassembler->ParseHeader())
31    return disassembler;
32  else
33    delete disassembler;
34
35  disassembler = new DisassemblerWin32X64(buffer, length);
36  if (disassembler->ParseHeader())
37    return disassembler;
38  else
39    delete disassembler;
40
41  disassembler = new DisassemblerElf32X86(buffer, length);
42  if (disassembler->ParseHeader())
43    return disassembler;
44  else
45    delete disassembler;
46
47  disassembler = new DisassemblerElf32ARM(buffer, length);
48  if (disassembler->ParseHeader())
49    return disassembler;
50  else
51    delete disassembler;
52
53  return NULL;
54}
55
56Status DetectExecutableType(const void* buffer, size_t length,
57                            ExecutableType* type,
58                            size_t* detected_length) {
59
60  Disassembler* disassembler = DetectDisassembler(buffer, length);
61
62  if (disassembler) {
63    *type = disassembler->kind();
64    *detected_length = disassembler->length();
65    delete disassembler;
66    return C_OK;
67  }
68
69  // We failed to detect anything
70  *type = EXE_UNKNOWN;
71  *detected_length = 0;
72  return C_INPUT_NOT_RECOGNIZED;
73}
74
75Status ParseDetectedExecutable(const void* buffer, size_t length,
76                               AssemblyProgram** output) {
77  *output = NULL;
78
79  Disassembler* disassembler = DetectDisassembler(buffer, length);
80
81  if (!disassembler) {
82    return C_INPUT_NOT_RECOGNIZED;
83  }
84
85  AssemblyProgram* program = new AssemblyProgram(disassembler->kind());
86
87  if (!disassembler->Disassemble(program)) {
88    delete program;
89    delete disassembler;
90    return C_DISASSEMBLY_FAILED;
91  }
92
93  delete disassembler;
94  *output = program;
95  return C_OK;
96}
97
98void DeleteAssemblyProgram(AssemblyProgram* program) {
99  delete program;
100}
101
102Disassembler::Disassembler(const void* start, size_t length)
103  : failure_reason_("uninitialized") {
104
105  start_ = reinterpret_cast<const uint8*>(start);
106  length_ = length;
107  end_ = start_ + length_;
108};
109
110Disassembler::~Disassembler() {};
111
112const uint8* Disassembler::OffsetToPointer(size_t offset) const {
113  assert(start_ + offset <= end_);
114  return start_ + offset;
115}
116
117bool Disassembler::Good() {
118  failure_reason_ = NULL;
119  return true;
120}
121
122bool Disassembler::Bad(const char* reason) {
123  failure_reason_ = reason;
124  return false;
125}
126
127void Disassembler::ReduceLength(size_t reduced_length) {
128  if (reduced_length < length_)
129    length_ = reduced_length;
130}
131
132}  // namespace courgette
133