1 /* 2 * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* hsdis-demo.c -- dump a range of addresses as native instructions 26 This demonstrates the protocol required by the HotSpot PrintAssembly option. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <inttypes.h> 33 34 #include "hsdis.h" 35 36 37 void greet(const char*); 38 void disassemble(uintptr_t, uintptr_t); 39 void end_of_file(); 40 41 const char* options = NULL; 42 int raw = 0; 43 int xml = 0; 44 45 int main(int ac, char** av) { 46 int greeted = 0; 47 int i; 48 for (i = 1; i < ac; i++) { 49 const char* arg = av[i]; 50 if (arg[0] == '-') { 51 if (!strcmp(arg, "-xml")) 52 xml ^= 1; 53 else if (!strcmp(arg, "-raw")) 54 raw ^= 1; 55 else if (!strncmp(arg, "-options=", 9)) 56 options = arg+9; 57 else 58 { printf("Usage: %s [-xml] [name...]\n", av[0]); exit(2); } 59 continue; 60 } 61 greet(arg); 62 greeted = 1; 63 } 64 if (!greeted) 65 greet("world"); 66 printf("...And now for something completely different:\n"); 67 void *start = (void*) &main; 68 void *end = (void*) &end_of_file; 69 #if defined(__ia64) || defined(__powerpc__) 70 /* On IA64 and PPC function pointers are pointers to function descriptors */ 71 start = *((void**)start); 72 end = *((void**)end); 73 #endif 74 disassemble(start, (end > start) ? end : start + 64); 75 printf("Cheers!\n"); 76 } 77 78 void greet(const char* whom) { 79 printf("Hello, %s!\n", whom); 80 } 81 82 void end_of_file() { } 83 84 /* don't disassemble after this point... */ 85 86 #include "dlfcn.h" 87 88 #define DECODE_INSTRUCTIONS_VIRTUAL_NAME "decode_instructions_virtual" 89 #define DECODE_INSTRUCTIONS_NAME "decode_instructions" 90 #define HSDIS_NAME "hsdis" 91 static void* decode_instructions_pv = 0; 92 static void* decode_instructions_sv = 0; 93 static const char* hsdis_path[] = { 94 HSDIS_NAME"-"LIBARCH LIB_EXT, 95 "./" HSDIS_NAME"-"LIBARCH LIB_EXT, 96 #ifdef TARGET_DIR 97 TARGET_DIR"/"HSDIS_NAME"-"LIBARCH LIB_EXT, 98 #endif 99 NULL 100 }; 101 102 static const char* load_decode_instructions() { 103 void* dllib = NULL; 104 const char* *next_in_path = hsdis_path; 105 while (1) { 106 decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_VIRTUAL_NAME); 107 decode_instructions_sv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME); 108 if (decode_instructions_pv != NULL || decode_instructions_sv != NULL) 109 return NULL; 110 if (dllib != NULL) 111 return "plugin does not defined "DECODE_INSTRUCTIONS_VIRTUAL_NAME" and "DECODE_INSTRUCTIONS_NAME; 112 for (dllib = NULL; dllib == NULL; ) { 113 const char* next_lib = (*next_in_path++); 114 if (next_lib == NULL) 115 return "cannot find plugin "HSDIS_NAME LIB_EXT; 116 dllib = dlopen(next_lib, RTLD_LAZY); 117 } 118 } 119 } 120 121 122 static const char* lookup(void* addr) { 123 #if defined(__ia64) || defined(__powerpc__) 124 /* On IA64 and PPC function pointers are pointers to function descriptors */ 125 #define CHECK_NAME(fn) \ 126 if (addr == *((void**) &fn)) return #fn; 127 #else 128 #define CHECK_NAME(fn) \ 129 if (addr == (void*) &fn) return #fn; 130 #endif 131 132 CHECK_NAME(main); 133 CHECK_NAME(greet); 134 return NULL; 135 } 136 137 /* does the event match the tag, followed by a null, space, or slash? */ 138 #define MATCH(event, tag) \ 139 (!strncmp(event, tag, sizeof(tag)-1) && \ 140 (!event[sizeof(tag)-1] || strchr(" /", event[sizeof(tag)-1]))) 141 142 143 static const char event_cookie[] = "event_cookie"; /* demo placeholder */ 144 static void* simple_handle_event(void* cookie, const char* event, void* arg) { 145 if (MATCH(event, "/insn")) { 146 // follow each complete insn by a nice newline 147 printf("\n"); 148 } 149 return NULL; 150 } 151 152 static void* handle_event(void* cookie, const char* event, void* arg) { 153 #define NS_DEMO "demo:" 154 if (cookie != event_cookie) 155 printf("*** bad event cookie %p != %p\n", cookie, event_cookie); 156 157 if (xml) { 158 /* We could almost do a printf(event, arg), 159 but for the sake of a better demo, 160 we dress the result up as valid XML. 161 */ 162 const char* fmt = strchr(event, ' '); 163 int evlen = (fmt ? fmt - event : strlen(event)); 164 if (!fmt) { 165 if (event[0] != '/') { 166 printf("<"NS_DEMO"%.*s>", evlen, event); 167 } else { 168 printf("</"NS_DEMO"%.*s>", evlen-1, event+1); 169 } 170 } else { 171 if (event[0] != '/') { 172 printf("<"NS_DEMO"%.*s", evlen, event); 173 printf(fmt, arg); 174 printf(">"); 175 } else { 176 printf("<"NS_DEMO"%.*s_done", evlen-1, event+1); 177 printf(fmt, arg); 178 printf("/></"NS_DEMO"%.*s>", evlen-1, event+1); 179 } 180 } 181 } 182 183 if (MATCH(event, "insn")) { 184 const char* name = lookup(arg); 185 if (name) printf("%s:\n", name); 186 187 /* basic action for <insn>: */ 188 printf(" %p\t", arg); 189 190 } else if (MATCH(event, "/insn")) { 191 // follow each complete insn by a nice newline 192 printf("\n"); 193 } else if (MATCH(event, "mach")) { 194 printf("Decoding for CPU '%s'\n", (char*) arg); 195 196 } else if (MATCH(event, "addr")) { 197 /* basic action for <addr/>: */ 198 const char* name = lookup(arg); 199 if (name) { 200 printf("&%s (%p)", name, arg); 201 /* return non-null to notify hsdis not to print the addr */ 202 return arg; 203 } 204 } 205 206 /* null return is always safe; can mean "I ignored it" */ 207 return NULL; 208 } 209 210 #define fprintf_callback \ 211 (decode_instructions_printf_callback_ftype)&fprintf 212 213 void disassemble(uintptr_t from, uintptr_t to) { 214 const char* err = load_decode_instructions(); 215 if (err != NULL) { 216 printf("%s: %s\n", err, dlerror()); 217 exit(1); 218 } 219 decode_func_vtype decode_instructions_v 220 = (decode_func_vtype) decode_instructions_pv; 221 decode_func_stype decode_instructions_s 222 = (decode_func_stype) decode_instructions_sv; 223 void* res; 224 if (decode_instructions_pv != NULL) { 225 printf("\nDecoding from %p to %p...with %s\n", from, to, DECODE_INSTRUCTIONS_VIRTUAL_NAME); 226 if (raw) { 227 res = (*decode_instructions_v)(from, to, 228 (unsigned char*)from, to - from, 229 simple_handle_event, stdout, 230 NULL, stdout, 231 options, 0); 232 } else { 233 res = (*decode_instructions_v)(from, to, 234 (unsigned char*)from, to - from, 235 handle_event, (void*) event_cookie, 236 fprintf_callback, stdout, 237 options, 0); 238 } 239 if (res != (void*)to) 240 printf("*** Result was %p!\n", res); 241 } 242 void* sres; 243 if (decode_instructions_sv != NULL) { 244 printf("\nDecoding from %p to %p...with old decode_instructions\n", from, to, DECODE_INSTRUCTIONS_NAME); 245 if (raw) { 246 sres = (*decode_instructions_s)(from, to, 247 simple_handle_event, stdout, 248 NULL, stdout, 249 options); 250 } else { 251 sres = (*decode_instructions_s)(from, to, 252 handle_event, (void*) event_cookie, 253 fprintf_callback, stdout, 254 options); 255 } 256 if (sres != (void *)to) 257 printf("*** Result of decode_instructions %p!\n", sres); 258 } 259 }