File: | jdk/src/hotspot/share/compiler/abstractDisassembler.cpp |
Warning: | line 219, column 27 Although the value stored to 'align' is used in the enclosing expression, the value is never actually read from 'align' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. |
3 | * Copyright (c) 2019 SAP SE. All rights reserved. |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
5 | * |
6 | * This code is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License version 2 only, as |
8 | * published by the Free Software Foundation. |
9 | * |
10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
13 | * version 2 for more details (a copy is included in the LICENSE file that |
14 | * accompanied this code). |
15 | * |
16 | * You should have received a copy of the GNU General Public License version |
17 | * 2 along with this work; if not, write to the Free Software Foundation, |
18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | * |
20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
21 | * or visit www.oracle.com if you need additional information or have any |
22 | * questions. |
23 | * |
24 | */ |
25 | |
26 | // AbstractDisassembler is the base class for |
27 | // platform-specific Disassembler classes. |
28 | |
29 | #include "precompiled.hpp" |
30 | #include "asm/assembler.inline.hpp" |
31 | #include "compiler/abstractDisassembler.hpp" |
32 | #include "oops/oop.inline.hpp" |
33 | #include "utilities/debug.hpp" |
34 | #include "utilities/ostream.hpp" |
35 | |
36 | // Default values for what is being printed as line prefix when disassembling a single instruction. |
37 | // Can be overridden by command line parameter PrintAssemblyOptions. |
38 | bool AbstractDisassembler::_show_data_hex = true; |
39 | bool AbstractDisassembler::_show_data_int = false; |
40 | bool AbstractDisassembler::_show_data_float = false; |
41 | bool AbstractDisassembler::_align_instr = true; |
42 | bool AbstractDisassembler::_show_pc = true; |
43 | bool AbstractDisassembler::_show_offset = false; |
44 | bool AbstractDisassembler::_show_structs = true; |
45 | bool AbstractDisassembler::_show_comment = true; |
46 | bool AbstractDisassembler::_show_block_comment = true; |
47 | |
48 | // set "true" to see what's in memory bit by bit |
49 | // might prove cumbersome on platforms where instr_len is hard to find out |
50 | bool AbstractDisassembler::_show_bytes = false; |
51 | |
52 | // Return #bytes printed. Callers may use that for output alignment. |
53 | // Print instruction address, and offset from blob begin. |
54 | // Offset width (2, 4, 6, 8 bytes) is adapted to size of blob. |
55 | // Working assumption: we are at st->bol() upon entry. If not, it's the |
56 | // caller's responsibility to guarantee proper alignment. |
57 | int AbstractDisassembler::print_location(address here, address begin, address end, outputStream* st, bool align, bool print_header) { |
58 | const int pos_0 = st->position(); |
59 | |
60 | if (show_pc() || show_offset()) { |
61 | st->print(" "); |
62 | } |
63 | |
64 | if (show_pc()) { |
65 | if (print_header) { |
66 | st->print(" %*s", 18, "Address"); |
67 | } else { |
68 | st->print(" " PTR_FORMAT"0x%016" "l" "x", p2i(here)); |
69 | } |
70 | } |
71 | |
72 | if (show_offset()) { |
73 | #ifdef ASSERT1 |
74 | if ((uintptr_t)begin > (uintptr_t)here) st->print(">>begin(" PTR_FORMAT"0x%016" "l" "x" ") > here(" PTR_FORMAT"0x%016" "l" "x" ")<<", p2i(begin), p2i(here)); |
75 | if ((uintptr_t)end < (uintptr_t)here) st->print(">> end(" PTR_FORMAT"0x%016" "l" "x" ") < here(" PTR_FORMAT"0x%016" "l" "x" ")<<", p2i(end), p2i(here)); |
76 | assert((uintptr_t)begin <= (uintptr_t)end, "inverted address range")do { if (!((uintptr_t)begin <= (uintptr_t)end)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/compiler/abstractDisassembler.cpp" , 76, "assert(" "(uintptr_t)begin <= (uintptr_t)end" ") failed" , "inverted address range"); ::breakpoint(); } } while (0); |
77 | #endif |
78 | const int blob_len = end - begin; |
79 | const int offset = here - begin; |
80 | const int width = (blob_len < (1<< 8)) ? 2 : (blob_len < (1<<16)) ? 4 : (blob_len < (1<<24)) ? 6 : 8; |
81 | if (print_header) { |
82 | st->print(" %*s", width+5, "offset"); |
83 | } else { |
84 | st->print(" (+0x%*.*x)", width, width, offset); |
85 | } |
86 | } |
87 | |
88 | if ((show_pc() || show_offset()) && !print_header) { |
89 | st->print(": "); |
90 | } |
91 | |
92 | if (align) { |
93 | const uint tabspacing = 8; |
94 | const uint pos = st->position(); |
95 | const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing /* - 1 */; |
96 | st->fill_to(aligned_pos); |
97 | } |
98 | |
99 | return st->position() - pos_0; |
100 | } |
101 | |
102 | |
103 | // Return #bytes printed. Callers may use that for output alignment. |
104 | // Print instruction in hexadecimal representation, using 2-byte blocks. |
105 | // Used with real disassemblies. Not so useful with abstract disassemblies. |
106 | int AbstractDisassembler::print_instruction(address here, int len, int max_len, outputStream* st, bool align, bool print_header) { |
107 | if (show_bytes()) { |
108 | const int block_bytes = 2; |
109 | const int pos_0 = st->position(); |
110 | address pos = here; |
111 | |
112 | //---< print instruction bytes in blocks >--- |
113 | // must print byte by byte: address might be unaligned. |
114 | for (; pos <= here + len - block_bytes; pos += block_bytes) { |
115 | for (address byte = pos; byte < pos + block_bytes; byte++) { |
116 | st->print("%2.2x", *byte); |
117 | } |
118 | st->print(" "); |
119 | } |
120 | |
121 | //---< Print the remaining bytes of the instruction >--- |
122 | if ((len & (block_bytes - 1)) != 0) { |
123 | for (; pos < here + len; pos++) { |
124 | st->print("%2.2x", *pos); |
125 | } |
126 | } |
127 | |
128 | //---< filler for shorter than max_len instructions >--- |
129 | for (int i = len+1; i < max_len; i++) { |
130 | st->print(" "); |
131 | } |
132 | |
133 | st->print(" "); // separator space. |
134 | print_delimiter(st); |
135 | return st->position() - pos_0; |
136 | } |
137 | |
138 | if (align) { |
139 | const uint tabspacing = 8; |
140 | const uint pos = st->position(); |
141 | const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing /* - 1 */; |
142 | st->fill_to(aligned_pos); |
143 | } |
144 | |
145 | return 0; |
146 | } |
147 | |
148 | |
149 | // Return #bytes printed. Callers may use that for output alignment. |
150 | // Print data (e.g. constant pool entries) in hex format. |
151 | // Depending on the alignment, short, int, and long entities are printed. |
152 | // If selected, data is formatted as int/long and float/double values in addition. |
153 | int AbstractDisassembler::print_hexdata(address here, int len, outputStream* st, bool print_header) { |
154 | const int tsize = 8; |
155 | const int pos_0 = st->position(); |
156 | int pos = pos_0; |
157 | int align = ((pos+tsize-1)/tsize)*tsize; |
158 | st->fill_to(align); |
159 | |
160 | //---< printing hex data >--- |
161 | if (show_data_hex()) { |
162 | switch (len) { |
163 | case 1: if (print_header) { |
164 | st->print("hex1"); |
165 | } else { |
166 | st->print("0x%02x", *here); |
167 | } |
168 | st->fill_to(align += tsize); |
169 | case 2: if (print_header) { |
170 | st->print(" hex2"); |
171 | } else { |
172 | if (((uintptr_t)(here)&0x01) == 0) { |
173 | st->print("0x%04x", *((jushort*)here)); |
174 | } |
175 | } |
176 | st->fill_to(align += tsize); |
177 | case 4: if (print_header) { |
178 | st->print(" hex4"); |
179 | } else { |
180 | if (((uintptr_t)(here)&0x03) == 0) { |
181 | st->print("0x%08x", *((juint*)here)); |
182 | } |
183 | } |
184 | st->fill_to(align += 2*tsize); |
185 | case 8: if (print_header) { |
186 | st->print(" hex8"); |
187 | } else { |
188 | if (((uintptr_t)(here)&0x07) == 0) { |
189 | st->print(PTR_FORMAT"0x%016" "l" "x", *((uintptr_t*)here)); |
190 | } |
191 | } |
192 | st->fill_to(align += 3*tsize); |
193 | break; |
194 | default: ; |
195 | } |
196 | pos = st->position(); |
197 | align = ((pos+tsize-1)/tsize)*tsize; |
198 | st->fill_to(align); |
199 | } |
200 | |
201 | //---< printing int/long data >--- |
202 | if (show_data_int()) { |
203 | switch (len) { |
204 | case 4: if (print_header) { |
205 | st->print(" int"); |
206 | } else { |
207 | if (((uintptr_t)(here)&0x03) == 0) { |
208 | st->print("%12.1d", *((jint*)here)); |
209 | } |
210 | } |
211 | st->fill_to(align += 2*tsize); |
212 | case 8: if (print_header) { |
213 | st->print(" long"); |
214 | } else { |
215 | if (((uintptr_t)(here)&0x07) == 0) { |
216 | st->print(JLONG_FORMAT_W(23)"%" "23" "l" "d", *((jlong*)here)); |
217 | } |
218 | } |
219 | st->fill_to(align += 3*tsize); |
Although the value stored to 'align' is used in the enclosing expression, the value is never actually read from 'align' | |
220 | break; |
221 | default: ; |
222 | } |
223 | pos = st->position(); |
224 | align = ((pos+tsize-1)/tsize)*tsize; |
225 | st->fill_to(align); |
226 | } |
227 | |
228 | //---< printing float/double data >--- |
229 | if (show_data_float()) { |
230 | switch (len) { |
231 | case 4: if (print_header) { |
232 | st->print(" float"); |
233 | } else { |
234 | if (((uintptr_t)(here)&0x03) == 0) { |
235 | st->print("%15.7e", (double)*((float*)here)); |
236 | } |
237 | } |
238 | st->fill_to(align += 2*tsize); |
239 | case 8: if (print_header) { |
240 | st->print(" double"); |
241 | } else { |
242 | if (((uintptr_t)(here)&0x07) == 0) { |
243 | st->print("%23.15e", *((double*)here)); |
244 | } |
245 | } |
246 | st->fill_to(align += 3*tsize); |
247 | break; |
248 | default: ; |
249 | } |
250 | } |
251 | |
252 | return st->position() - pos_0; |
253 | } |
254 | |
255 | |
256 | // Return #bytes printed. Callers may use that for output alignment. |
257 | // Print an instruction delimiter. |
258 | int AbstractDisassembler::print_delimiter(outputStream* st) { |
259 | if (align_instr()) { st->print("| "); return 2; } |
260 | else return 0; |
261 | } |
262 | |
263 | |
264 | // Decodes the one instruction at address start in a platform-independent format. |
265 | // Returns the start of the next instruction (which is 'start' plus 'instruction_size_in_bytes'). |
266 | // The parameter max_instr_size_in_bytes is used for output alignment purposes only. |
267 | address AbstractDisassembler::decode_instruction_abstract(address start, |
268 | outputStream* st, |
269 | const int instruction_size_in_bytes, |
270 | const int max_instr_size_in_bytes) { |
271 | assert(instruction_size_in_bytes > 0, "no zero-size instructions!")do { if (!(instruction_size_in_bytes > 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/compiler/abstractDisassembler.cpp" , 271, "assert(" "instruction_size_in_bytes > 0" ") failed" , "no zero-size instructions!"); ::breakpoint(); } } while (0 ); |
272 | assert(max_instr_size_in_bytes >= instruction_size_in_bytes, "inconsistent call parameters")do { if (!(max_instr_size_in_bytes >= instruction_size_in_bytes )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/compiler/abstractDisassembler.cpp" , 272, "assert(" "max_instr_size_in_bytes >= instruction_size_in_bytes" ") failed", "inconsistent call parameters"); ::breakpoint(); } } while (0); |
273 | |
274 | //---< current instruction is at the start address >--- |
275 | unsigned char* current = (unsigned char*) start; |
276 | int filler_limit = align_instr() ? max_instr_size_in_bytes : ((instruction_size_in_bytes+abstract_instruction_bytes_per_block-1)/abstract_instruction_bytes_per_block) |
277 | *abstract_instruction_bytes_per_block; |
278 | |
279 | //---< print the instruction's bytes >--- |
280 | for (int i = 1; i <= instruction_size_in_bytes; i++) { |
281 | st->print("%02x", *current); |
282 | ++current; |
283 | if (abstract_instruction_bytes_per_block <= max_instr_size_in_bytes) { |
284 | if (i%abstract_instruction_bytes_per_block == 0) st->print(" "); |
285 | } else { |
286 | if (i == instruction_size_in_bytes) st->print(" "); |
287 | } |
288 | } |
289 | |
290 | //---< print some filler spaces to column-align instructions >--- |
291 | for (int i = instruction_size_in_bytes+1; i <= filler_limit; i++) { |
292 | st->print(" "); |
293 | if (abstract_instruction_bytes_per_block <= max_instr_size_in_bytes) { |
294 | if (i%abstract_instruction_bytes_per_block == 0) st->print(" "); |
295 | } else { |
296 | if (i == instruction_size_in_bytes) st->print(" "); |
297 | } |
298 | } |
299 | |
300 | //---< the address of the next instruction >--- |
301 | return (address) current; |
302 | } |
303 | |
304 | |
305 | // Decodes all instructions in the given range [start..end) |
306 | // calling decode_instruction_abstract for each instruction. |
307 | // The format is platform dependent only to the extend that |
308 | // it respects the actual instruction length where possible. |
309 | // Does not print any markers or decorators. |
310 | void AbstractDisassembler::decode_range_abstract(address range_start, address range_end, |
311 | address start, address end, |
312 | outputStream* st, |
313 | const int max_instr_size_in_bytes) { |
314 | assert(st != NULL, "need an output stream (no default)!")do { if (!(st != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/compiler/abstractDisassembler.cpp" , 314, "assert(" "st != __null" ") failed", "need an output stream (no default)!" ); ::breakpoint(); } } while (0); |
315 | int idx = 0; |
316 | address pos = range_start; |
317 | |
318 | while ((pos != NULL__null) && (pos < range_end)) { |
319 | int instr_size_in_bytes = Assembler::instr_len(pos); |
320 | |
321 | if (idx == 0) print_location(pos, start, end, st, false, false); |
322 | else print_delimiter(st); |
323 | |
324 | //---< print the instruction's bytes >--- |
325 | // don't access storage beyond end of range |
326 | if (pos + instr_size_in_bytes <= range_end) { |
327 | pos = decode_instruction_abstract(pos, st, instr_size_in_bytes, max_instr_size_in_bytes); |
328 | } else { |
329 | // If the range to be decoded contains garbage at the end (e.g. 0xcc initializer bytes), |
330 | // instruction size calculation may run out of sync. Just terminate in that case. |
331 | pos = range_end; |
332 | } |
333 | |
334 | idx += instr_size_in_bytes; |
335 | if (start_newline(idx)) { |
336 | st->cr(); |
337 | idx = 0; |
338 | } |
339 | } |
340 | } |
341 | |
342 | |
343 | // Decodes all instructions in the given range [start..end). |
344 | // The output is enclosed in [MachCode] and [/MachCode] tags for later recognition. |
345 | // The format is platform dependent only to the extend that |
346 | // it respects the actual instruction length where possible. |
347 | void AbstractDisassembler::decode_abstract(address start, address end, outputStream* ost, |
348 | const int max_instr_size_in_bytes) { |
349 | int idx = 0; |
350 | address pos = start; |
351 | |
352 | outputStream* st = (ost == NULL__null) ? tty : ost; |
353 | |
354 | //---< Open the output (Marker for post-mortem disassembler) >--- |
355 | st->bol(); |
356 | st->print_cr("[MachCode]"); |
357 | |
358 | decode_range_abstract(start, end, start, end, st, max_instr_size_in_bytes); |
359 | |
360 | //---< Close the output (Marker for post-mortem disassembler) >--- |
361 | st->bol(); |
362 | st->print_cr("[/MachCode]"); |
363 | } |