001 package serp.bytecode.visitor; 002 003 import java.io.*; 004 005 import serp.bytecode.*; 006 import serp.bytecode.lowlevel.*; 007 008 /** 009 * Visitor type that outputs a detailed, formatted document of the 010 * visited entity; similar to the <i>javap -c</i> command but more detailed. 011 * 012 * @author Abe White 013 */ 014 public class PrettyPrintVisitor extends BCVisitor { 015 private PrintWriter _out = null; 016 private String _prefix = ""; 017 018 /** 019 * Constructor; all pritning will go to stdout. 020 */ 021 public PrettyPrintVisitor() { 022 _out = new PrintWriter(System.out); 023 } 024 025 /** 026 * Constructor. 027 * 028 * @param out the stream to print to 029 */ 030 public PrettyPrintVisitor(PrintWriter out) { 031 _out = out; 032 } 033 034 /** 035 * Invoke with the class or file names to pretty print; the 036 * functionality is similar to the <i>javap -c</i> command, but more 037 * detailed. 038 */ 039 public static void main(String[] args) 040 throws ClassNotFoundException, IOException { 041 if (args.length == 0) { 042 System.err.println("Usage: java " 043 + PrettyPrintVisitor.class.getName() 044 + " <class name | .class file>+"); 045 System.exit(1); 046 } 047 048 PrettyPrintVisitor ppv = new PrettyPrintVisitor(); 049 Project project = new Project(); 050 BCClass type; 051 for (int i = 0; i < args.length; i++) { 052 if (args[i].endsWith(".class")) 053 type = project.loadClass(new File(args[i])); 054 else 055 type = project.loadClass(Class.forName(args[i], false, 056 PrettyPrintVisitor.class.getClassLoader())); 057 ppv.visit(type); 058 } 059 } 060 061 public void visit(VisitAcceptor entity) { 062 super.visit(entity); 063 _out.flush(); 064 } 065 066 public void enterProject(Project obj) { 067 openBlock("Project"); 068 println("name=" + obj.getName()); 069 } 070 071 public void exitProject(Project obj) { 072 closeBlock(); 073 } 074 075 public void enterBCClass(BCClass obj) { 076 openBlock("Class"); 077 078 println("magic=" + obj.getMagic()); 079 println("minor=" + obj.getMinorVersion()); 080 println("major=" + obj.getMajorVersion()); 081 println("access=" + obj.getAccessFlags()); 082 println("name=" + obj.getIndex() + " <" + obj.getName() + ">"); 083 println("super=" + obj.getSuperclassIndex() + " <" + 084 obj.getSuperclassName() + ">"); 085 086 int[] indexes = obj.getDeclaredInterfaceIndexes(); 087 String[] names = obj.getDeclaredInterfaceNames(); 088 for (int i = 0; i < indexes.length; i++) 089 println("interface=" + indexes[i] + " <" + names[i] + ">"); 090 } 091 092 public void exitBCClass(BCClass obj) { 093 closeBlock(); 094 } 095 096 public void enterBCField(BCField obj) { 097 openBlock("Field"); 098 println("access=" + obj.getAccessFlags()); 099 println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); 100 println("type=" + obj.getDescriptorIndex() + " <" + obj.getTypeName() 101 + ">"); 102 } 103 104 public void exitBCField(BCField obj) { 105 closeBlock(); 106 } 107 108 public void enterBCMethod(BCMethod obj) { 109 openBlock("Method"); 110 println("access=" + obj.getAccessFlags()); 111 println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); 112 println("descriptor=" + obj.getDescriptorIndex()); 113 println("return=" + obj.getReturnName()); 114 String[] params = obj.getParamNames(); 115 for (int i = 0; i < params.length; i++) 116 println("param=" + params[i]); 117 } 118 119 public void exitBCMethod(BCMethod obj) { 120 closeBlock(); 121 } 122 123 public void enterAttribute(Attribute obj) { 124 openBlock(obj.getName()); 125 } 126 127 public void exitAttribute(Attribute obj) { 128 closeBlock(); 129 } 130 131 public void enterConstantValue(ConstantValue obj) { 132 println("value=" + obj.getValueIndex() + " <" + obj.getTypeName() + 133 "=" + obj.getValue() + ">"); 134 } 135 136 public void enterExceptions(Exceptions obj) { 137 int[] indexes = obj.getExceptionIndexes(); 138 String[] names = obj.getExceptionNames(); 139 for (int i = 0; i < indexes.length; i++) 140 println("exception=" + indexes[i] + " <" + names[i] + ">"); 141 } 142 143 public void enterSourceFile(SourceFile obj) { 144 println("source=" + obj.getFileIndex() + " <" + obj.getFileName() 145 + ">"); 146 } 147 148 public void enterCode(Code obj) { 149 println("maxStack=" + obj.getMaxStack()); 150 println("maxLocals=" + obj.getMaxLocals()); 151 println(""); 152 } 153 154 public void enterExceptionHandler(ExceptionHandler obj) { 155 openBlock("ExceptionHandler"); 156 println("startPc=" + obj.getTryStartPc()); 157 println("endPc=" + obj.getTryEndPc()); 158 println("handlerPc=" + obj.getHandlerStartPc()); 159 println("catch=" + obj.getCatchIndex() + " <" + obj.getCatchName() 160 + ">"); 161 } 162 163 public void exitExceptionHandler(ExceptionHandler obj) { 164 closeBlock(); 165 } 166 167 public void enterInnerClass(InnerClass obj) { 168 openBlock("InnerClass"); 169 println("access=" + obj.getAccessFlags()); 170 println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); 171 println("type=" + obj.getTypeIndex() + "<" + obj.getTypeName() + ">"); 172 println("declarer=" + obj.getDeclarerIndex() + "<" 173 + obj.getDeclarerName() + ">"); 174 } 175 176 public void exitInnerClass(InnerClass obj) { 177 closeBlock(); 178 } 179 180 public void enterLineNumber(LineNumber obj) { 181 openBlock("LineNumber"); 182 println("startPc=" + obj.getStartPc()); 183 println("line=" + obj.getLine()); 184 } 185 186 public void exitLineNumber(LineNumber obj) { 187 closeBlock(); 188 } 189 190 public void enterLocalVariable(LocalVariable obj) { 191 openBlock("LocalVariable"); 192 println("startPc=" + obj.getStartPc()); 193 println("length=" + obj.getLength()); 194 println("local=" + obj.getLocal()); 195 println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); 196 println("type=" + obj.getTypeIndex() + " <" + obj.getTypeName() + ">"); 197 } 198 199 public void exitLocalVariable(LocalVariable obj) { 200 closeBlock(); 201 } 202 203 public void enterLocalVariableType(LocalVariableType obj) { 204 openBlock("LocalVariableType"); 205 println("startPc=" + obj.getStartPc()); 206 println("length=" + obj.getLength()); 207 println("local=" + obj.getLocal()); 208 println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); 209 println("signature=" + obj.getTypeIndex() + " <" + obj.getTypeName() 210 + ">"); 211 } 212 213 public void exitLocalVariableType(LocalVariableType obj) { 214 closeBlock(); 215 } 216 217 public void enterAnnotation(Annotation obj) { 218 openBlock("Annotation"); 219 println("type=" + obj.getTypeIndex() + " <" + obj.getTypeName() + ">"); 220 } 221 222 public void exitAnnotation(Annotation obj) { 223 closeBlock(); 224 } 225 226 public void enterAnnotationProperty(Annotation.Property obj) { 227 openBlock("Property"); 228 println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); 229 Object val = obj.getValue(); 230 if (val instanceof Object[]) { 231 Object[] arr = (Object[]) val; 232 for (int i = 0; i < arr.length; i++) 233 printAnnotationPropertyValue(arr[i]); 234 } else 235 printAnnotationPropertyValue(val); 236 } 237 238 private void printAnnotationPropertyValue(Object obj) { 239 if (obj == null) 240 println("value=null"); 241 else if (obj instanceof Annotation) { 242 _out.print(_prefix); 243 _out.print("value="); 244 ((Annotation) obj).acceptVisit(this); 245 } else 246 println("value=(" + obj.getClass().getName() + ") " + obj); 247 } 248 249 public void exitAnnotationProperty(Annotation.Property obj) { 250 closeBlock(); 251 } 252 253 public void enterInstruction(Instruction obj) { 254 _out.print(_prefix + obj.getByteIndex() + " " + obj.getName() + " "); 255 } 256 257 public void exitInstruction(Instruction obj) { 258 _out.println(); 259 } 260 261 public void enterClassInstruction(ClassInstruction obj) { 262 _out.print(obj.getTypeIndex() + " <" + obj.getTypeName() + ">"); 263 } 264 265 public void enterConstantInstruction(ConstantInstruction obj) { 266 _out.print("<" + obj.getValue() + ">"); 267 } 268 269 public void enterGetFieldInstruction(GetFieldInstruction obj) { 270 _out.print(obj.getFieldIndex() + " <" + obj.getFieldTypeName() + " " 271 + obj.getFieldDeclarerName() + "." + obj.getFieldName() + ">"); 272 } 273 274 public void enterIIncInstruction(IIncInstruction obj) { 275 _out.print(obj.getLocal() + " "); 276 if (obj.getIncrement() < 0) 277 _out.print("-"); 278 _out.print(obj.getIncrement()); 279 } 280 281 public void enterJumpInstruction(JumpInstruction obj) { 282 _out.print(obj.getOffset()); 283 } 284 285 public void enterIfInstruction(IfInstruction obj) { 286 _out.print(obj.getOffset()); 287 } 288 289 public void enterLoadInstruction(LoadInstruction obj) { 290 _out.print("<" + obj.getLocal() + ">"); 291 } 292 293 public void enterLookupSwitchInstruction(LookupSwitchInstruction obj) { 294 _out.println(); 295 _prefix += " "; 296 297 int[] offsets = obj.getOffsets(); 298 int[] matches = obj.getMatches(); 299 for (int i = 0; i < offsets.length; i++) 300 println("case " + matches[i] + "=" + offsets[i]); 301 _out.print(_prefix + "default=" + obj.getDefaultOffset()); 302 _prefix = _prefix.substring(2); 303 } 304 305 public void enterMethodInstruction(MethodInstruction obj) { 306 _out.print(obj.getMethodIndex() + " <" + obj.getMethodReturnName() 307 + " " + obj.getMethodDeclarerName() + "." + obj.getMethodName() 308 + "("); 309 310 String[] params = obj.getMethodParamNames(); 311 int dotIndex; 312 for (int i = 0; i < params.length; i++) { 313 dotIndex = params[i].lastIndexOf('.'); 314 if (dotIndex != -1) 315 params[i] = params[i].substring(dotIndex + 1); 316 317 _out.print(params[i]); 318 if (i != (params.length - 1)) 319 _out.print(", "); 320 } 321 _out.print(")>"); 322 } 323 324 public void enterMultiANewArrayInstruction(MultiANewArrayInstruction obj) { 325 _out.print(obj.getTypeIndex() + " " + obj.getDimensions() + " <" 326 + obj.getTypeName()); 327 String post = ""; 328 for (int i = 0; i < obj.getDimensions(); i++) 329 post += "[]"; 330 _out.print(post + ">"); 331 } 332 333 public void enterNewArrayInstruction(NewArrayInstruction obj) { 334 _out.print(obj.getTypeCode() + " <" + obj.getTypeName() + "[]>"); 335 } 336 337 public void enterPutFieldInstruction(PutFieldInstruction obj) { 338 _out.print(obj.getFieldIndex() + " <" + obj.getFieldTypeName() + " " 339 + obj.getFieldDeclarerName() + "." + obj.getFieldName() + ">"); 340 } 341 342 public void enterRetInstruction(RetInstruction obj) { 343 _out.print(obj.getLocal()); 344 } 345 346 public void enterStoreInstruction(StoreInstruction obj) { 347 _out.print("<" + obj.getLocal() + ">"); 348 } 349 350 public void enterTableSwitchInstruction(TableSwitchInstruction obj) { 351 _out.println(); 352 _prefix += " "; 353 354 println("low=" + obj.getLow()); 355 println("high=" + obj.getHigh()); 356 int[] offsets = obj.getOffsets(); 357 for (int i = 0; i < offsets.length; i++) 358 println("case=" + offsets[i]); 359 _out.print(_prefix + "default=" + obj.getDefaultOffset()); 360 _prefix = _prefix.substring(2); 361 } 362 363 public void enterWideInstruction(WideInstruction obj) { 364 int ins = obj.getInstruction(); 365 _out.print(ins + " <" + Constants.OPCODE_NAMES[ins] + ">"); 366 } 367 368 public void enterConstantPool(ConstantPool obj) { 369 openBlock("ConstantPool"); 370 } 371 372 public void exitConstantPool(ConstantPool obj) { 373 closeBlock(); 374 } 375 376 public void enterEntry(Entry obj) { 377 String name = obj.getClass().getName(); 378 openBlock(obj.getIndex() + ": " 379 + name.substring(name.lastIndexOf('.') + 1)); 380 } 381 382 public void exitEntry(Entry obj) { 383 closeBlock(); 384 } 385 386 public void enterClassEntry(ClassEntry obj) { 387 println("name=" + obj.getNameIndex()); 388 } 389 390 public void enterDoubleEntry(DoubleEntry obj) { 391 println("value=" + obj.getValue()); 392 } 393 394 public void enterFieldEntry(FieldEntry obj) { 395 println("class=" + obj.getClassIndex()); 396 println("nameAndType=" + obj.getNameAndTypeIndex()); 397 } 398 399 public void enterFloatEntry(FloatEntry obj) { 400 println("value=" + obj.getValue()); 401 } 402 403 public void enterIntEntry(IntEntry obj) { 404 println("value=" + obj.getValue()); 405 } 406 407 public void enterInterfaceMethodEntry(InterfaceMethodEntry obj) { 408 println("class=" + obj.getClassIndex()); 409 println("nameAndType=" + obj.getNameAndTypeIndex()); 410 } 411 412 public void enterLongEntry(LongEntry obj) { 413 println("value=" + obj.getValue()); 414 } 415 416 public void enterMethodEntry(MethodEntry obj) { 417 println("class=" + obj.getClassIndex()); 418 println("nameAndType=" + obj.getNameAndTypeIndex()); 419 } 420 421 public void enterNameAndTypeEntry(NameAndTypeEntry obj) { 422 println("name=" + obj.getNameIndex()); 423 println("descriptor=" + obj.getDescriptorIndex()); 424 } 425 426 public void enterStringEntry(StringEntry obj) { 427 println("index=" + obj.getStringIndex()); 428 } 429 430 public void enterUTF8Entry(UTF8Entry obj) { 431 println("value=" + obj.getValue()); 432 } 433 434 private void println(String ln) { 435 _out.print(_prefix); 436 _out.println(ln); 437 } 438 439 private void openBlock(String name) { 440 println(name + " {"); 441 _prefix += " "; 442 } 443 444 private void closeBlock() { 445 _prefix = _prefix.substring(2); 446 println("}"); 447 } 448 }