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