2 +----------------------------------------------------------------------+
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"
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"
30 static uintptr_t excludeLow
, excludeLen
;
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
,
38 if (address
- excludeLow
< excludeLen
) return 0;
40 auto name
= boost::trim_copy(getNativeFunctionName((void*)address
));
41 if (boost::starts_with(name
, "0x")) {
44 strncpy(symbolBuffer
, name
.c_str(), bufferLength
- 1);
45 symbolBuffer
[bufferLength
- 1] = '\0';
49 #endif /* HAVE_LIBXED */
51 void Disasm::ExcludedAddressRange(void* low
, size_t len
) {
52 excludeLow
= uintptr_t(low
);
56 Disasm::Disasm(const Disasm::Options
& opts
)
60 xed_state_init(&m_xedState
, XED_MACHINE_MODE_LONG_64
,
61 XED_ADDRESS_WIDTH_64b
, XED_ADDRESS_WIDTH_64b
);
63 #if XED_ENCODE_ORDER_MAX_ENTRIES == 28 // Older version of XED library
64 xed_register_disassembly_callback(addressToSymbol
);
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
;
77 void Disasm::disasm(std::ostream
& out
, uint8_t* codeStartAddr
,
78 uint8_t* codeEndAddr
, uint64_t adjust
) {
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
);
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
) {
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
);
103 // Get disassembled instruction in codeStr
104 auto const syntax
= m_opts
.m_forceAttSyntax
? XED_SYNTAX_ATT
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
112 out
<< folly::format("xed_format_context failed at address {}\n",
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
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
) -
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(
139 m_opts
.m_relativeOffset
? (ip
- codeBase
) : (ip
- adjust
)
142 if (m_opts
.m_printEncoding
) {
143 // print encoding, like in objdump
145 for (; posi
< instrLen
; ++posi
) {
146 out
<< folly::format("{:02x} ", (uint8_t)frontier
[posi
]);
148 for (; posi
< 16; ++posi
) {
152 out
<< codeStr
<< jmpComment
<< endClr
<< '\n';
153 frontier
+= instrLen
;
157 out
<< "This binary was compiled without disassembly support\n";
158 #endif // HAVE_LIBXED