Toplevel entrypoints for classes/traits/interfaces
[hiphop-php.git] / hphp / util / disasm.cpp
blob2b56505aef0dc5d72fa4b791631e46fe9632179f
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/util/disasm.h"
18 #include <iomanip>
19 #include <stdlib.h>
21 #include <boost/algorithm/string.hpp>
23 #include <folly/Format.h>
25 #include "hphp/util/abi-cxx.h"
26 #include "hphp/util/text-color.h"
28 namespace HPHP {
30 static uintptr_t excludeLow, excludeLen;
32 #ifdef HAVE_LIBXED
34 // XED callback function to get a symbol from an address
35 static int addressToSymbol(xed_uint64_t address, char* symbolBuffer,
36 xed_uint32_t bufferLength, xed_uint64_t* offset,
37 void* /*context*/) {
38 if (address - excludeLow < excludeLen) return 0;
40 auto name = boost::trim_copy(getNativeFunctionName((void*)address));
41 if (boost::starts_with(name, "0x")) {
42 return 0;
44 strncpy(symbolBuffer, name.c_str(), bufferLength - 1);
45 symbolBuffer[bufferLength - 1] = '\0';
46 *offset = 0;
47 return 1;
49 #endif /* HAVE_LIBXED */
51 void Disasm::ExcludedAddressRange(void* low, size_t len) {
52 excludeLow = uintptr_t(low);
53 excludeLen = len;
56 Disasm::Disasm(const Disasm::Options& opts)
57 : m_opts(opts)
59 #ifdef HAVE_LIBXED
60 xed_state_init(&m_xedState, XED_MACHINE_MODE_LONG_64,
61 XED_ADDRESS_WIDTH_64b, XED_ADDRESS_WIDTH_64b);
62 xed_tables_init();
63 #if XED_ENCODE_ORDER_MAX_ENTRIES == 28 // Older version of XED library
64 xed_register_disassembly_callback(addressToSymbol);
65 #endif
66 #endif // HAVE_LIBXED
69 #ifdef HAVE_LIBXED
71 #define MAX_INSTR_ASM_LEN 128
73 static const xed_syntax_enum_t s_xed_syntax =
74 getenv("HHVM_INTEL_DISAS") ? XED_SYNTAX_INTEL : XED_SYNTAX_ATT;
75 #endif // HAVE_LIBXED
77 void Disasm::disasm(std::ostream& out, uint8_t* codeStartAddr,
78 uint8_t* codeEndAddr, uint64_t adjust) {
80 #ifdef HAVE_LIBXED
81 auto const endClr = m_opts.m_color.empty() ? "" : ANSI_COLOR_END;
82 char codeStr[MAX_INSTR_ASM_LEN];
83 xed_uint8_t *frontier;
84 xed_decoded_inst_t xedd;
85 uint64_t codeBase = uint64_t(codeStartAddr);
86 uint64_t ip;
88 // Decode and print each instruction
89 for (frontier = codeStartAddr, ip = (uint64_t)codeStartAddr;
90 frontier < codeEndAddr; ) {
91 for (int i = 0; i < m_opts.m_indentLevel; ++i) {
92 out << ' ';
95 xed_decoded_inst_zero_set_mode(&xedd, &m_xedState);
96 xed_decoded_inst_set_input_chip(&xedd, XED_CHIP_INVALID);
97 xed_error_enum_t xed_error = xed_decode(&xedd, frontier, 15);
98 if (xed_error != XED_ERROR_NONE) {
99 out << folly::format("xed_decode failed at address {}\n", frontier);
100 return;
103 // Get disassembled instruction in codeStr
104 auto const syntax = m_opts.m_forceAttSyntax ? XED_SYNTAX_ATT
105 : s_xed_syntax;
106 if (!xed_format_context(syntax, &xedd, codeStr,
107 MAX_INSTR_ASM_LEN, ip - adjust, nullptr
108 #if XED_ENCODE_ORDER_MAX_ENTRIES != 28 // Newer version of XED library
109 , addressToSymbol
110 #endif
111 )) {
112 out << folly::format("xed_format_context failed at address {}\n",
113 frontier);
114 return;
116 uint32_t instrLen = xed_decoded_inst_get_length(&xedd);
118 // If it's a jump, we're printing relative offsets, and the dest
119 // is within the range we're printing, add the dest as a relative
120 // offset.
121 std::string jmpComment;
122 auto const cat = xed_decoded_inst_get_category(&xedd);
123 if (cat == XED_CATEGORY_COND_BR || cat == XED_CATEGORY_UNCOND_BR) {
124 if (m_opts.m_relativeOffset) {
125 auto disp = uint64_t(frontier + instrLen +
126 xed_decoded_inst_get_branch_displacement(&xedd) -
127 codeBase);
128 if (disp < uint64_t(codeEndAddr - codeStartAddr)) {
129 jmpComment = folly::format(" # {:#x}", disp).str();
134 out << m_opts.m_color;
135 if (m_opts.m_addresses) {
136 const char* fmt = m_opts.m_relativeOffset ? "{:3x}: " : "{:#10x}: ";
137 out << folly::format(
138 fmt,
139 m_opts.m_relativeOffset ? (ip - codeBase) : (ip - adjust)
142 if (m_opts.m_printEncoding) {
143 // print encoding, like in objdump
144 unsigned posi = 0;
145 for (; posi < instrLen; ++posi) {
146 out << folly::format("{:02x} ", (uint8_t)frontier[posi]);
148 for (; posi < 16; ++posi) {
149 out << " ";
152 out << codeStr << jmpComment << endClr << '\n';
153 frontier += instrLen;
154 ip += instrLen;
156 #else
157 out << "This binary was compiled without disassembly support\n";
158 #endif // HAVE_LIBXED
161 } // namespace HPHP