1// Copyright 2016, VIXL authors
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7//   * Redistributions of source code must retain the above copyright notice,
8//     this list of conditions and the following disclaimer.
9//   * Redistributions in binary form must reproduce the above copyright notice,
10//     this list of conditions and the following disclaimer in the documentation
11//     and/or other materials provided with the distribution.
12//   * Neither the name of ARM Limited nor the names of its contributors may be
13//     used to endorse or promote products derived from this software without
14//     specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#include <string>
28#include <map>
29#include <iostream>
30
31#include "aarch32/constants-aarch32.h"
32#include "aarch32/instructions-aarch32.h"
33#include "aarch32/macro-assembler-aarch32.h"
34#include "aarch32/disasm-aarch32.h"
35
36#define __ masm.
37
38namespace vixl {
39namespace aarch32 {
40
41// Example of disassembly customization.
42
43class CustomStream : public Disassembler::DisassemblerStream {
44  std::map<Label::Offset, const char*> symbols_;
45
46 public:
47  CustomStream() : Disassembler::DisassemblerStream(std::cout) {}
48  std::map<Label::Offset, const char*>& GetSymbols() { return symbols_; }
49  virtual DisassemblerStream& operator<<(const Disassembler::PrintLabel& label)
50      VIXL_OVERRIDE {
51    std::map<Label::Offset, const char*>::iterator symbol =
52        symbols_.find(label.GetLabel()->GetLocation() + label.GetPosition());
53    // If the label was named, print the name instead of the address.
54    if (symbol != symbols_.end()) {
55      os() << symbol->second;
56      return *this;
57    }
58    os() << label;
59    return *this;
60  }
61  virtual DisassemblerStream& operator<<(const Register reg) VIXL_OVERRIDE {
62    // Print all the core registers with an upper-case letter instead of the
63    // default lower-case.
64    os() << "R" << reg.GetCode();
65    return *this;
66  }
67};
68
69class CustomDisassembler : public PrintDisassembler {
70 public:
71  explicit CustomDisassembler(CustomStream* stream)
72      : PrintDisassembler(stream) {}
73  CustomStream* GetStream() const {
74    return reinterpret_cast<CustomStream*>(&os());
75  }
76  virtual void PrintCodeAddress(uint32_t pc) VIXL_OVERRIDE {
77    // If the address matches a label, then print the label. Otherwise, print
78    // nothing.
79    std::map<Label::Offset, const char*>::iterator symbol =
80        GetStream()->GetSymbols().find(pc);
81    if (symbol != GetStream()->GetSymbols().end()) {
82      os().os() << symbol->second << ":" << std::endl;
83    }
84    // Add indentation for instructions.
85    os() << "  ";
86  }
87  virtual void PrintOpcode16(uint32_t opcode) VIXL_OVERRIDE {
88    // Do not print opcodes.
89    USE(opcode);
90  }
91  virtual void PrintOpcode32(uint32_t opcode) VIXL_OVERRIDE {
92    // Do not print opcodes.
93    USE(opcode);
94  }
95};
96
97class NamedLabel : public Label {
98  CustomStream* stream_;
99  const char* name_;
100
101 public:
102  NamedLabel(CustomStream* stream, const char* name)
103      : stream_(stream), name_(name) {}
104  ~NamedLabel() {
105    if (IsBound()) {
106      stream_->GetSymbols().insert(
107          std::pair<Label::Offset, const char*>(GetLocation(), name_));
108    }
109  }
110};
111
112void RunCustomDisassemblerTest() {
113  CustomStream stream;
114  MacroAssembler masm;
115  {
116    NamedLabel loop(&stream, "loop");
117    NamedLabel end(&stream, "end");
118    __ Mov(r0, 0);
119    __ Mov(r1, 0);
120    __ Bind(&loop);
121    __ Cmp(r1, 20);
122    __ B(gt, &end);
123    __ Add(r0, r0, r1);
124    __ Add(r1, r1, 1);
125    __ B(&loop);
126    __ Bind(&end);
127    __ Bx(lr);
128    __ FinalizeCode();
129  }
130  std::cout << "Custom disassembly:" << std::endl;
131  CustomDisassembler custom_disassembler(&stream);
132  custom_disassembler
133      .DisassembleA32Buffer(masm.GetBuffer()->GetOffsetAddress<uint32_t*>(0),
134                            masm.GetBuffer()->GetSizeInBytes());
135  std::cout << std::endl;
136  std::cout << "Standard disassembly:" << std::endl;
137  PrintDisassembler print_disassembler(std::cout);
138  print_disassembler
139      .DisassembleA32Buffer(masm.GetBuffer()->GetOffsetAddress<uint32_t*>(0),
140                            masm.GetBuffer()->GetSizeInBytes());
141}
142
143}  // namespace aarch32
144}  // namespace vixl
145
146#ifndef TEST_EXAMPLES
147int main() {
148  vixl::aarch32::RunCustomDisassemblerTest();
149  return 0;
150}
151#endif  // TEST_EXAMPLES
152