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 auto pos
= name
.find_first_of('(');
45 auto copyLength
= pos
!= std::string::npos
46 ? std::min(pos
, size_t(bufferLength
- 1))
48 strncpy(symbolBuffer
, name
.c_str(), copyLength
);
49 symbolBuffer
[copyLength
] = '\0';
53 #endif /* HAVE_LIBXED */
55 void Disasm::ExcludedAddressRange(void* low
, size_t len
) {
56 excludeLow
= uintptr_t(low
);
60 Disasm::Disasm(const Disasm::Options
& opts
)
64 xed_state_init(&m_xedState
, XED_MACHINE_MODE_LONG_64
,
65 XED_ADDRESS_WIDTH_64b
, XED_ADDRESS_WIDTH_64b
);
67 #if XED_ENCODE_ORDER_MAX_ENTRIES == 28 // Older version of XED library
68 xed_register_disassembly_callback(addressToSymbol
);
75 #define MAX_INSTR_ASM_LEN 128
77 static const xed_syntax_enum_t s_xed_syntax
=
78 getenv("HHVM_INTEL_DISAS") ? XED_SYNTAX_INTEL
: XED_SYNTAX_ATT
;
81 void Disasm::disasm(std::ostream
& out
, uint8_t* codeStartAddr
,
82 uint8_t* codeEndAddr
) {
85 auto const endClr
= m_opts
.m_color
.empty() ? "" : ANSI_COLOR_END
;
86 char codeStr
[MAX_INSTR_ASM_LEN
];
87 xed_uint8_t
*frontier
;
88 xed_decoded_inst_t xedd
;
89 uint64_t codeBase
= uint64_t(codeStartAddr
);
92 // Decode and print each instruction
93 for (frontier
= codeStartAddr
, ip
= (uint64_t)codeStartAddr
;
94 frontier
< codeEndAddr
; ) {
95 for (int i
= 0; i
< m_opts
.m_indentLevel
; ++i
) {
99 xed_decoded_inst_zero_set_mode(&xedd
, &m_xedState
);
100 xed_decoded_inst_set_input_chip(&xedd
, XED_CHIP_INVALID
);
101 xed_error_enum_t xed_error
= xed_decode(&xedd
, frontier
, 15);
102 if (xed_error
!= XED_ERROR_NONE
) {
103 out
<< folly::format("xed_decode failed at address {}\n", frontier
);
107 // Get disassembled instruction in codeStr
108 auto const syntax
= m_opts
.m_forceAttSyntax
? XED_SYNTAX_ATT
110 if (!xed_format_context(syntax
, &xedd
, codeStr
,
111 MAX_INSTR_ASM_LEN
, ip
, nullptr
112 #if XED_ENCODE_ORDER_MAX_ENTRIES != 28 // Newer version of XED library
116 out
<< folly::format("xed_format_context failed at address {}\n",
120 uint32_t instrLen
= xed_decoded_inst_get_length(&xedd
);
122 // If it's a jump, we're printing relative offsets, and the dest
123 // is within the range we're printing, add the dest as a relative
125 std::string jmpComment
;
126 auto const cat
= xed_decoded_inst_get_category(&xedd
);
127 if (cat
== XED_CATEGORY_COND_BR
|| cat
== XED_CATEGORY_UNCOND_BR
) {
128 if (m_opts
.m_relativeOffset
) {
129 auto disp
= uint64_t(frontier
+ instrLen
+
130 xed_decoded_inst_get_branch_displacement(&xedd
) -
132 if (disp
< uint64_t(codeEndAddr
- codeStartAddr
)) {
133 jmpComment
= folly::format(" # {:#x}", disp
).str();
138 out
<< m_opts
.m_color
;
139 if (m_opts
.m_addresses
) {
140 const char* fmt
= m_opts
.m_relativeOffset
? "{:3x}: " : "{:#10x}: ";
141 out
<< folly::format(fmt
, ip
- (m_opts
.m_relativeOffset
? codeBase
: 0));
143 if (m_opts
.m_printEncoding
) {
144 // print encoding, like in objdump
146 for (; posi
< instrLen
; ++posi
) {
147 out
<< folly::format("{:02x} ", (uint8_t)frontier
[posi
]);
149 for (; posi
< 16; ++posi
) {
153 out
<< codeStr
<< jmpComment
<< endClr
<< '\n';
154 frontier
+= instrLen
;
158 out
<< "This binary was compiled without disassembly support\n";
159 #endif // HAVE_LIBXED