00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00115 jclass klass = JDWPCommandSet::getClassMap().value(refid);
00116
00117
00118 error = getSourceFileName(klass, bytecodeStr);
00119 if (error != JVMTI_ERROR_NONE) {
00120 *reply << bytecodeStr;
00121 cbk(reply);
00122 return;
00123 }
00124
00125
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
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
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
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
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
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
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
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
00336 bytecodeStr.append("}");
00337
00338 *reply << bytecodeStr;
00339 } else {
00340
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 }
00377 }
00378 }