53 static const char decode_instructions_name[] = "decode_instructions"; |
54 static const char decode_instructions_name[] = "decode_instructions"; |
54 static bool use_new_version = true; |
55 static bool use_new_version = true; |
55 #define COMMENT_COLUMN 52 LP64_ONLY(+8) /*could be an option*/ |
56 #define COMMENT_COLUMN 52 LP64_ONLY(+8) /*could be an option*/ |
56 #define BYTES_COMMENT ";..." /* funky byte display comment */ |
57 #define BYTES_COMMENT ";..." /* funky byte display comment */ |
57 |
58 |
58 bool Disassembler::load_library() { |
|
59 if (_decode_instructions_virtual != NULL || _decode_instructions != NULL) { |
|
60 // Already succeeded. |
|
61 return true; |
|
62 } |
|
63 if (_tried_to_load_library) { |
|
64 // Do not try twice. |
|
65 // To force retry in debugger: assign _tried_to_load_library=0 |
|
66 return false; |
|
67 } |
|
68 // Try to load it. |
|
69 char ebuf[1024]; |
|
70 char buf[JVM_MAXPATHLEN]; |
|
71 os::jvm_path(buf, sizeof(buf)); |
|
72 int jvm_offset = -1; |
|
73 int lib_offset = -1; |
|
74 #ifdef STATIC_BUILD |
|
75 char* p = strrchr(buf, '/'); |
|
76 *p = '\0'; |
|
77 strcat(p, "/lib/"); |
|
78 lib_offset = jvm_offset = strlen(buf); |
|
79 #else |
|
80 { |
|
81 // Match "jvm[^/]*" in jvm_path. |
|
82 const char* base = buf; |
|
83 const char* p = strrchr(buf, *os::file_separator()); |
|
84 if (p != NULL) lib_offset = p - base + 1; |
|
85 p = strstr(p ? p : base, "jvm"); |
|
86 if (p != NULL) jvm_offset = p - base; |
|
87 } |
|
88 #endif |
|
89 // Find the disassembler shared library. |
|
90 // Search for several paths derived from libjvm, in this order: |
|
91 // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so (for compatibility) |
|
92 // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so |
|
93 // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so |
|
94 // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH) |
|
95 if (jvm_offset >= 0) { |
|
96 // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so |
|
97 strcpy(&buf[jvm_offset], hsdis_library_name); |
|
98 strcat(&buf[jvm_offset], os::dll_file_extension()); |
|
99 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
100 if (_library == NULL && lib_offset >= 0) { |
|
101 // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so |
|
102 strcpy(&buf[lib_offset], hsdis_library_name); |
|
103 strcat(&buf[lib_offset], os::dll_file_extension()); |
|
104 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
105 } |
|
106 if (_library == NULL && lib_offset > 0) { |
|
107 // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so |
|
108 buf[lib_offset - 1] = '\0'; |
|
109 const char* p = strrchr(buf, *os::file_separator()); |
|
110 if (p != NULL) { |
|
111 lib_offset = p - buf + 1; |
|
112 strcpy(&buf[lib_offset], hsdis_library_name); |
|
113 strcat(&buf[lib_offset], os::dll_file_extension()); |
|
114 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
115 } |
|
116 } |
|
117 } |
|
118 if (_library == NULL) { |
|
119 // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH) |
|
120 strcpy(&buf[0], hsdis_library_name); |
|
121 strcat(&buf[0], os::dll_file_extension()); |
|
122 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
123 } |
|
124 if (_library != NULL) { |
|
125 _decode_instructions_virtual = CAST_TO_FN_PTR(Disassembler::decode_func_virtual, |
|
126 os::dll_lookup(_library, decode_instructions_virtual_name)); |
|
127 } |
|
128 if (_decode_instructions_virtual == NULL && _library != NULL) { |
|
129 // could not spot in new version, try old version |
|
130 _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func, |
|
131 os::dll_lookup(_library, decode_instructions_name)); |
|
132 use_new_version = false; |
|
133 } else { |
|
134 use_new_version = true; |
|
135 } |
|
136 _tried_to_load_library = true; |
|
137 if (_decode_instructions_virtual == NULL && _decode_instructions == NULL) { |
|
138 tty->print_cr("Could not load %s; %s; %s", buf, |
|
139 ((_library != NULL) |
|
140 ? "entry point is missing" |
|
141 : (WizardMode || PrintMiscellaneous) |
|
142 ? (const char*)ebuf |
|
143 : "library not loadable"), |
|
144 "PrintAssembly is disabled"); |
|
145 return false; |
|
146 } |
|
147 |
|
148 // Success. |
|
149 tty->print_cr("Loaded disassembler from %s", buf); |
|
150 return true; |
|
151 } |
|
152 |
|
153 |
|
154 class decode_env { |
59 class decode_env { |
155 private: |
60 private: |
156 nmethod* _nm; |
61 outputStream* _output; // where the disassembly is directed to |
157 CodeBlob* _code; |
62 CodeBuffer* _codeBuffer; // != NULL only when decoding a CodeBuffer |
|
63 CodeBlob* _codeBlob; // != NULL only when decoding a CodeBlob |
|
64 nmethod* _nm; // != NULL only when decoding a nmethod |
158 CodeStrings _strings; |
65 CodeStrings _strings; |
159 outputStream* _output; |
66 address _start; // != NULL when decoding a range of unknown type |
160 address _start, _end; |
67 address _end; // != NULL when decoding a range of unknown type |
161 ptrdiff_t _offset; |
|
162 |
68 |
163 char _option_buf[512]; |
69 char _option_buf[512]; |
164 char _print_raw; |
70 char _print_raw; |
165 bool _print_pc; |
71 address _cur_insn; // address of instruction currently being decoded |
166 bool _print_bytes; |
72 int _bytes_per_line; // arch-specific formatting option |
167 address _cur_insn; |
73 int _pre_decode_alignment; |
168 int _bytes_per_line; // arch-specific formatting option |
74 int _post_decode_alignment; |
169 bool _print_file_name; |
75 bool _print_file_name; |
170 |
76 bool _print_help; |
|
77 bool _helpPrinted; |
|
78 static bool _optionsParsed; |
|
79 |
|
80 enum { |
|
81 tabspacing = 8 |
|
82 }; |
|
83 |
|
84 // Check if the event matches the expected tag |
|
85 // The tag must be a substring of the event, and |
|
86 // the tag must be a token in the event, i.e. separated by delimiters |
171 static bool match(const char* event, const char* tag) { |
87 static bool match(const char* event, const char* tag) { |
172 size_t taglen = strlen(tag); |
88 size_t eventlen = strlen(event); |
173 if (strncmp(event, tag, taglen) != 0) |
89 size_t taglen = strlen(tag); |
|
90 if (eventlen < taglen) // size mismatch |
|
91 return false; |
|
92 if (strncmp(event, tag, taglen) != 0) // string mismatch |
174 return false; |
93 return false; |
175 char delim = event[taglen]; |
94 char delim = event[taglen]; |
176 return delim == '\0' || delim == ' ' || delim == '/' || delim == '='; |
95 return delim == '\0' || delim == ' ' || delim == '/' || delim == '='; |
177 } |
96 } |
178 |
97 |
|
98 // Merge new option string with previously recorded options |
179 void collect_options(const char* p) { |
99 void collect_options(const char* p) { |
180 if (p == NULL || p[0] == '\0') return; |
100 if (p == NULL || p[0] == '\0') return; |
181 size_t opt_so_far = strlen(_option_buf); |
101 size_t opt_so_far = strlen(_option_buf); |
182 if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return; |
102 if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return; |
183 char* fillp = &_option_buf[opt_so_far]; |
103 char* fillp = &_option_buf[opt_so_far]; |
185 strcat(fillp, p); |
105 strcat(fillp, p); |
186 // replace white space by commas: |
106 // replace white space by commas: |
187 char* q = fillp; |
107 char* q = fillp; |
188 while ((q = strpbrk(q, " \t\n")) != NULL) |
108 while ((q = strpbrk(q, " \t\n")) != NULL) |
189 *q++ = ','; |
109 *q++ = ','; |
190 // Note that multiple PrintAssemblyOptions flags accumulate with \n, |
110 } |
191 // which we want to be changed to a comma... |
111 |
192 } |
112 void process_options(outputStream* ost); |
193 |
113 |
194 void print_insn_labels(); |
114 void print_insn_labels(); |
195 void print_insn_bytes(address pc0, address pc); |
115 void print_insn_prefix(); |
196 void print_address(address value); |
116 void print_address(address value); |
|
117 |
|
118 // Properly initializes _start/_end. Overwritten too often if |
|
119 // printing of instructions is called for each instruction. |
|
120 void set_start(address s) { _start = s; } |
|
121 void set_end (address e) { _end = e; } |
|
122 void set_nm (nmethod* nm) { _nm = nm; } |
|
123 void set_output(outputStream* st) { _output = st; } |
|
124 |
|
125 #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) |
|
126 // The disassembler library (sometimes) uses tabs to nicely align the instruction operands. |
|
127 // Depending on the mnemonic length and the column position where the |
|
128 // mnemonic is printed, alignment may turn out to be not so nice. |
|
129 // To improve, we assume 8-character tab spacing and left-align the mnemonic on a tab position. |
|
130 // Instruction comments are aligned 4 tab positions to the right of the mnemonic. |
|
131 void calculate_alignment() { |
|
132 _pre_decode_alignment = ((output()->position()+tabspacing-1)/tabspacing)*tabspacing; |
|
133 _post_decode_alignment = _pre_decode_alignment + 4*tabspacing; |
|
134 } |
|
135 |
|
136 void start_insn(address pc) { |
|
137 _cur_insn = pc; |
|
138 output()->bol(); |
|
139 print_insn_labels(); |
|
140 print_insn_prefix(); |
|
141 } |
|
142 |
|
143 void end_insn(address pc) { |
|
144 address pc0 = cur_insn(); |
|
145 outputStream* st = output(); |
|
146 |
|
147 if (AbstractDisassembler::show_comment()) { |
|
148 if ((_nm != NULL) && _nm->has_code_comment(pc0, pc)) { |
|
149 _nm->print_code_comment_on(st, _post_decode_alignment, pc0, pc); |
|
150 // this calls reloc_string_for which calls oop::print_value_on |
|
151 } |
|
152 print_hook_comments(pc0, _nm != NULL); |
|
153 } |
|
154 Disassembler::annotate(pc0, output()); |
|
155 // follow each complete insn by a nice newline |
|
156 st->bol(); |
|
157 } |
|
158 #endif |
197 |
159 |
198 struct SourceFileInfo { |
160 struct SourceFileInfo { |
199 struct Link : public CHeapObj<mtCode> { |
161 struct Link : public CHeapObj<mtCode> { |
200 const char* file; |
162 const char* file; |
201 int line; |
163 int line; |
239 static SourceFileInfoTable _src_table; |
201 static SourceFileInfoTable _src_table; |
240 static const char* _cached_src; |
202 static const char* _cached_src; |
241 static GrowableArray<const char*>* _cached_src_lines; |
203 static GrowableArray<const char*>* _cached_src_lines; |
242 |
204 |
243 public: |
205 public: |
244 decode_env(CodeBlob* code, outputStream* output, |
206 decode_env(CodeBuffer* code, outputStream* output); |
245 CodeStrings c = CodeStrings(), ptrdiff_t offset = 0); |
207 decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings() /* , ptrdiff_t offset */); |
246 |
208 decode_env(nmethod* code, outputStream* output, CodeStrings c = CodeStrings()); |
247 address decode_instructions(address start, address end); |
209 // Constructor for a 'decode_env' to decode an arbitrary |
248 |
210 // piece of memory, hopefully containing code. |
249 void start_insn(address pc) { |
211 decode_env(address start, address end, outputStream* output); |
250 _cur_insn = pc; |
212 |
251 output()->bol(); |
213 // Add 'original_start' argument which is the the original address |
252 print_insn_labels(); |
214 // the instructions were located at (if this is not equal to 'start'). |
253 } |
215 address decode_instructions(address start, address end, address original_start = NULL); |
254 |
|
255 void end_insn(address pc) { |
|
256 address pc0 = cur_insn(); |
|
257 outputStream* st = output(); |
|
258 if (_print_bytes && pc > pc0) |
|
259 print_insn_bytes(pc0, pc); |
|
260 if (_nm != NULL) { |
|
261 _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc); |
|
262 // this calls reloc_string_for which calls oop::print_value_on |
|
263 } |
|
264 print_hook_comments(pc0, _nm != NULL); |
|
265 // follow each complete insn by a nice newline |
|
266 st->cr(); |
|
267 } |
|
268 |
216 |
269 address handle_event(const char* event, address arg); |
217 address handle_event(const char* event, address arg); |
270 |
218 |
271 outputStream* output() { return _output; } |
219 outputStream* output() { return _output; } |
272 address cur_insn() { return _cur_insn; } |
220 address cur_insn() { return _cur_insn; } |
273 const char* options() { return _option_buf; } |
221 const char* options() { return _option_buf; } |
274 static void hook(const char* file, int line, address pc); |
222 static void hook(const char* file, int line, address pc); |
275 void print_hook_comments(address pc, bool newline); |
223 void print_hook_comments(address pc, bool newline); |
276 }; |
224 }; |
|
225 |
|
226 bool decode_env::_optionsParsed = false; |
277 |
227 |
278 decode_env::SourceFileInfoTable decode_env::_src_table; |
228 decode_env::SourceFileInfoTable decode_env::_src_table; |
279 const char* decode_env::_cached_src = NULL; |
229 const char* decode_env::_cached_src = NULL; |
280 GrowableArray<const char*>* decode_env::_cached_src_lines = NULL; |
230 GrowableArray<const char*>* decode_env::_cached_src_lines = NULL; |
281 |
231 |
359 } |
309 } |
360 } |
310 } |
361 } |
311 } |
362 } |
312 } |
363 |
313 |
364 decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c, |
314 decode_env::decode_env(CodeBuffer* code, outputStream* output) { |
365 ptrdiff_t offset) : _nm(NULL), |
315 memset(this, 0, sizeof(*this)); |
366 _start(NULL), |
|
367 _end(NULL), |
|
368 _option_buf(), |
|
369 _print_raw('\0'), |
|
370 _cur_insn(NULL) { |
|
371 _output = output ? output : tty; |
316 _output = output ? output : tty; |
372 _code = code; |
317 _codeBlob = NULL; |
373 if (code != NULL && code->is_nmethod()) |
318 _codeBuffer = code; |
|
319 _helpPrinted = false; |
|
320 |
|
321 process_options(_output); |
|
322 } |
|
323 |
|
324 decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) { |
|
325 memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields. |
|
326 _output = output ? output : tty; |
|
327 _codeBlob = code; |
|
328 _codeBuffer = NULL; |
|
329 _helpPrinted = false; |
|
330 if (_codeBlob != NULL && _codeBlob->is_nmethod()) { |
374 _nm = (nmethod*) code; |
331 _nm = (nmethod*) code; |
|
332 } |
375 _strings.copy(c); |
333 _strings.copy(c); |
376 _offset = offset; |
334 |
377 |
335 process_options(_output); |
|
336 } |
|
337 |
|
338 decode_env::decode_env(nmethod* code, outputStream* output, CodeStrings c) { |
|
339 memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields. |
|
340 _output = output ? output : tty; |
|
341 _codeBlob = NULL; |
|
342 _codeBuffer = NULL; |
|
343 _nm = code; |
|
344 _start = _nm->code_begin(); |
|
345 _end = _nm->code_end(); |
|
346 _helpPrinted = false; |
|
347 _strings.copy(c); |
|
348 |
|
349 process_options(_output); |
|
350 } |
|
351 |
|
352 // Constructor for a 'decode_env' to decode a memory range [start, end) |
|
353 // of unknown origin, assuming it contains code. |
|
354 decode_env::decode_env(address start, address end, outputStream* output) { |
|
355 assert(start < end, "Range must have a positive size, [" PTR_FORMAT ".." PTR_FORMAT ").", p2i(start), p2i(end)); |
|
356 memset(this, 0, sizeof(*this)); |
|
357 _output = output ? output : tty; |
|
358 _codeBlob = NULL; |
|
359 _codeBuffer = NULL; |
|
360 _start = start; |
|
361 _end = end; |
|
362 _helpPrinted = false; |
|
363 |
|
364 process_options(_output); |
|
365 } |
|
366 |
|
367 void decode_env::process_options(outputStream* ost) { |
378 // by default, output pc but not bytes: |
368 // by default, output pc but not bytes: |
379 _print_pc = true; |
369 _print_help = false; |
380 _print_bytes = false; |
370 _bytes_per_line = Disassembler::pd_instruction_alignment(); |
381 _bytes_per_line = Disassembler::pd_instruction_alignment(); |
371 _print_file_name = true; |
382 _print_file_name= true; |
372 |
|
373 if (_optionsParsed) return; // parse only once |
383 |
374 |
384 // parse the global option string: |
375 // parse the global option string: |
385 collect_options(Disassembler::pd_cpu_opts()); |
376 collect_options(Disassembler::pd_cpu_opts()); |
386 collect_options(PrintAssemblyOptions); |
377 collect_options(PrintAssemblyOptions); |
387 |
378 |
388 if (strstr(options(), "hsdis-")) { |
379 if (strstr(options(), "print-raw")) { |
389 if (strstr(options(), "hsdis-print-raw")) |
380 _print_raw = (strstr(options(), "xml") ? 2 : 1); |
390 _print_raw = (strstr(options(), "xml") ? 2 : 1); |
381 } |
391 if (strstr(options(), "hsdis-print-pc")) |
382 |
392 _print_pc = !_print_pc; |
|
393 if (strstr(options(), "hsdis-print-bytes")) |
|
394 _print_bytes = !_print_bytes; |
|
395 } |
|
396 if (strstr(options(), "help")) { |
383 if (strstr(options(), "help")) { |
397 tty->print_cr("PrintAssemblyOptions help:"); |
384 _print_help = true; |
398 tty->print_cr(" hsdis-print-raw test plugin by requesting raw output"); |
385 } |
399 tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml"); |
386 if (strstr(options(), "align-instr")) { |
400 tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)"); |
387 AbstractDisassembler::toggle_align_instr(); |
401 tty->print_cr(" hsdis-print-bytes turn on instruction byte output"); |
388 } |
402 tty->print_cr("combined options: %s", options()); |
389 if (strstr(options(), "show-pc")) { |
403 } |
390 AbstractDisassembler::toggle_show_pc(); |
404 } |
391 } |
405 |
392 if (strstr(options(), "show-offset")) { |
|
393 AbstractDisassembler::toggle_show_offset(); |
|
394 } |
|
395 if (strstr(options(), "show-bytes")) { |
|
396 AbstractDisassembler::toggle_show_bytes(); |
|
397 } |
|
398 if (strstr(options(), "show-data-hex")) { |
|
399 AbstractDisassembler::toggle_show_data_hex(); |
|
400 } |
|
401 if (strstr(options(), "show-data-int")) { |
|
402 AbstractDisassembler::toggle_show_data_int(); |
|
403 } |
|
404 if (strstr(options(), "show-data-float")) { |
|
405 AbstractDisassembler::toggle_show_data_float(); |
|
406 } |
|
407 if (strstr(options(), "show-structs")) { |
|
408 AbstractDisassembler::toggle_show_structs(); |
|
409 } |
|
410 if (strstr(options(), "show-comment")) { |
|
411 AbstractDisassembler::toggle_show_comment(); |
|
412 } |
|
413 if (strstr(options(), "show-block-comment")) { |
|
414 AbstractDisassembler::toggle_show_block_comment(); |
|
415 } |
|
416 _optionsParsed = true; |
|
417 |
|
418 if (_print_help && ! _helpPrinted) { |
|
419 _helpPrinted = true; |
|
420 ost->print_cr("PrintAssemblyOptions help:"); |
|
421 ost->print_cr(" print-raw test plugin by requesting raw output"); |
|
422 ost->print_cr(" print-raw-xml test plugin by requesting raw xml"); |
|
423 ost->cr(); |
|
424 ost->print_cr(" show-pc toggle printing current pc, currently %s", AbstractDisassembler::show_pc() ? "ON" : "OFF"); |
|
425 ost->print_cr(" show-offset toggle printing current offset, currently %s", AbstractDisassembler::show_offset() ? "ON" : "OFF"); |
|
426 ost->print_cr(" show-bytes toggle printing instruction bytes, currently %s", AbstractDisassembler::show_bytes() ? "ON" : "OFF"); |
|
427 ost->print_cr(" show-data-hex toggle formatting data as hex, currently %s", AbstractDisassembler::show_data_hex() ? "ON" : "OFF"); |
|
428 ost->print_cr(" show-data-int toggle formatting data as int, currently %s", AbstractDisassembler::show_data_int() ? "ON" : "OFF"); |
|
429 ost->print_cr(" show-data-float toggle formatting data as float, currently %s", AbstractDisassembler::show_data_float() ? "ON" : "OFF"); |
|
430 ost->print_cr(" show-structs toggle compiler data structures, currently %s", AbstractDisassembler::show_structs() ? "ON" : "OFF"); |
|
431 ost->print_cr(" show-comment toggle instruction comments, currently %s", AbstractDisassembler::show_comment() ? "ON" : "OFF"); |
|
432 ost->print_cr(" show-block-comment toggle block comments, currently %s", AbstractDisassembler::show_block_comment() ? "ON" : "OFF"); |
|
433 ost->print_cr(" align-instr toggle instruction alignment, currently %s", AbstractDisassembler::align_instr() ? "ON" : "OFF"); |
|
434 ost->print_cr("combined options: %s", options()); |
|
435 } |
|
436 } |
|
437 |
|
438 // Disassembly Event Handler. |
|
439 // This method receives events from the disassembler library hsdis |
|
440 // via event_to_env for each decoding step (installed by |
|
441 // Disassembler::decode_instructions(), replacing the default |
|
442 // callback method). This enables dumping additional info |
|
443 // and custom line formatting. |
|
444 // In a future extension, calling a custom decode method will be |
|
445 // supported. We can use such a method to decode instructions the |
|
446 // binutils decoder does not handle to our liking (suboptimal |
|
447 // formatting, incomplete information, ...). |
|
448 // Returns: |
|
449 // - NULL for all standard invocations. The function result is not |
|
450 // examined (as of now, 20190409) by the hsdis decoder loop. |
|
451 // - next for 'insn0' invocations. |
|
452 // next == arg: the custom decoder didn't do anything. |
|
453 // next > arg: the custom decoder did decode the instruction. |
|
454 // next points to the next undecoded instruction |
|
455 // (continuation point for decoder loop). |
|
456 // |
|
457 // "Normal" sequence of events: |
|
458 // insns - start of instruction stream decoding |
|
459 // mach - display architecture |
|
460 // format - display bytes-per-line |
|
461 // for each instruction: |
|
462 // insn - start of instruction decoding |
|
463 // insn0 - custom decoder invocation (if any) |
|
464 // addr - print address value |
|
465 // /insn - end of instruction decoding |
|
466 // /insns - premature end of instruction stream due to no progress |
|
467 // |
406 address decode_env::handle_event(const char* event, address arg) { |
468 address decode_env::handle_event(const char* event, address arg) { |
407 if (match(event, "insn")) { |
469 |
|
470 #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) |
|
471 |
|
472 //---< Event: end decoding loop (error, no progress) >--- |
|
473 if (decode_env::match(event, "/insns")) { |
|
474 // Nothing to be done here. |
|
475 return NULL; |
|
476 } |
|
477 |
|
478 //---< Event: start decoding loop >--- |
|
479 if (decode_env::match(event, "insns")) { |
|
480 // Nothing to be done here. |
|
481 return NULL; |
|
482 } |
|
483 |
|
484 //---< Event: finish decoding an instruction >--- |
|
485 if (decode_env::match(event, "/insn")) { |
|
486 output()->fill_to(_post_decode_alignment); |
|
487 end_insn(arg); |
|
488 return NULL; |
|
489 } |
|
490 |
|
491 //---< Event: start decoding an instruction >--- |
|
492 if (decode_env::match(event, "insn")) { |
408 start_insn(arg); |
493 start_insn(arg); |
409 } else if (match(event, "/insn")) { |
494 } else if (match(event, "/insn")) { |
410 end_insn(arg); |
495 end_insn(arg); |
411 } else if (match(event, "addr")) { |
496 } else if (match(event, "addr")) { |
412 if (arg != NULL) { |
497 if (arg != NULL) { |
413 print_address(arg); |
498 print_address(arg); |
414 return arg; |
499 return arg; |
415 } |
500 } |
416 } else if (match(event, "mach")) { |
501 calculate_alignment(); |
417 static char buffer[32] = { 0, }; |
502 output()->fill_to(_pre_decode_alignment); |
418 if (strcmp(buffer, (const char*)arg) != 0 || |
503 return NULL; |
419 strlen((const char*)arg) > sizeof(buffer) - 1) { |
504 } |
|
505 |
|
506 //---< Event: call custom decoder (platform specific) >--- |
|
507 if (decode_env::match(event, "insn0")) { |
|
508 return Disassembler::decode_instruction0(arg, output(), arg); |
|
509 } |
|
510 |
|
511 //---< Event: Print address >--- |
|
512 if (decode_env::match(event, "addr")) { |
|
513 print_address(arg); |
|
514 return arg; |
|
515 } |
|
516 |
|
517 //---< Event: mach (inform about machine architecture) >--- |
|
518 // This event is problematic because it messes up the output. |
|
519 // The event is fired after the instruction address has already |
|
520 // been printed. The decoded instruction (event "insn") is |
|
521 // printed afterwards. That doesn't look nice. |
|
522 if (decode_env::match(event, "mach")) { |
|
523 guarantee(arg != NULL, "event_to_env - arg must not be NULL for event 'mach'"); |
|
524 static char buffer[64] = { 0, }; |
|
525 // Output suppressed because it messes up disassembly. |
|
526 // Only print this when the mach changes. |
|
527 if (false && (strcmp(buffer, (const char*)arg) != 0 || |
|
528 strlen((const char*)arg) > sizeof(buffer) - 1)) { |
420 // Only print this when the mach changes |
529 // Only print this when the mach changes |
421 strncpy(buffer, (const char*)arg, sizeof(buffer) - 1); |
530 strncpy(buffer, (const char*)arg, sizeof(buffer) - 1); |
422 buffer[sizeof(buffer) - 1] = '\0'; |
531 buffer[sizeof(buffer) - 1] = '\0'; |
423 output()->print_cr("[Disassembling for mach='%s']", arg); |
532 output()->print_cr("[Disassembling for mach='%s']", (const char*)arg); |
424 } |
533 } |
425 } else if (match(event, "format bytes-per-line")) { |
534 return NULL; |
|
535 } |
|
536 |
|
537 //---< Event: format bytes-per-line >--- |
|
538 if (decode_env::match(event, "format bytes-per-line")) { |
426 _bytes_per_line = (int) (intptr_t) arg; |
539 _bytes_per_line = (int) (intptr_t) arg; |
427 } else { |
540 return NULL; |
428 // ignore unrecognized markup |
541 } |
429 } |
542 #endif |
430 return NULL; |
543 return NULL; |
|
544 } |
|
545 |
|
546 static void* event_to_env(void* env_pv, const char* event, void* arg) { |
|
547 decode_env* env = (decode_env*) env_pv; |
|
548 return env->handle_event(event, (address) arg); |
431 } |
549 } |
432 |
550 |
433 // called by the disassembler to print out jump targets and data addresses |
551 // called by the disassembler to print out jump targets and data addresses |
434 void decode_env::print_address(address adr) { |
552 void decode_env::print_address(address adr) { |
435 outputStream* st = _output; |
553 outputStream* st = output(); |
436 |
554 |
437 if (adr == NULL) { |
555 if (adr == NULL) { |
438 st->print("NULL"); |
556 st->print("NULL"); |
439 return; |
557 return; |
440 } |
558 } |
493 // Fall through to a simple (hexadecimal) numeral. |
613 // Fall through to a simple (hexadecimal) numeral. |
494 st->print(PTR_FORMAT, p2i(adr)); |
614 st->print(PTR_FORMAT, p2i(adr)); |
495 } |
615 } |
496 |
616 |
497 void decode_env::print_insn_labels() { |
617 void decode_env::print_insn_labels() { |
498 address p = cur_insn(); |
618 if (AbstractDisassembler::show_block_comment()) { |
|
619 address p = cur_insn(); |
|
620 outputStream* st = output(); |
|
621 |
|
622 //---< Block comments for nmethod >--- |
|
623 // Outputs a bol() before and a cr() after, but only if a comment is printed. |
|
624 // Prints nmethod_section_label as well. |
|
625 if (_nm != NULL) { |
|
626 _nm->print_block_comment(st, p); |
|
627 } |
|
628 if (_codeBlob != NULL) { |
|
629 _codeBlob->print_block_comment(st, p); |
|
630 } |
|
631 if (_codeBuffer != NULL) { |
|
632 _codeBuffer->print_block_comment(st, p); |
|
633 } |
|
634 _strings.print_block_comment(st, (intptr_t)(p - _start)); |
|
635 } |
|
636 } |
|
637 |
|
638 void decode_env::print_insn_prefix() { |
|
639 address p = cur_insn(); |
499 outputStream* st = output(); |
640 outputStream* st = output(); |
500 CodeBlob* cb = _code; |
641 AbstractDisassembler::print_location(p, _start, _end, st, false, false); |
501 if (cb != NULL) { |
642 AbstractDisassembler::print_instruction(p, Assembler::instr_len(p), Assembler::instr_maxlen(), st, true, false); |
502 cb->print_block_comment(st, p); |
|
503 } |
|
504 _strings.print_block_comment(st, (intptr_t)(p - _start + _offset)); |
|
505 if (_print_pc) { |
|
506 st->print(" " PTR_FORMAT ": ", p2i(p)); |
|
507 } |
|
508 } |
|
509 |
|
510 void decode_env::print_insn_bytes(address pc, address pc_limit) { |
|
511 outputStream* st = output(); |
|
512 size_t incr = 1; |
|
513 size_t perline = _bytes_per_line; |
|
514 if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int) |
|
515 && !((uintptr_t)pc % sizeof(int)) |
|
516 && !((uintptr_t)pc_limit % sizeof(int))) { |
|
517 incr = sizeof(int); |
|
518 if (perline % incr) perline += incr - (perline % incr); |
|
519 } |
|
520 while (pc < pc_limit) { |
|
521 // tab to the desired column: |
|
522 st->move_to(COMMENT_COLUMN); |
|
523 address pc0 = pc; |
|
524 address pc1 = pc + perline; |
|
525 if (pc1 > pc_limit) pc1 = pc_limit; |
|
526 for (; pc < pc1; pc += incr) { |
|
527 if (pc == pc0) { |
|
528 st->print(BYTES_COMMENT); |
|
529 } else if ((uint)(pc - pc0) % sizeof(int) == 0) { |
|
530 st->print(" "); // put out a space on word boundaries |
|
531 } |
|
532 if (incr == sizeof(int)) { |
|
533 st->print("%08x", *(int*)pc); |
|
534 } else { |
|
535 st->print("%02x", (*pc)&0xFF); |
|
536 } |
|
537 } |
|
538 st->cr(); |
|
539 } |
|
540 } |
|
541 |
|
542 |
|
543 static void* event_to_env(void* env_pv, const char* event, void* arg) { |
|
544 decode_env* env = (decode_env*) env_pv; |
|
545 return env->handle_event(event, (address) arg); |
|
546 } |
643 } |
547 |
644 |
548 ATTRIBUTE_PRINTF(2, 3) |
645 ATTRIBUTE_PRINTF(2, 3) |
549 static int printf_to_env(void* env_pv, const char* format, ...) { |
646 static int printf_to_env(void* env_pv, const char* format, ...) { |
550 decode_env* env = (decode_env*) env_pv; |
647 decode_env* env = (decode_env*) env_pv; |
623 &event_to_env, (void*) this, |
735 &event_to_env, (void*) this, |
624 &printf_to_env, (void*) this, |
736 &printf_to_env, (void*) this, |
625 options()); |
737 options()); |
626 } |
738 } |
627 |
739 |
628 |
740 // ---------------------------------------------------------------------------- |
629 void Disassembler::decode(CodeBlob* cb, outputStream* st) { |
741 // Disassembler |
630 ttyLocker ttyl; |
742 // Used as a static wrapper for decode_env. |
631 if (!load_library()) return; |
743 // Each method will create a decode_env before decoding. |
|
744 // You can call the decode_env methods directly if you already have one. |
|
745 |
|
746 |
|
747 bool Disassembler::load_library(outputStream* st) { |
|
748 // Do not try to load multiple times. Failed once -> fails always. |
|
749 // To force retry in debugger: assign _tried_to_load_library=0 |
|
750 if (_tried_to_load_library) { |
|
751 return _library_usable; |
|
752 } |
|
753 |
|
754 #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) |
|
755 // Print to given stream, if any. |
|
756 // Print to tty if Verbose is on and no stream given. |
|
757 st = ((st == NULL) && Verbose) ? tty : st; |
|
758 |
|
759 // Compute fully qualified library name. |
|
760 char ebuf[1024]; |
|
761 char buf[JVM_MAXPATHLEN]; |
|
762 os::jvm_path(buf, sizeof(buf)); |
|
763 int jvm_offset = -1; |
|
764 int lib_offset = -1; |
|
765 #ifdef STATIC_BUILD |
|
766 char* p = strrchr(buf, '/'); |
|
767 *p = '\0'; |
|
768 strcat(p, "/lib/"); |
|
769 lib_offset = jvm_offset = strlen(buf); |
|
770 #else |
|
771 { |
|
772 // Match "libjvm" instead of "jvm" on *nix platforms. Creates better matches. |
|
773 // Match "[lib]jvm[^/]*" in jvm_path. |
|
774 const char* base = buf; |
|
775 const char* p = strrchr(buf, *os::file_separator()); |
|
776 #ifdef _WIN32 |
|
777 p = strstr(p ? p : base, "jvm"); |
|
778 #else |
|
779 p = strstr(p ? p : base, "libjvm"); |
|
780 #endif |
|
781 if (p != NULL) lib_offset = p - base + 1; |
|
782 if (p != NULL) jvm_offset = p - base; |
|
783 } |
|
784 #endif |
|
785 |
|
786 // Find the disassembler shared library. |
|
787 // Search for several paths derived from libjvm, in this order: |
|
788 // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so (for compatibility) |
|
789 // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so |
|
790 // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so |
|
791 // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH) |
|
792 if (jvm_offset >= 0) { |
|
793 // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so |
|
794 strcpy(&buf[jvm_offset], hsdis_library_name); |
|
795 strcat(&buf[jvm_offset], os::dll_file_extension()); |
|
796 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
797 if (_library == NULL && lib_offset >= 0) { |
|
798 // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so |
|
799 strcpy(&buf[lib_offset], hsdis_library_name); |
|
800 strcat(&buf[lib_offset], os::dll_file_extension()); |
|
801 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
802 } |
|
803 if (_library == NULL && lib_offset > 0) { |
|
804 // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so |
|
805 buf[lib_offset - 1] = '\0'; |
|
806 const char* p = strrchr(buf, *os::file_separator()); |
|
807 if (p != NULL) { |
|
808 lib_offset = p - buf + 1; |
|
809 strcpy(&buf[lib_offset], hsdis_library_name); |
|
810 strcat(&buf[lib_offset], os::dll_file_extension()); |
|
811 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
812 } |
|
813 } |
|
814 } |
|
815 if (_library == NULL) { |
|
816 // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH) |
|
817 strcpy(&buf[0], hsdis_library_name); |
|
818 strcat(&buf[0], os::dll_file_extension()); |
|
819 _library = os::dll_load(buf, ebuf, sizeof ebuf); |
|
820 } |
|
821 |
|
822 // load the decoder function to use (new or old version). |
|
823 if (_library != NULL) { |
|
824 _decode_instructions_virtual = CAST_TO_FN_PTR(Disassembler::decode_func_virtual, |
|
825 os::dll_lookup(_library, decode_instructions_virtual_name)); |
|
826 } |
|
827 if (_decode_instructions_virtual == NULL && _library != NULL) { |
|
828 // could not spot in new version, try old version |
|
829 _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func, |
|
830 os::dll_lookup(_library, decode_instructions_name)); |
|
831 use_new_version = false; |
|
832 } else { |
|
833 use_new_version = true; |
|
834 } |
|
835 _tried_to_load_library = true; |
|
836 _library_usable = _decode_instructions_virtual != NULL || _decode_instructions != NULL; |
|
837 |
|
838 // Create a dummy environment to initialize PrintAssemblyOptions. |
|
839 // The PrintAssemblyOptions must be known for abstract disassemblies as well. |
|
840 decode_env dummy((unsigned char*)(&buf[0]), (unsigned char*)(&buf[1]), st); |
|
841 |
|
842 // Report problems during dll_load or dll_lookup, if any. |
|
843 if (st != NULL) { |
|
844 // Success. |
|
845 if (_library_usable) { |
|
846 st->print_cr("Loaded disassembler from %s", buf); |
|
847 } else { |
|
848 st->print_cr("Could not load %s; %s; %s", |
|
849 buf, |
|
850 ((_library != NULL) |
|
851 ? "entry point is missing" |
|
852 : ((WizardMode || PrintMiscellaneous) |
|
853 ? (const char*)ebuf |
|
854 : "library not loadable")), |
|
855 "PrintAssembly defaults to abstract disassembly."); |
|
856 } |
|
857 } |
|
858 #endif |
|
859 return _library_usable; |
|
860 } |
|
861 |
|
862 |
|
863 // Directly disassemble code buffer. |
|
864 void Disassembler::decode(CodeBuffer* cb, address start, address end, outputStream* st) { |
|
865 #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) |
|
866 //---< Test memory before decoding >--- |
|
867 if (!(cb->contains(start) && cb->contains(end))) { |
|
868 //---< Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode. >--- |
|
869 if (st != NULL) { |
|
870 st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not contained in CodeBuffer", p2i(start), p2i(end)); |
|
871 } |
|
872 return; |
|
873 } |
|
874 if (!os::is_readable_range(start, end)) { |
|
875 //---< Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode. >--- |
|
876 if (st != NULL) { |
|
877 st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not readable", p2i(start), p2i(end)); |
|
878 } |
|
879 return; |
|
880 } |
|
881 |
|
882 decode_env env(cb, st); |
|
883 env.output()->print_cr("--------------------------------------------------------------------------------"); |
|
884 env.output()->print("Decoding CodeBuffer (" PTR_FORMAT ")", p2i(cb)); |
|
885 if (cb->name() != NULL) { |
|
886 env.output()->print(", name: %s,", cb->name()); |
|
887 } |
|
888 env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(start), p2i(end), ((jlong)(end - start))); |
|
889 |
|
890 if (is_abstract()) { |
|
891 AbstractDisassembler::decode_abstract(start, end, env.output(), Assembler::instr_maxlen()); |
|
892 } else { |
|
893 env.decode_instructions(start, end); |
|
894 } |
|
895 env.output()->print_cr("--------------------------------------------------------------------------------"); |
|
896 #endif |
|
897 } |
|
898 |
|
899 // Directly disassemble code blob. |
|
900 void Disassembler::decode(CodeBlob* cb, outputStream* st, CodeStrings c) { |
|
901 #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) |
632 if (cb->is_nmethod()) { |
902 if (cb->is_nmethod()) { |
633 decode((nmethod*)cb, st); |
903 // If we have an nmethod at hand, |
|
904 // call the specialized decoder directly. |
|
905 decode((nmethod*)cb, st, c); |
634 return; |
906 return; |
635 } |
907 } |
|
908 |
636 decode_env env(cb, st); |
909 decode_env env(cb, st); |
637 env.output()->print_cr("----------------------------------------------------------------------"); |
910 env.output()->print_cr("--------------------------------------------------------------------------------"); |
638 if (cb->is_aot()) { |
911 if (cb->is_aot()) { |
639 env.output()->print("A "); |
912 env.output()->print("A "); |
640 if (cb->is_compiled()) { |
913 if (cb->is_compiled()) { |
641 CompiledMethod* cm = (CompiledMethod*)cb; |
914 CompiledMethod* cm = (CompiledMethod*)cb; |
642 env.output()->print("%d ",cm->compile_id()); |
915 env.output()->print("%d ",cm->compile_id()); |
646 cm->method()->signature()->print_symbol_on(env.output()); |
919 cm->method()->signature()->print_symbol_on(env.output()); |
647 } else { |
920 } else { |
648 env.output()->print_cr("%s", cb->name()); |
921 env.output()->print_cr("%s", cb->name()); |
649 } |
922 } |
650 } else { |
923 } else { |
651 env.output()->print_cr("%s", cb->name()); |
924 env.output()->print("Decoding CodeBlob"); |
652 } |
925 if (cb->name() != NULL) { |
653 env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*)); |
926 env.output()->print(", name: %s,", cb->name()); |
654 env.decode_instructions(cb->code_begin(), cb->code_end()); |
927 } |
655 } |
928 } |
656 |
929 env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin()))); |
657 void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c, |
930 |
658 ptrdiff_t offset) { |
931 if (is_abstract()) { |
|
932 AbstractDisassembler::decode_abstract(cb->code_begin(), cb->code_end(), env.output(), Assembler::instr_maxlen()); |
|
933 } else { |
|
934 env.decode_instructions(cb->code_begin(), cb->code_end()); |
|
935 } |
|
936 env.output()->print_cr("--------------------------------------------------------------------------------"); |
|
937 #endif |
|
938 } |
|
939 |
|
940 // Decode a nmethod. |
|
941 // This includes printing the constant pool and all code segments. |
|
942 // The nmethod data structures (oop maps, relocations and the like) are not printed. |
|
943 void Disassembler::decode(nmethod* nm, outputStream* st, CodeStrings c) { |
|
944 #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) |
659 ttyLocker ttyl; |
945 ttyLocker ttyl; |
660 if (!load_library()) return; |
946 |
661 decode_env env(CodeCache::find_blob_unsafe(start), st, c, offset); |
|
662 env.decode_instructions(start, end); |
|
663 } |
|
664 |
|
665 void Disassembler::decode(nmethod* nm, outputStream* st) { |
|
666 ttyLocker ttyl; |
|
667 if (!load_library()) return; |
|
668 decode_env env(nm, st); |
947 decode_env env(nm, st); |
669 env.output()->print_cr("----------------------------------------------------------------------"); |
948 env.output()->print_cr("--------------------------------------------------------------------------------"); |
670 |
949 nm->print_constant_pool(env.output()); |
671 unsigned char* p = nm->code_begin(); |
950 env.output()->print_cr("--------------------------------------------------------------------------------"); |
672 unsigned char* end = nm->code_end(); |
951 env.output()->cr(); |
673 |
952 if (is_abstract()) { |
674 nm->method()->method_holder()->name()->print_symbol_on(env.output()); |
953 AbstractDisassembler::decode_abstract(nm->code_begin(), nm->code_end(), env.output(), Assembler::instr_maxlen()); |
675 env.output()->print("."); |
954 } else { |
676 nm->method()->name()->print_symbol_on(env.output()); |
955 env.decode_instructions(nm->code_begin(), nm->code_end()); |
677 nm->method()->signature()->print_symbol_on(env.output()); |
956 } |
678 #if INCLUDE_JVMCI |
957 env.output()->print_cr("--------------------------------------------------------------------------------"); |
|
958 #endif |
|
959 } |
|
960 |
|
961 // Decode a range, given as [start address, end address) |
|
962 void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c /*, ptrdiff_t offset */) { |
|
963 #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) |
|
964 //---< Test memory before decoding >--- |
|
965 if (!os::is_readable_range(start, end)) { |
|
966 //---< Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode. >--- |
|
967 if (st != NULL) { |
|
968 st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not readable", p2i(start), p2i(end)); |
|
969 } |
|
970 return; |
|
971 } |
|
972 |
|
973 if (is_abstract()) { |
|
974 AbstractDisassembler::decode_abstract(start, end, st, Assembler::instr_maxlen()); |
|
975 return; |
|
976 } |
|
977 |
|
978 // Don't do that fancy stuff. If we just have two addresses, live with it |
|
979 // and treat the memory contents as "amorphic" piece of code. |
|
980 #if 0 |
|
981 CodeBlob* cb = CodeCache::find_blob_unsafe(start); |
|
982 if (cb != NULL) { |
|
983 // If we have an CodeBlob at hand, |
|
984 // call the specialized decoder directly. |
|
985 decode(cb, st, c); |
|
986 } else |
|
987 #endif |
679 { |
988 { |
680 const char* jvmciName = nm->jvmci_name(); |
989 // This seems to be just a chunk of memory. |
681 if (jvmciName != NULL) { |
990 decode_env env(start, end, st); |
682 env.output()->print(" (%s)", jvmciName); |
991 env.output()->print_cr("--------------------------------------------------------------------------------"); |
683 } |
992 env.decode_instructions(start, end); |
|
993 env.output()->print_cr("--------------------------------------------------------------------------------"); |
684 } |
994 } |
685 #endif |
995 #endif |
686 env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p))); |
|
687 |
|
688 // Print constant table. |
|
689 if (nm->consts_size() > 0) { |
|
690 nm->print_nmethod_labels(env.output(), nm->consts_begin()); |
|
691 int offset = 0; |
|
692 for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) { |
|
693 if ((offset % 8) == 0) { |
|
694 env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p2i(p), offset, *((int32_t*) p), *((int64_t*) p)); |
|
695 } else { |
|
696 env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p2i(p), offset, *((int32_t*) p)); |
|
697 } |
|
698 } |
|
699 } |
|
700 |
|
701 env.decode_instructions(p, end); |
|
702 } |
996 } |
703 |
997 |
704 // To prevent excessive code expansion in the interpreter generator, we |
998 // To prevent excessive code expansion in the interpreter generator, we |
705 // do not inline this function into Disassembler::hook(). |
999 // do not inline this function into Disassembler::hook(). |
706 void Disassembler::_hook(const char* file, int line, MacroAssembler* masm) { |
1000 void Disassembler::_hook(const char* file, int line, MacroAssembler* masm) { |