blob: e65ef44a2832b5716d993cdd3ab47e3f22a1813f [file] [log] [blame]
//===-- classdump.cpp - classdump utility -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is a sample class reader driver. It is used to drive class
// reader tests.
//
//===----------------------------------------------------------------------===//
#include <llvm/Java/ClassFile.h>
#include <llvm/Java/BytecodeParser.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/System/Signals.h>
#include <cstddef>
#include <iostream>
using namespace llvm;
namespace {
enum DumpType { code, constantPool };
cl::opt<std::string>
InputClass(cl::Positional, cl::desc("<input class>"));
cl::opt<DumpType>
DumpMode(
"dumptype",
cl::desc("Dump type: (default = code)"),
cl::Prefix,
cl::values(
clEnumVal(code, "code"),
clEnumVal(constantPool, "constant pool"),
clEnumValEnd),
cl::init(code));
using namespace llvm::Java;
class ClassDump : public BytecodeParser<ClassDump> {
const ClassFile* CF;
std::ostream& Out;
public:
ClassDump(const ClassFile* cf, std::ostream& out)
: CF(cf), Out(out) {
if (CF->isPublic())
Out << "public ";
if (CF->isFinal())
Out << "final ";
Out << "class " << CF->getThisClass()->getName()->str() << ' ';
if (ConstantClass* super = CF->getSuperClass())
Out << "extends " << super->getName()->str() << ' ';
if (CF->getNumInterfaces()) {
Out << "implements " << CF->getInterface(0)->getName()->str();
for (unsigned i = 1, e = CF->getNumInterfaces(); i != e; ++i)
Out << ", " << CF->getInterface(i)->getName()->str();
Out << ' ';
}
Out << "{\n";
const Fields& fields = CF->getFields();
// Dump static fields.
for (unsigned i = 0, e = fields.size(); i != e; ++i)
if (fields[i]->isStatic())
dumpField(fields[i]);
// Dump instance fields.
for (unsigned i = 0, e = fields.size(); i != e; ++i)
if (!fields[i]->isStatic())
dumpField(fields[i]);
const Methods& methods = CF->getMethods();
for (unsigned i = 0, e = methods.size(); i != e; ++i)
dumpMethod(methods[i]);
Out << "\n}\n";
}
void dumpField(const Field* F) {
Out << '\n';
if (F->isPublic())
Out << "public ";
else if (F->isProtected())
Out << "protected ";
else if (F->isPrivate())
Out << "private ";
if (F->isStatic())
Out << "static ";
if (F->isFinal())
Out << "final ";
if (F->isTransient())
Out << "transient ";
Out << getPrettyString(F->getDescriptor()->str()) << ' '
<< F->getName()->str() << ";\n";
}
void dumpMethod(const Method* M) {
Out << '\n';
if (M->isPublic())
Out << "public ";
else if (M->isProtected())
Out << "protected ";
else if (M->isPrivate())
Out << "private ";
if (M->isStatic())
Out << "static ";
if (M->isAbstract())
Out << "abstract ";
if (M->isFinal())
Out << "final ";
if (M->isSynchronized())
Out << "synchronized ";
std::string Signature = getPrettyString(M->getDescriptor()->str());
Signature.insert(Signature.find('('), M->getName()->str());
Out << Signature << ";\n";
if (CodeAttribute* CodeAttr = M->getCodeAttribute()) {
Out << "\tCode:";
parse(CodeAttr->getCode(), 0, CodeAttr->getCodeSize());
Out << '\n';
}
}
std::string getPrettyString(const std::string& Desc) {
unsigned I = 0;
std::string prettyString = getPrettyStringHelper(Desc, I);
for (unsigned i = 0, e = prettyString.size(); i != e; ++i)
if (prettyString[i] == '/')
prettyString[i] = '.';
return prettyString;
}
std::string getPrettyStringHelper(const std::string& Desc, unsigned& I) {
if (Desc.size() == I)
return "";
switch (Desc[I++]) {
case 'B': return "byte";
case 'C': return "char";
case 'D': return "double";
case 'F': return "float";
case 'I': return "int";
case 'J': return "long";
case 'S': return "short";
case 'Z': return "boolean";
case 'V': return "void";
case 'L': {
unsigned E = Desc.find(';', I);
std::string ClassName = Desc.substr(I, E - I);
I = E + 1;
return ClassName;
}
case '[': {
std::string ArrayPart;
ArrayPart += "[]";
while (Desc[I] == '[') {
ArrayPart += "[]";
++I;
}
return getPrettyStringHelper(Desc, I) + ArrayPart;
}
case '(': {
std::string Params;
while (Desc[I] != ')') {
if (Desc[I-1] != '(')
Params += ',';
Params += getPrettyStringHelper(Desc, I);
}
return getPrettyStringHelper(Desc, ++I) + " (" + Params + ')';
}
}
return "";
}
/// @brief called before every bytecode
void pre_inst(unsigned bcI) { Out << "\n\t " << bcI << ":\t"; }
/// @brief called on ACONST_NULL
void do_aconst_null() { Out << "aconst_null"; }
/// @brief called on ICONST_<n>, SIPUSH and BIPUSH
void do_iconst(int value) {
if (value == -1)
Out << "iconst_m1";
else if (value >=0 && value <= 5)
Out << "iconst_" << value;
else if (value >= -128 && value <= 127)
Out << "bipush " << value;
else
Out << "sipush " << value;
}
/// @brief called on LCONST_<n>
void do_lconst(long long value) {
if (value == 0 || value == 1)
Out << "lconst_" << value;
else
Out << "lconst " << value;
}
/// @brief called on FCONST_<n>
void do_fconst(float value) {
if (value >= 0 && value <= 2)
Out << "fconst_" << value;
else
Out << "fconst " << value;
}
/// @brief called on DCONST_<n>
void do_dconst(double value) {
if (value == 0 || value == 1)
Out << "dconst_" << value;
else
Out << "dconst " << value;
}
/// @brief called on LDC and LDC_W
void do_ldc(unsigned index) {
if (index <= 255)
Out << "ldc";
else
Out << "ldc_w";
Out << "\t#" << index << "; //" << *CF->getConstant(index);
}
/// @brief called on LDC2_W
void do_ldc2(unsigned index) {
Out << "ldc2_w \t#" << index << "; //" << *CF->getConstant(index);
}
/// @brief called on ILOAD and ILOAD_<n>
void do_iload(unsigned index) {
if (index <= 3)
Out << "iload_" << index;
else
Out << "iload " << index;
}
/// @brief called on LLOAD and LLOAD_<n>
void do_lload(unsigned index) {
if (index <= 3)
Out << "lload_" << index;
else
Out << "lload " << index;
}
/// @brief called on FLOAD and FLOAD_<n>
void do_fload(unsigned index) {
if (index <= 3)
Out << "fload_" << index;
else
Out << "fload " << index;
}
/// @brief called on DLOAD and DLOAD_<n>
void do_dload(unsigned index) {
if (index <= 3)
Out << "dload_" << index;
else
Out << "dload " << index;
}
/// @brief called on ALOAD and ALOAD_<n>
void do_aload(unsigned index) {
if (index <= 3)
Out << "aload_" << index;
else
Out << "aload " << index;
}
/// @brief called on IALOAD
void do_iaload() { Out << "iaload"; }
/// @brief called on LALOAD
void do_laload() { Out << "laload"; }
/// @brief called on FALOAD
void do_faload() { Out << "faload"; }
/// @brief called on DALOAD
void do_daload() { Out << "daload"; }
/// @brief called on AALOAD
void do_aaload() { Out << "aaload"; }
/// @brief called on BALOAD
void do_baload() { Out << "baload"; }
/// @brief called on CALOAD
void do_caload() { Out << "caload"; }
/// @brief called on SALOAD
void do_saload() { Out << "saload"; }
/// @brief called on ISTORE and ISTORE_<n>
void do_istore(unsigned index) {
if (index <= 3)
Out << "istore_" << index;
else
Out << "istore " << index;
}
/// @brief called on LSTORE and LSTORE_<n>
void do_lstore(unsigned index) {
if (index <= 3)
Out << "lstore_" << index;
else
Out << "lstore " << index;
}
/// @brief called on FSTORE and FSTORE_<n>
void do_fstore(unsigned index) {
if (index <= 3)
Out << "fstore_" << index;
else
Out << "fstore " << index;
}
/// @brief called on DSTORE and DSTORE_<n>
void do_dstore(unsigned index) {
if (index <= 3)
Out << "dstore_" << index;
else
Out << "dstore " << index;
}
/// @brief called on ASTORE and ASTORE_<n>
void do_astore(unsigned index) {
if (index <= 3)
Out << "astore_" << index;
else
Out << "astore " << index;
}
/// @brief called on IASTORE
void do_iastore() { Out << "iastore"; }
/// @brief called on LASTORE
void do_lastore() { Out << "lastore"; }
/// @brief called on FASTORE
void do_fastore() { Out << "fastore"; }
/// @brief called on DASTORE
void do_dastore() { Out << "dastore"; }
/// @brief called on AASTORE
void do_aastore() { Out << "aastore"; }
/// @brief called on BASTORE
void do_bastore() { Out << "bastore"; }
/// @brief called on CASTORE
void do_castore() { Out << "castore"; }
/// @brief called on SASTORE
void do_sastore() { Out << "sastore"; }
/// @brief called on POP
void do_pop() { Out << "pop"; }
/// @brief called on POP2
void do_pop2() { Out << "pop2"; }
/// @brief called on DUP
void do_dup() { Out << "dup"; }
/// @brief called on DUP_X1
void do_dup_x1() { Out << "dup_x1"; }
/// @brief called on DUP_X2
void do_dup_x2() { Out << "dup_x2"; }
/// @brief called on DUP2
void do_dup2() { Out << "dup2"; }
/// @brief called on DUP2_X1
void do_dup2_x1() { Out << "dup2_x1"; }
/// @brief called on DUP2_X2
void do_dup2_x2() { Out << "dup2_x2"; }
/// @brief called on SWAP
void do_swap() { Out << "swap"; }
/// @brief called on IADD
void do_iadd() { Out << "iadd"; }
/// @brief called on LADD
void do_ladd() { Out << "ladd"; }
/// @brief called on FADD
void do_fadd() { Out << "fadd"; }
/// @brief called on DADD
void do_dadd() { Out << "dadd"; }
/// @brief called on ISUB
void do_isub() { Out << "isub"; }
/// @brief called on LSUB
void do_lsub() { Out << "lsub"; }
/// @brief called on FSUB
void do_fsub() { Out << "fsub"; }
/// @brief called on DSUB
void do_dsub() { Out << "dsub"; }
/// @brief called on IMUL
void do_imul() { Out << "imul"; }
/// @brief called on LMUL
void do_lmul() { Out << "lmul"; }
/// @brief called on FMUL
void do_fmul() { Out << "fmul"; }
/// @brief called on DMUL
void do_dmul() { Out << "dmul"; }
/// @brief called on IDIV
void do_idiv() { Out << "idiv"; }
/// @brief called on LDIV
void do_ldiv() { Out << "ldiv"; }
/// @brief called on FDIV
void do_fdiv() { Out << "fdiv"; }
/// @brief called on DDIV
void do_ddiv() { Out << "ddiv"; }
/// @brief called on IREM
void do_irem() { Out << "irem"; }
/// @brief called on LREM
void do_lrem() { Out << "lrem"; }
/// @brief called on FREM
void do_frem() { Out << "frem"; }
/// @brief called on DREM
void do_drem() { Out << "drem"; }
/// @brief called on INEG
void do_ineg() { Out << "ineg"; }
/// @brief called on LNEG
void do_lneg() { Out << "lneg"; }
/// @brief called on FNEG
void do_fneg() { Out << "fneg"; }
/// @brief called on DNEG
void do_dneg() { Out << "dneg"; }
/// @brief called on ISHL
void do_ishl() { Out << "ishl"; }
/// @brief called on LSHL
void do_lshl() { Out << "lshl"; }
/// @brief called on ISHR
void do_ishr() { Out << "ishr"; }
/// @brief called on LSHR
void do_lshr() { Out << "lshr"; }
/// @brief called on IUSHR
void do_iushr() { Out << "iushr"; }
/// @brief called on LUSHR
void do_lushr() { Out << "lushr"; }
/// @brief called on IAND
void do_iand() { Out << "iand"; }
/// @brief called on LAND
void do_land() { Out << "land"; }
/// @brief called on IOR
void do_ior() { Out << "ior"; }
/// @brief called on LOR
void do_lor() { Out << "lor"; }
/// @brief called on IXOR
void do_ixor() { Out << "ixor"; }
/// @brief called on LXOR
void do_lxor() { Out << "lxor"; }
/// @brief called on IINC
void do_iinc(unsigned index, int amount) {
Out << "iinc " << index << ", " << amount;
}
/// @brief called on I2L
void do_i2l() { Out << "i2l"; }
/// @brief called on I2F
void do_i2f() { Out << "i2f"; }
/// @brief called on I2D
void do_i2d() { Out << "i2d"; }
/// @brief called on L2I
void do_l2i() { Out << "l2i"; }
/// @brief called on L2F
void do_l2f() { Out << "l2f"; }
/// @brief called on L2D
void do_l2d() { Out << "l2d"; }
/// @brief called on F2I
void do_f2i() { Out << "f2i"; }
/// @brief called on F2L
void do_f2l() { Out << "f2l"; }
/// @brief called on F2D
void do_f2d() { Out << "f2d"; }
/// @brief called on D2I
void do_d2i() { Out << "d2i"; }
/// @brief called on D2L
void do_d2l() { Out << "d2l"; }
/// @brief called on D2F
void do_d2f() { Out << "d2f"; }
/// @brief called on I2B
void do_i2b() { Out << "i2b"; }
/// @brief called on I2C
void do_i2c() { Out << "i2c"; }
/// @brief called on I2S
void do_i2s() { Out << "i2s"; }
/// @brief called on LCMP
void do_lcmp() { Out << "lcmp"; }
/// @brief called on FCMPL
void do_fcmpl() { Out << "fcmpl"; }
/// @brief called on DCMPL
void do_dcmpl() { Out << "dcmpl"; }
/// @brief called on FCMPG
void do_fcmpg() { Out << "fcmpg"; }
/// @brief called on DCMPG
void do_dcmpg() { Out << "dcmpg"; }
/// @brief called on IFEQ
void do_ifeq(unsigned t, unsigned f) { Out << "ifeq " << t; }
/// @brief called on IFNE
void do_ifne(unsigned t, unsigned f) { Out << "ifne " << t; }
/// @brief called on IFLT
void do_iflt(unsigned t, unsigned f) { Out << "iflt " << t; }
/// @brief called on IFGE
void do_ifge(unsigned t, unsigned f) { Out << "ifge " << t; }
/// @brief called on IFGT
void do_ifgt(unsigned t, unsigned f) { Out << "ifgt " << t; }
/// @brief called on IFLE
void do_ifle(unsigned t, unsigned f) { Out << "ifle " << t; }
/// @brief called on IF_ICMPEQ
void do_if_icmpeq(unsigned t, unsigned f) { Out << "if_icmpeq " << t; }
/// @brief called on IF_ICMPNE
void do_if_icmpne(unsigned t, unsigned f) { Out << "if_icmpne " << t; }
/// @brief called on IF_ICMPLT
void do_if_icmplt(unsigned t, unsigned f) { Out << "if_icmplt " << t; }
/// @brief called on IF_ICMPGE
void do_if_icmpge(unsigned t, unsigned f) { Out << "if_icmpge " << t; }
/// @brief called on IF_ICMPGT
void do_if_icmpgt(unsigned t, unsigned f) { Out << "if_icmpgt " << t; }
/// @brief called on IF_ICMPLE
void do_if_icmple(unsigned t, unsigned f) { Out << "if_icmple " << t; }
/// @brief called on IF_ACMPEQ
void do_if_acmpeq(unsigned t, unsigned f) { Out << "if_acmpeq " << t; }
/// @brief called on IF_ACMPNE
void do_if_acmpne(unsigned t, unsigned f) { Out << "if_acmpne " << t; }
/// @brief called on GOTO and GOTO_W
void do_goto(unsigned target) { Out << "goto " << target; }
/// @brief called on JSR and JSR_W
void do_jsr(unsigned target, unsigned retAddress) { abort(); }
/// @brief called on RET
void do_ret(unsigned index) { abort(); }
/// @brief called on TABLESWITCH
void do_tableswitch(unsigned defTarget, const SwitchCases& sw) {
Out << "tableswitch{ //" << sw.front().first << " to " << sw.back().first;
for (unsigned i = 0, e = sw.size(); i != e; ++i)
Out << "\n\t\t\t" << sw[i].first << ": " << sw[i].second << ';';
Out << ";\n\t\t\tdefault: " << defTarget << " }";
}
/// @brief called on LOOKUPSWITCH
void do_lookupswitch(unsigned defTarget, const SwitchCases& sw) { abort(); }
/// @brief called on IRETURN
void do_ireturn() { Out << "ireturn"; }
/// @brief called on LRETURN
void do_lreturn() { Out << "lreturn"; }
/// @brief called on FRETURN
void do_freturn() { Out << "freturn"; }
/// @brief called on DRETURN
void do_dreturn() { Out << "dreturn"; }
/// @brief called on ARETURN
void do_areturn() { Out << "areturn"; }
/// @brief called on RETURN
void do_return() { Out << "return"; }
/// @brief called on GETSTATIC
void do_getstatic(unsigned index) {
Out << "getstatic #" << index << "; //Field ";
printMemberRef(index);
}
/// @brief called on PUTSTATIC
void do_putstatic(unsigned index) {
Out << "putstatic #" << index << "; //Field ";
printMemberRef(index);
}
/// @brief called on GETFIELD
void do_getfield(unsigned index) {
Out << "getfield #" << index << "; //Field ";
printMemberRef(index);
}
/// @brief called on PUTFIELD
void do_putfield(unsigned index) {
Out << "putfield #" << index << "; //Field ";
printMemberRef(index);
}
/// @brief called on INVOKEVIRTUAL
void do_invokevirtual(unsigned index) {
Out << "invokevirtual #" << index << "; //Method ";
printMemberRef(index);
}
/// @brief called on INVOKESPECIAL
void do_invokespecial(unsigned index) {
Out << "invokespecial #" << index << "; //Method ";
printMemberRef(index);
}
/// @brief called on INVOKESTATIC
void do_invokestatic(unsigned index) {
Out << "invokestatic #" << index << "; //Method ";
printMemberRef(index);
}
/// @brief called on INVOKEINTERFACE
void do_invokeinterface(unsigned index) {
Out << "invokeinterface #" << index << "; //InterfaceMethod ";
printMemberRef(index);
}
/// @brief called on NEW
void do_new(unsigned index) {
Out << "new #" << index << "; //class ";
printClassRef(index);
}
/// @brief called on NEWARRAY
void do_newarray(JType type) {
Out << "newarray ";
switch (type) {
case BOOLEAN: Out << "boolean"; break;
case CHAR: Out << "char"; break;
case FLOAT: Out << "float"; break;
case DOUBLE: Out << "double"; break;
case BYTE: Out << "byte"; break;
case SHORT: Out << "short"; break;
case INT: Out << "int"; break;
case LONG: Out << "long"; break;
default: assert(0 && "Unknown type for newarray!");
}
}
/// @brief called on ANEWARRAY
void do_anewarray(unsigned index) {
Out << "anewarray #" << index << "; //class ";
printClassRef(index);
}
/// @brief called on ARRAYLENGTH
void do_arraylength() { Out << "arraylength"; }
/// @brief called on ATHROW
void do_athrow() { Out << "athrow"; }
/// @brief called on CHECKCAST
void do_checkcast(unsigned index) {
Out << "checkcast #" << index
<< "; //class ";
printClassRef(index);
}
/// @brief called on INSTANCEOF
void do_instanceof(unsigned index) {
Out << "instanceof #" << index
<< "; //class ";
printClassRef(index);
}
/// @brief called on MONITORENTER
void do_monitorenter() { Out << "monitorenter"; }
/// @brief called on MONITOREXIT
void do_monitorexit() { Out << "monitorexit"; }
/// @brief called on MULTIANEWARRAY
void do_multianewarray(unsigned index, unsigned dims) { }
/// @brief called on IFNULL
void do_ifnull(unsigned t, unsigned f) { Out << "ifnull " << t; }
/// @brief called on IFNONNULL
void do_ifnonnull(unsigned t, unsigned f) { Out << "ifnonnull " << t; }
void printMemberRef(unsigned index) {
ConstantMemberRef* Ref = CF->getConstantMemberRef(index);
ConstantClass* Class = Ref->getClass();
if (Class != CF->getThisClass())
Out << Class->getName()->str() << '.';
Out << Ref->getNameAndType()->getName()->str()
<< ':'
<< Ref->getNameAndType()->getDescriptor()->str();
}
void printClassRef(unsigned index) {
const std::string& FQCN = CF->getConstantClass(index)->getName()->str();
Out << FQCN.substr(FQCN.rfind('/')+1);
}
};
}
int main(int argc, char* argv[])
{
sys::PrintStackTraceOnErrorSignal();
cl::ParseCommandLineOptions(argc, argv,
"class dump utility");
try {
const Java::ClassFile* cf(Java::ClassFile::get(InputClass));
switch (DumpMode) {
default:
std::cerr << "no dump type selected";
abort();
case code: {
ClassDump(cf, std::cout);
break;
}
case constantPool: {
for (unsigned i = 0, e = cf->getNumConstants(); i != e; ++i) {
Constant* c = cf->getConstant(i);
std::cout.width(6);
std::cout << i << ": ";
std::cout.width(0);
if (c)
std::cout << *cf->getConstant(i);
else
std::cout << "empty";
std::cout << '\n';
}
break;
}
}
}
catch (std::exception& e) {
std::cerr << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}