1 /*
   2  * Copyright (c) 2003, 2018, 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  */
  26 
  27 #include <stdio.h>
  28 #include <string.h>
  29 #include "jvmti.h"
  30 #include "agent_common.h"
  31 #include "JVMTITools.h"
  32 
  33 extern "C" {
  34 
  35 
  36 #define PASSED 0
  37 #define STATUS_FAILED 2
  38 
  39 static jvmtiEnv *jvmti = NULL;
  40 static jvmtiCapabilities caps;
  41 static jint result = PASSED;
  42 static jboolean printdump = JNI_FALSE;
  43 
  44 #ifdef STATIC_BUILD
  45 JNIEXPORT jint JNICALL Agent_OnLoad_linetab004(JavaVM *jvm, char *options, void *reserved) {
  46     return Agent_Initialize(jvm, options, reserved);
  47 }
  48 JNIEXPORT jint JNICALL Agent_OnAttach_linetab004(JavaVM *jvm, char *options, void *reserved) {
  49     return Agent_Initialize(jvm, options, reserved);
  50 }
  51 JNIEXPORT jint JNI_OnLoad_linetab004(JavaVM *jvm, char *options, void *reserved) {
  52     return JNI_VERSION_1_8;
  53 }
  54 #endif
  55 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
  56     jvmtiError err;
  57     jint res;
  58 
  59     if (options != NULL && strcmp(options, "printdump") == 0) {
  60         printdump = JNI_TRUE;
  61     }
  62 
  63     res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
  64     if (res != JNI_OK || jvmti == NULL) {
  65         printf("Wrong result of a valid call to GetEnv!\n");
  66         return JNI_ERR;
  67     }
  68 
  69     err = jvmti->GetPotentialCapabilities(&caps);
  70     if (err != JVMTI_ERROR_NONE) {
  71         printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n",
  72                TranslateError(err), err);
  73         return JNI_ERR;
  74     }
  75 
  76     err = jvmti->AddCapabilities(&caps);
  77     if (err != JVMTI_ERROR_NONE) {
  78         printf("(AddCapabilities) unexpected error: %s (%d)\n",
  79                TranslateError(err), err);
  80         return JNI_ERR;
  81     }
  82 
  83     err = jvmti->GetCapabilities(&caps);
  84     if (err != JVMTI_ERROR_NONE) {
  85         printf("(GetCapabilities) unexpected error: %s (%d)\n",
  86                TranslateError(err), err);
  87         return JNI_ERR;
  88     }
  89 
  90     if (!caps.can_get_line_numbers) {
  91         printf("Warning: GetLineNumberTable is not implemented\n");
  92     }
  93 
  94     return JNI_OK;
  95 }
  96 
  97 void checkGetLineNumberTable(jmethodID mid, const char *methName,
  98         int abstract, jvmtiError exp) {
  99     jint entryCount = -1;
 100     jvmtiLineNumberEntry *table = NULL;
 101     jvmtiError err;
 102     int i;
 103 
 104     err = jvmti->GetLineNumberTable(mid, &entryCount, &table);
 105     if (printdump == JNI_TRUE) {
 106         printf("\n Method: %s%s\n", methName,
 107             (abstract==0) ? "" : " (abstract)");
 108     }
 109     if (err != exp) {
 110         result = STATUS_FAILED;
 111         printf(" Error expected: %s (%d),\n", TranslateError(exp), exp);
 112         printf(" actual: %s (%d)\n", TranslateError(err), err);
 113         if (err == JVMTI_ERROR_NONE) {
 114             printf("  %s%s line number table (%d entries):%s\n",
 115                    methName, (abstract==0) ? "" : " (abstract)",
 116                    entryCount, (entryCount==0 ? " empty" : ""));
 117             for (i = 0; i < entryCount; i++) {
 118                 printf("    start_location = 0x%x%08x,",
 119                        (jint)(table[i].start_location >> 32),
 120                        (jint)table[i].start_location);
 121                 printf(" line_number = %d\n", table[i].line_number);
 122             }
 123         }
 124     } else if (printdump == JNI_TRUE) {
 125         printf(" Error code: %s (%d),\n", TranslateError(err), err);
 126     }
 127 }
 128 
 129 JNIEXPORT jint JNICALL
 130 Java_nsk_jvmti_unit_GetLineNumberTable_linetab004_check(JNIEnv *env, jclass cls) {
 131     jmethodID mid;
 132     jclass abstr;
 133     jclass interf;
 134 
 135     if (jvmti == NULL) {
 136         printf("JVMTI client was not properly loaded!\n");
 137         return STATUS_FAILED;
 138     }
 139 
 140     if (!caps.can_get_line_numbers) {
 141         return result;
 142     }
 143 
 144     if (printdump == JNI_TRUE) {
 145         printf("\n Check methods of interface:\n");
 146     }
 147     interf = env->FindClass("nsk/jvmti/unit/GetLineNumberTable/Interface004");
 148     if (interf == NULL) {
 149         printf("Cannot get Interface class!\n");
 150         return STATUS_FAILED;
 151     }
 152 
 153     mid = env->GetMethodID(cls, "instanceMeth0", "()I");
 154     if (mid == NULL) {
 155         printf("Cannot get method ID!\n");
 156         return STATUS_FAILED;
 157     }
 158     checkGetLineNumberTable(mid, "instanceMeth0", 1,
 159         JVMTI_ERROR_ABSENT_INFORMATION);
 160 
 161     mid = env->GetMethodID(cls, "instanceMeth1", "()I");
 162     if (mid == NULL) {
 163         printf("Cannot get method ID!\n");
 164         return STATUS_FAILED;
 165     }
 166     checkGetLineNumberTable(mid, "instanceMeth1", 1,
 167         JVMTI_ERROR_ABSENT_INFORMATION);
 168 
 169     if (printdump == JNI_TRUE) {
 170         printf("\n Check methods of abstract class:\n");
 171     }
 172     abstr = env->GetSuperclass(cls);
 173     if (abstr == NULL) {
 174         printf("Cannot get super class!\n");
 175         return STATUS_FAILED;
 176     }
 177 
 178     mid = env->GetMethodID(abstr, "instanceMeth0", "()I");
 179     if (mid == NULL) {
 180         printf("Cannot get method ID!\n");
 181         return STATUS_FAILED;
 182     }
 183     checkGetLineNumberTable(mid, "instanceMeth0", 1,
 184         JVMTI_ERROR_ABSENT_INFORMATION);
 185 
 186     mid = env->GetMethodID(abstr, "instanceMeth1", "()I");
 187     if (mid == NULL) {
 188         printf("Cannot get method ID!\n");
 189         return STATUS_FAILED;
 190     }
 191     checkGetLineNumberTable(mid, "instanceMeth1", 0,
 192         JVMTI_ERROR_ABSENT_INFORMATION);
 193 
 194     if (printdump == JNI_TRUE) {
 195         printf("\n Check methods of regular class:\n");
 196     }
 197     mid = env->GetMethodID(cls, "instanceMeth0", "()I");
 198     if (mid == NULL) {
 199         printf("Cannot get method ID!\n");
 200         return STATUS_FAILED;
 201     }
 202     checkGetLineNumberTable(mid, "instanceMeth0", 0,
 203         JVMTI_ERROR_ABSENT_INFORMATION);
 204 
 205     mid = env->GetMethodID(cls, "instanceMeth1", "()I");
 206     if (mid == NULL) {
 207         printf("Cannot get method ID!\n");
 208         return STATUS_FAILED;
 209     }
 210     checkGetLineNumberTable(mid, "instanceMeth1", 0,
 211         JVMTI_ERROR_ABSENT_INFORMATION);
 212 
 213     mid = env->GetMethodID(cls, "instanceMeth2", "()I");
 214     if (mid == NULL) {
 215         printf("Cannot get method ID!\n");
 216         return STATUS_FAILED;
 217     }
 218     checkGetLineNumberTable(mid, "instanceMeth2", 0,
 219         JVMTI_ERROR_ABSENT_INFORMATION);
 220 
 221     if (printdump == JNI_TRUE) {
 222         printf("\n Check native methods of regular class:\n");
 223     }
 224     mid = env->GetMethodID(cls, "instanceNativeMeth", "()I");
 225     if (mid == NULL) {
 226         printf("Cannot get method ID!\n");
 227         return STATUS_FAILED;
 228     }
 229     checkGetLineNumberTable(mid, "instanceNativeMeth", 1,
 230         JVMTI_ERROR_NATIVE_METHOD);
 231 
 232     mid = env->GetStaticMethodID(cls, "staticNativeMeth", "()I");
 233     if (mid == NULL) {
 234         printf("Cannot get method ID!\n");
 235         return STATUS_FAILED;
 236     }
 237     checkGetLineNumberTable(mid, "staticNativeMeth", 1,
 238         JVMTI_ERROR_NATIVE_METHOD);
 239 
 240     if (printdump == JNI_TRUE) {
 241         printf(">>> ... done\n");
 242     }
 243 
 244     return result;
 245 }
 246 
 247 }