ij-16.png   inspectorJ -- JavaTM Profiler
sf project site browse source checkout source
SourceForge.net Logo



src/inspectorj/agent/commandset/bytecodecmdset.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   inspectorJ - java profiler                                            *
00003  *   Copyright (C) 2007 by James May
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00027 #include "bytecodecmdset.h"
00028 #include "virtualmachinecmdset.h"
00029 namespace inspectorj {
00030 namespace agent {
00031 namespace commandset {
00032 
00033 using namespace inspectorj::jdwp;
00034 
00035 const QString BytecodeCmdSet::failureMsg = "Bytecode generation failed:\n";
00039 BytecodeCmdSet::BytecodeCmdSet(JavaVM *vm, JNIEnv *env, jvmtiEnv *jvmti): ReferenceTypeCmdSet(vm, env, jvmti)
00040 {
00041     
00042 }
00043 
00047 BytecodeCmdSet::~BytecodeCmdSet()
00048 {
00049 }
00050 
00051 
00057 void BytecodeCmdSet::process(JDWPCommand* cmd, boost::function< void (JDWPReply*) > cbk)
00058 {
00059     int jdwpCmd = static_cast<int>(cmd->getCmd());
00060     switch (jdwpCmd) {
00061 
00062         case BC_TYPE_CMD_DISASSEMBLE : disassembleBytecodes(cmd, cbk); break;
00063 
00064         default : sendNotImplementedReply(cmd, cbk); break;
00065     }    
00066 }
00067 
00075 void addColumnSpacing(int prvHdrLen, int hdrSpace, int prvDataLen, QString &tableStr)
00076 {
00077     int desiredSpace = prvHdrLen + hdrSpace;
00078     if (prvDataLen < desiredSpace) {
00079         for (int i = prvDataLen; i < desiredSpace; i++) {
00080             tableStr.append(" ");
00081         }
00082     } else {
00083         tableStr.append(" ");
00084     }
00085 }
00086 
00098 void BytecodeCmdSet::disassembleBytecodes(JDWPCommand* cmd, boost::function< void (JDWPReply*) > cbk)
00099 {
00100     QString bytecodeStr;
00101     QString tab = "    ";
00102     QString tab2(tab);
00103     tab2.append(tab);
00104     QString errStr(failureMsg);
00105     JDWPReply *reply = getJDWPReply(cmd);
00106     qint64 refid;
00107     QString args;
00108     *cmd >> refid;
00109     *cmd >> args;
00110     jvmtiError error;
00111     
00112     if (JDWPCommandSet::getClassMap().contains(refid)) {
00113         
00114         // obtain the class
00115         jclass klass = JDWPCommandSet::getClassMap().value(refid);
00116         
00117         // get the source file name        
00118         error = getSourceFileName(klass, bytecodeStr);        
00119         if (error != JVMTI_ERROR_NONE) {
00120             *reply << bytecodeStr;
00121             cbk(reply);
00122             return;
00123         }
00124         
00125         // get modifiers
00126         QString modStr;
00127         error = getClassModifierString(klass, modStr);
00128         if (error != JVMTI_ERROR_NONE) {
00129             errStr.append("Error getting class modifiers.");
00130             *reply << errStr;
00131             cbk(reply);
00132             return;
00133         }    
00134         bytecodeStr.append(modStr).append(" ");
00135             
00136         // get reference type
00137         QString refType;
00138         error = getReferenceTypeString(klass, refType);
00139         if (error != JVMTI_ERROR_NONE) {
00140             errStr.append("Error getting class reference type.");
00141             *reply << errStr;
00142             cbk(reply);
00143             return;
00144         }
00145         bytecodeStr.append(refType).append(" ");
00146         
00147         // get class signature
00148         QString classSig;
00149         error = getClassSignatureString(klass, classSig);
00150         if (error != JVMTI_ERROR_NONE) {
00151             errStr.append("Error getting class signature.");
00152             *reply << errStr;
00153             cbk(reply);
00154             return;
00155         }
00156         classSig = inspectorj::toolset::ToolSetUtils::normalizeClassSignature(classSig);
00157         bytecodeStr.append(classSig).append(" ");  
00158          
00159         // get super class
00160         QString signature = "";
00161         jclass superClass = env->GetSuperclass(klass);
00162         if (superClass) {
00163             error = getClassSignatureString(superClass, signature);        
00164             if (error != JVMTI_ERROR_NONE) {
00165                 errStr.append("Error getting SuperClass signature.");
00166                 *reply << errStr;
00167                 cbk(reply);
00168                 return;
00169             }   
00170         }
00171         if (!signature.isEmpty()) {
00172             signature = inspectorj::toolset::ToolSetUtils::normalizeClassSignature(signature);
00173             bytecodeStr.append("extends ").append(signature).append(" ");  
00174         }  
00175                        
00176         // get implemented interfaces
00177         jint infCnt;
00178         jclass *interfaces;
00179         error = jvmti->GetImplementedInterfaces(klass, &infCnt, &interfaces);
00180 
00181         if (infCnt > 0) {
00182             if (refType == "interface") {
00183                 bytecodeStr.append("extends ");
00184             } else {
00185                 bytecodeStr.append("implements ");
00186             }
00187             for (int i = 0; i < infCnt; i++) {
00188                 error = getClassSignatureString(interfaces[i], signature);
00189                 if (error != JVMTI_ERROR_NONE) {
00190                     errStr.append("Error getting interface signature.");
00191                     *reply << errStr;
00192                     cbk(reply);
00193                     return;
00194                 }
00195                 signature =  inspectorj::toolset::ToolSetUtils::normalizeClassSignature(signature);
00196                 bytecodeStr.append(signature); 
00197                 if (i < infCnt - 1) {
00198                     bytecodeStr.append(", ");
00199                 }                                   
00200             }
00201             jvmti->Deallocate((unsigned char*)interfaces);
00202         }
00203         
00204         bytecodeStr.append(" {\n\n");
00205                        
00206         // get fields
00207         if (args.indexOf("f") >= 0) {
00208             jint fieldCnt = 0;
00209             jfieldID *fieldIds;
00210             error = jvmti->GetClassFields(klass, &fieldCnt, &fieldIds);
00211             if (error != JVMTI_ERROR_NONE) {
00212                 errStr.append("Error getting class fields.");
00213                 *reply << errStr;
00214                 cbk(reply);
00215                 return;
00216             }
00217             if (fieldCnt > 0) {
00218                 bytecodeStr.append(tab).append("// fields\n");
00219             }            
00220             for (int i = 0; i < fieldCnt; i++) {
00221                 QString fieldModStr;
00222                 QString fieldSig;
00223                 QString fieldName;
00224                 error = getFieldModifierString(klass, fieldIds[i], fieldModStr);
00225                 error = getFieldString(klass, fieldIds[i], fieldSig, fieldName);
00226                 bytecodeStr.append(tab);
00227                 if (!fieldModStr.isEmpty()) {
00228                     bytecodeStr.append(fieldModStr).append(" ");
00229                 }
00230                 fieldSig = inspectorj::toolset::ToolSetUtils::normalizeClassSignature(fieldSig);
00231                 bytecodeStr.append(fieldSig).append(" ").append(fieldName).append(";\n"); 
00232             }
00233             error = jvmti->Deallocate((unsigned char*)fieldIds);
00234             if (fieldCnt > 0) {
00235                 bytecodeStr.append("\n");
00236             }
00237         }
00238         
00239         // get method signatures
00240         jint methodCnt;
00241         jmethodID *methodIds;
00242         error = jvmti->GetClassMethods(klass, &methodCnt, &methodIds);
00243         if (error != JVMTI_ERROR_NONE) {
00244             errStr.append("Error getting class methods.");
00245             *reply << errStr;
00246             cbk(reply);
00247             return;
00248         }
00249         if (methodCnt > 0) {
00250             bytecodeStr.append(tab).append("// methods\n");
00251         }            
00252         for (int i = 0; i < methodCnt; i++) {
00253             QString methodModStr;
00254             QString jniSig;
00255             QString methodSig;
00256             QString methodName;
00257             error = getMethodModifierString(methodIds[i], methodModStr);
00258             error = getMethodSignatureString(methodIds[i], jniSig, methodName);
00259             bytecodeStr.append(tab);
00260             if (!methodModStr.isEmpty()) {
00261                 bytecodeStr.append(methodModStr).append(" ");
00262             }
00263             methodSig = jniSig;
00264             inspectorj::toolset::ToolSetUtils::normalizeMethodSignature(
00265                     methodSig, methodName, classSig);
00266             bytecodeStr.append(methodSig).append(";\n");
00267             if (args.indexOf("i") >= 0) {
00268                 bytecodeStr.append(tab).append(tab).append("Signature: ");
00269                 bytecodeStr.append(jniSig).append("\n");
00270             }
00271             // print line number table and local variable table
00272             if (args.indexOf("l") >= 0) {
00273                 
00274                 bytecodeStr.append(tab2).append("LineNumberTable:\n");
00275                 jint entryCnt;
00276                 jvmtiLineNumberEntry *table;
00277                 QString lineNumStr;
00278                 QString startLoc;
00279                 error = jvmti->GetLineNumberTable(methodIds[i], &entryCnt, &table);
00280                 for (int j = 0; j < entryCnt; j++) {
00281                     bytecodeStr.append(tab2).append(" line ");
00282                     bytecodeStr.append(lineNumStr.setNum((jint)table[j].line_number));
00283                     bytecodeStr.append(": ");
00284                     bytecodeStr.append(startLoc.setNum((jlong)table[j].start_location));
00285                     bytecodeStr.append("\n");
00286                 }                
00287                 if (!error) jvmti->Deallocate((unsigned char*)table);
00288                 bytecodeStr.append("\n");      
00289                 
00290                 entryCnt = 0;
00291                 QString num;
00292                 jvmtiLocalVariableEntry *lvTable;
00293                 error = jvmti->GetLocalVariableTable(methodIds[i], &entryCnt, &lvTable);
00294                 if (entryCnt > 0) { 
00295                     QString lvtStart = "Start";
00296                     QString lvtLength = "Length";
00297                     QString lvtSlot = "Slot";
00298                     QString lvtName = "Name";
00299                     QString lvtSig = "Signature";      
00300                     bytecodeStr.append(tab2).append("LocalVariableTable:\n");
00301                     bytecodeStr.append(tab2).append(" ").append(lvtStart);
00302                     bytecodeStr.append(tab).append(lvtLength);
00303                     bytecodeStr.append(tab).append(lvtSlot);
00304                     bytecodeStr.append(tab).append(lvtName);
00305                     bytecodeStr.append(tab2).append(lvtSig).append("\n");
00306                     for (int k = 0; k < entryCnt; k++) {
00307                         bytecodeStr.append(tab2).append(" ");                       
00308                         bytecodeStr.append(num.setNum((qint64)(lvTable[k].start_location)));
00309                         addColumnSpacing(lvtStart.length(), tab.length(), num.length(), bytecodeStr);
00310                         
00311                         bytecodeStr.append(num.setNum((jint)(lvTable[k].length)));
00312                         addColumnSpacing(lvtLength.length(), tab.length(), num.length(), bytecodeStr);
00313                         
00314                         bytecodeStr.append(num.setNum((jint)(lvTable[k].slot)));
00315                         addColumnSpacing(lvtSlot.length(), tab.length(), num.length(), bytecodeStr);
00316                         
00317                         QString lvt_name(lvTable[k].name);
00318                         bytecodeStr.append(lvt_name);
00319                         addColumnSpacing(lvtName.length(), tab2.length(), lvt_name.length(), bytecodeStr);
00320                         
00321                         bytecodeStr.append(lvTable[k].signature).append("\n");
00322                         
00323                         jvmti->Deallocate((unsigned char*)lvTable[k].name);
00324                         jvmti->Deallocate((unsigned char*)lvTable[k].signature);
00325                         jvmti->Deallocate((unsigned char*)lvTable[k].generic_signature);
00326                     }
00327                     bytecodeStr.append("\n");
00328                 }
00329                 if (!error) jvmti->Deallocate((unsigned char*)lvTable);    
00330             }
00331         }
00332         error = jvmti->Deallocate((unsigned char*)methodIds);
00333         
00334         
00335         // close the class/interface brace
00336         bytecodeStr.append("}");
00337         // store the bytecode str in the packet's payload
00338         *reply << bytecodeStr;
00339     } else {
00340         // no class found with the provided ReferenceTypeId
00341         reply->setErrorCode((short)JVMTI_ERROR_INVALID_CLASS);
00342     }
00343     cbk(reply);
00344 }
00345 
00352 jvmtiError BytecodeCmdSet::getSourceFileName(jclass &klass, QString &bytecodeStr)
00353 {
00354         char* srcFileStr;        
00355         jvmtiError error = jvmti->GetSourceFileName(klass, &srcFileStr);        
00356         check_jvmti_error(jvmti, error, "Bytecode Disassembly => Error getting source file.\n");
00357         
00358         if (error == JVMTI_ERROR_NONE)
00359         {
00360             bytecodeStr.append("Compiled from: \"").append(srcFileStr).append("\"\n");
00361             jvmti->Deallocate((unsigned char*)srcFileStr);
00362         } 
00363         else if (error == JVMTI_ERROR_ABSENT_INFORMATION) {
00364             bytecodeStr.append("*-- Class information does not include a source file name. --*");
00365         }
00366         else if (error == JVMTI_ERROR_INVALID_CLASS) {
00367             bytecodeStr.append("Bytecode generation failed:\n*-- The class or reference ID is invalid. --*");
00368         }
00369         
00370         return error;
00371 }
00372 
00373 
00374 
00375 
00376 } // end namespace commandset
00377 } // end namespace agent
00378 } // end namespace inspectorj

Generated on Sun Aug 19 17:07:53 2007 for inspectorJ by  doxygen 1.5.1