1 /*
   2  * Copyright (c) 2005, 2007, 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 # include "incls/_precompiled.incl"
  26 # include "incls/_attachListener.cpp.incl"
  27 
  28 volatile bool AttachListener::_initialized;
  29 
  30 // Implementation of "properties" command.
  31 //
  32 // Invokes sun.misc.VMSupport.serializePropertiesToByteArray to serialize
  33 // the system properties into a byte array.
  34 
  35 static klassOop load_and_initialize_klass(symbolHandle sh, TRAPS) {
  36   klassOop k = SystemDictionary::resolve_or_fail(sh, true, CHECK_NULL);
  37   instanceKlassHandle ik (THREAD, k);
  38   if (ik->should_be_initialized()) {
  39     ik->initialize(CHECK_NULL);
  40   }
  41   return ik();
  42 }
  43 
  44 static jint get_properties(AttachOperation* op, outputStream* out, symbolHandle serializePropertiesMethod) {
  45   Thread* THREAD = Thread::current();
  46   HandleMark hm;
  47 
  48   // load sun.misc.VMSupport
  49   symbolHandle klass = vmSymbolHandles::sun_misc_VMSupport();
  50   klassOop k = load_and_initialize_klass(klass, THREAD);
  51   if (HAS_PENDING_EXCEPTION) {
  52     java_lang_Throwable::print(PENDING_EXCEPTION, out);
  53     CLEAR_PENDING_EXCEPTION;
  54     return JNI_ERR;
  55   }
  56   instanceKlassHandle ik(THREAD, k);
  57 
  58   // invoke the serializePropertiesToByteArray method
  59   JavaValue result(T_OBJECT);
  60   JavaCallArguments args;
  61 
  62 
  63   symbolHandle signature = vmSymbolHandles::serializePropertiesToByteArray_signature();
  64   JavaCalls::call_static(&result,
  65                            ik,
  66                            serializePropertiesMethod,
  67                            signature,
  68                            &args,
  69                            THREAD);
  70   if (HAS_PENDING_EXCEPTION) {
  71     java_lang_Throwable::print(PENDING_EXCEPTION, out);
  72     CLEAR_PENDING_EXCEPTION;
  73     return JNI_ERR;
  74   }
  75 
  76   // The result should be a [B
  77   oop res = (oop)result.get_jobject();
  78   assert(res->is_typeArray(), "just checking");
  79   assert(typeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
  80 
  81   // copy the bytes to the output stream
  82   typeArrayOop ba = typeArrayOop(res);
  83   jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
  84   out->print_raw((const char*)addr, ba->length());
  85 
  86   return JNI_OK;
  87 }
  88 
  89 // Implementation of "properties" command.
  90 static jint get_system_properties(AttachOperation* op, outputStream* out) {
  91   return get_properties(op, out, vmSymbolHandles::serializePropertiesToByteArray_name());
  92 }
  93 
  94 // Implementation of "agent_properties" command.
  95 static jint get_agent_properties(AttachOperation* op, outputStream* out) {
  96   return get_properties(op, out, vmSymbolHandles::serializeAgentPropertiesToByteArray_name());
  97 }
  98 
  99 // Implementation of "datadump" command.
 100 //
 101 // Raises a SIGBREAK signal so that VM dump threads, does deadlock detection,
 102 // etc. In theory this command should only post a DataDumpRequest to any
 103 // JVMTI environment that has enabled this event. However it's useful to
 104 // trigger the SIGBREAK handler.
 105 
 106 static jint data_dump(AttachOperation* op, outputStream* out) {
 107   if (!ReduceSignalUsage) {
 108     AttachListener::pd_data_dump();
 109   } else {
 110     if (JvmtiExport::should_post_data_dump()) {
 111       JvmtiExport::post_data_dump();
 112     }
 113   }
 114   return JNI_OK;
 115 }
 116 
 117 // Implementation of "threaddump" command - essentially a remote ctrl-break
 118 //
 119 static jint thread_dump(AttachOperation* op, outputStream* out) {
 120   bool print_concurrent_locks = false;
 121   if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) {
 122     print_concurrent_locks = true;
 123   }
 124 
 125   // thread stacks
 126   VM_PrintThreads op1(out, print_concurrent_locks);
 127   VMThread::execute(&op1);
 128 
 129   // JNI global handles
 130   VM_PrintJNI op2(out);
 131   VMThread::execute(&op2);
 132 
 133   // Deadlock detection
 134   VM_FindDeadlocks op3(out);
 135   VMThread::execute(&op3);
 136 
 137   return JNI_OK;
 138 }
 139 
 140 #ifndef SERVICES_KERNEL   // Heap dumping not supported
 141 // Implementation of "dumpheap" command.
 142 //
 143 // Input arguments :-
 144 //   arg0: Name of the dump file
 145 //   arg1: "-live" or "-all"
 146 jint dump_heap(AttachOperation* op, outputStream* out) {
 147   const char* path = op->arg(0);
 148   if (path == NULL || path[0] == '\0') {
 149     out->print_cr("No dump file specified");
 150   } else {
 151     bool live_objects_only = true;   // default is true to retain the behavior before this change is made
 152     const char* arg1 = op->arg(1);
 153     if (arg1 != NULL && (strlen(arg1) > 0)) {
 154       if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) {
 155         out->print_cr("Invalid argument to dumpheap operation: %s", arg1);
 156         return JNI_ERR;
 157       }
 158       live_objects_only = strcmp(arg1, "-live") == 0;
 159     }
 160 
 161     // Request a full GC before heap dump if live_objects_only = true
 162     // This helps reduces the amount of unreachable objects in the dump
 163     // and makes it easier to browse.
 164     HeapDumper dumper(live_objects_only /* request GC */);
 165     int res = dumper.dump(op->arg(0));
 166     if (res == 0) {
 167       out->print_cr("Heap dump file created");
 168     } else {
 169       // heap dump failed
 170       ResourceMark rm;
 171       char* error = dumper.error_as_C_string();
 172       if (error == NULL) {
 173         out->print_cr("Dump failed - reason unknown");
 174       } else {
 175         out->print_cr("%s", error);
 176       }
 177     }
 178   }
 179   return JNI_OK;
 180 }
 181 #endif // SERVICES_KERNEL
 182 
 183 // Implementation of "inspectheap" command
 184 //
 185 // Input arguments :-
 186 //   arg0: "-live" or "-all"
 187 static jint heap_inspection(AttachOperation* op, outputStream* out) {
 188   bool live_objects_only = true;   // default is true to retain the behavior before this change is made
 189   const char* arg0 = op->arg(0);
 190   if (arg0 != NULL && (strlen(arg0) > 0)) {
 191     if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) {
 192       out->print_cr("Invalid argument to inspectheap operation: %s", arg0);
 193       return JNI_ERR;
 194     }
 195     live_objects_only = strcmp(arg0, "-live") == 0;
 196   }
 197   VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */);
 198   VMThread::execute(&heapop);
 199   return JNI_OK;
 200 }
 201 
 202 // set a boolean global flag using value from AttachOperation
 203 static jint set_bool_flag(const char* name, AttachOperation* op, outputStream* out) {
 204   bool value = true;
 205   const char* arg1;
 206   if ((arg1 = op->arg(1)) != NULL) {
 207     int tmp;
 208     int n = sscanf(arg1, "%d", &tmp);
 209     if (n != 1) {
 210       out->print_cr("flag value must be a boolean (1 or 0)");
 211       return JNI_ERR;
 212     }
 213     value = (tmp != 0);
 214   }
 215   bool res = CommandLineFlags::boolAtPut((char*)name, &value, ATTACH_ON_DEMAND);
 216   if (! res) {
 217     out->print_cr("setting flag %s failed", name);
 218   }
 219   return res? JNI_OK : JNI_ERR;
 220 }
 221 
 222 // set a intx global flag using value from AttachOperation
 223 static jint set_intx_flag(const char* name, AttachOperation* op, outputStream* out) {
 224   intx value;
 225   const char* arg1;
 226   if ((arg1 = op->arg(1)) != NULL) {
 227     int n = sscanf(arg1, INTX_FORMAT, &value);
 228     if (n != 1) {
 229       out->print_cr("flag value must be an integer");
 230       return JNI_ERR;
 231     }
 232   }
 233   bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
 234   if (! res) {
 235     out->print_cr("setting flag %s failed", name);
 236   }
 237 
 238   return res? JNI_OK : JNI_ERR;
 239 }
 240 
 241 // set a uintx global flag using value from AttachOperation
 242 static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) {
 243   uintx value;
 244   const char* arg1;
 245   if ((arg1 = op->arg(1)) != NULL) {
 246     int n = sscanf(arg1, UINTX_FORMAT, &value);
 247     if (n != 1) {
 248       out->print_cr("flag value must be an unsigned integer");
 249       return JNI_ERR;
 250     }
 251   }
 252   bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
 253   if (! res) {
 254     out->print_cr("setting flag %s failed", name);
 255   }
 256 
 257   return res? JNI_OK : JNI_ERR;
 258 }
 259 
 260 // set a uint64_t global flag using value from AttachOperation
 261 static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
 262   uint64_t value;
 263   const char* arg1;
 264   if ((arg1 = op->arg(1)) != NULL) {
 265     int n = sscanf(arg1, UINT64_FORMAT, &value);
 266     if (n != 1) {
 267       out->print_cr("flag value must be an unsigned 64-bit integer");
 268       return JNI_ERR;
 269     }
 270   }
 271   bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND);
 272   if (! res) {
 273     out->print_cr("setting flag %s failed", name);
 274   }
 275 
 276   return res? JNI_OK : JNI_ERR;
 277 }
 278 
 279 // set a string global flag using value from AttachOperation
 280 static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
 281   const char* value;
 282   if ((value = op->arg(1)) == NULL) {
 283     out->print_cr("flag value must be a string");
 284     return JNI_ERR;
 285   }
 286   bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND);
 287   if (res) {
 288     FREE_C_HEAP_ARRAY(char, value);
 289   } else {
 290     out->print_cr("setting flag %s failed", name);
 291   }
 292 
 293   return res? JNI_OK : JNI_ERR;
 294 }
 295 
 296 // Implementation of "setflag" command
 297 static jint set_flag(AttachOperation* op, outputStream* out) {
 298 
 299   const char* name = NULL;
 300   if ((name = op->arg(0)) == NULL) {
 301     out->print_cr("flag name is missing");
 302     return JNI_ERR;
 303   }
 304 
 305   Flag* f = Flag::find_flag((char*)name, strlen(name));
 306   if (f && f->is_external() && f->is_writeable()) {
 307     if (f->is_bool()) {
 308       return set_bool_flag(name, op, out);
 309     } else if (f->is_intx()) {
 310       return set_intx_flag(name, op, out);
 311     } else if (f->is_uintx()) {
 312       return set_uintx_flag(name, op, out);
 313     } else if (f->is_uint64_t()) {
 314       return set_uint64_t_flag(name, op, out);
 315     } else if (f->is_ccstr()) {
 316       return set_ccstr_flag(name, op, out);
 317     } else {
 318       ShouldNotReachHere();
 319       return JNI_ERR;
 320     }
 321   } else {
 322     return AttachListener::pd_set_flag(op, out);
 323   }
 324 }
 325 
 326 // Implementation of "printflag" command
 327 static jint print_flag(AttachOperation* op, outputStream* out) {
 328   const char* name = NULL;
 329   if ((name = op->arg(0)) == NULL) {
 330     out->print_cr("flag name is missing");
 331     return JNI_ERR;
 332   }
 333   Flag* f = Flag::find_flag((char*)name, strlen(name));
 334   if (f) {
 335     f->print_as_flag(out);
 336     out->print_cr("");
 337   } else {
 338     out->print_cr("no such flag '%s'", name);
 339   }
 340   return JNI_OK;
 341 }
 342 
 343 // Table to map operation names to functions.
 344 
 345 // names must be of length <= AttachOperation::name_length_max
 346 static AttachOperationFunctionInfo funcs[] = {
 347   { "agentProperties",  get_agent_properties },
 348   { "datadump",         data_dump },
 349 #ifndef SERVICES_KERNEL
 350   { "dumpheap",         dump_heap },
 351 #endif  // SERVICES_KERNEL
 352   { "load",             JvmtiExport::load_agent_library },
 353   { "properties",       get_system_properties },
 354   { "threaddump",       thread_dump },
 355   { "inspectheap",      heap_inspection },
 356   { "setflag",          set_flag },
 357   { "printflag",        print_flag },
 358   { NULL,               NULL }
 359 };
 360 
 361 
 362 
 363 // The Attach Listener threads services a queue. It dequeues an operation
 364 // from the queue, examines the operation name (command), and dispatches
 365 // to the corresponding function to perform the operation.
 366 
 367 static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
 368   os::set_priority(thread, NearMaxPriority);
 369 
 370   if (AttachListener::pd_init() != 0) {
 371     return;
 372   }
 373   AttachListener::set_initialized();
 374 
 375   for (;;) {
 376     AttachOperation* op = AttachListener::dequeue();
 377     if (op == NULL) {
 378       return;   // dequeue failed or shutdown
 379     }
 380 
 381     ResourceMark rm;
 382     bufferedStream st;
 383     jint res = JNI_OK;
 384 
 385     // handle special detachall operation
 386     if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
 387       AttachListener::detachall();
 388     } else {
 389       // find the function to dispatch too
 390       AttachOperationFunctionInfo* info = NULL;
 391       for (int i=0; funcs[i].name != NULL; i++) {
 392         const char* name = funcs[i].name;
 393         assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
 394         if (strcmp(op->name(), name) == 0) {
 395           info = &(funcs[i]);
 396           break;
 397         }
 398       }
 399 
 400       // check for platform dependent attach operation
 401       if (info == NULL) {
 402         info = AttachListener::pd_find_operation(op->name());
 403       }
 404 
 405       if (info != NULL) {
 406         // dispatch to the function that implements this operation
 407         res = (info->func)(op, &st);
 408       } else {
 409         st.print("Operation %s not recognized!", op->name());
 410         res = JNI_ERR;
 411       }
 412     }
 413 
 414     // operation complete - send result and output to client
 415     op->complete(res, &st);
 416   }
 417 }
 418 
 419 // Starts the Attach Listener thread
 420 void AttachListener::init() {
 421   EXCEPTION_MARK;
 422   klassOop k = SystemDictionary::resolve_or_fail(vmSymbolHandles::java_lang_Thread(), true, CHECK);
 423   instanceKlassHandle klass (THREAD, k);
 424   instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);
 425 
 426   const char thread_name[] = "Attach Listener";
 427   Handle string = java_lang_String::create_from_str(thread_name, CHECK);
 428 
 429   // Initialize thread_oop to put it into the system threadGroup
 430   Handle thread_group (THREAD, Universe::system_thread_group());
 431   JavaValue result(T_VOID);
 432   JavaCalls::call_special(&result, thread_oop,
 433                        klass,
 434                        vmSymbolHandles::object_initializer_name(),
 435                        vmSymbolHandles::threadgroup_string_void_signature(),
 436                        thread_group,
 437                        string,
 438                        CHECK);
 439 
 440   KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
 441   JavaCalls::call_special(&result,
 442                         thread_group,
 443                         group,
 444                         vmSymbolHandles::add_method_name(),
 445                         vmSymbolHandles::thread_void_signature(),
 446                         thread_oop,             // ARG 1
 447                         CHECK);
 448 
 449   { MutexLocker mu(Threads_lock);
 450     JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
 451 
 452     // Check that thread and osthread were created
 453     if (listener_thread == NULL || listener_thread->osthread() == NULL) {
 454       vm_exit_during_initialization("java.lang.OutOfMemoryError",
 455                                     "unable to create new native thread");
 456     }
 457 
 458     java_lang_Thread::set_thread(thread_oop(), listener_thread);
 459     java_lang_Thread::set_daemon(thread_oop());
 460 
 461     listener_thread->set_threadObj(thread_oop());
 462     Threads::add(listener_thread);
 463     Thread::start(listener_thread);
 464   }
 465 }
 466 
 467 // Performs clean-up tasks on platforms where we can detect that the last
 468 // client has detached
 469 void AttachListener::detachall() {
 470   // call the platform dependent clean-up
 471   pd_detachall();
 472 }