1 /*
   2  * Copyright (c) 2015, 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 #include "precompiled.hpp"
  26 #include "classfile/javaClasses.hpp"
  27 #include "memory/allocation.inline.hpp"
  28 #include "runtime/arguments.hpp"
  29 #include "runtime/flags/jvmFlag.hpp"
  30 #include "runtime/flags/jvmFlagRangeList.hpp"
  31 #include "runtime/java.hpp"
  32 #include "runtime/jniHandles.hpp"
  33 #include "services/writeableFlags.hpp"
  34 
  35 #define TEMP_BUF_SIZE 80
  36 
  37 static void buffer_concat(char* buffer, const char* src) {
  38   strncat(buffer, src, TEMP_BUF_SIZE - 1 - strlen(buffer));
  39 }
  40 
  41 static void print_flag_error_message_bounds(const JVMFlag* flag, char* buffer) {
  42   JVMFlagRange* range = JVMFlagRangeList::find(flag);
  43   if (range != NULL) {
  44     buffer_concat(buffer, "must have value in range ");
  45 
  46     stringStream stream;
  47     range->print(&stream);
  48     const char* range_string = stream.as_string();
  49     size_t j = strlen(buffer);
  50     for (size_t i=0; j<TEMP_BUF_SIZE-1; i++) {
  51       if (range_string[i] == '\0') {
  52         break;
  53       } else if (range_string[i] != ' ') {
  54         buffer[j] = range_string[i];
  55         j++;
  56       }
  57     }
  58     buffer[j] = '\0';
  59   }
  60 }
  61 
  62 static void print_flag_error_message_if_needed(JVMFlag::Error error, const JVMFlag* flag, FormatBuffer<80>& err_msg) {
  63   if (error == JVMFlag::SUCCESS) {
  64     return;
  65   }
  66 
  67   const char* name = flag->_name;
  68   char buffer[TEMP_BUF_SIZE] = {'\0'};
  69   if ((error != JVMFlag::MISSING_NAME) && (name != NULL)) {
  70     buffer_concat(buffer, name);
  71     buffer_concat(buffer, " error: ");
  72   } else {
  73     buffer_concat(buffer, "Error: ");
  74   }
  75   switch (error) {
  76     case JVMFlag::MISSING_NAME:
  77       buffer_concat(buffer, "flag name is missing."); break;
  78     case JVMFlag::MISSING_VALUE:
  79       buffer_concat(buffer, "parsing the textual form of the value."); break;
  80     case JVMFlag::NON_WRITABLE:
  81       buffer_concat(buffer, "flag is not writeable."); break;
  82     case JVMFlag::OUT_OF_BOUNDS:
  83       if (name != NULL) { print_flag_error_message_bounds(flag, buffer); } break;
  84     case JVMFlag::VIOLATES_CONSTRAINT:
  85       buffer_concat(buffer, "value violates its flag's constraint."); break;
  86     case JVMFlag::INVALID_FLAG:
  87       buffer_concat(buffer, "there is no flag with the given name."); break;
  88     case JVMFlag::ERR_OTHER:
  89       buffer_concat(buffer, "other, unspecified error related to setting the flag."); break;
  90     case JVMFlag::SUCCESS:
  91       break;
  92     default:
  93       break;
  94   }
  95 
  96   err_msg.print("%s", buffer);
  97 }
  98 
  99 // set a boolean global flag
 100 JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 101   if ((strcasecmp(arg, "true") == 0) || (*arg == '1' && *(arg + 1) == 0)) {
 102     return set_bool_flag(name, true, origin, err_msg);
 103   } else if ((strcasecmp(arg, "false") == 0) || (*arg == '0' && *(arg + 1) == 0)) {
 104     return set_bool_flag(name, false, origin, err_msg);
 105   }
 106   err_msg.print("flag value must be a boolean (1/0 or true/false)");
 107   return JVMFlag::WRONG_FORMAT;
 108 }
 109 
 110 JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 111   JVMFlag* flag = JVMFlag::find_flag(name);
 112   JVMFlag::Error err = JVMFlag::boolAtPut(flag, &value, origin);
 113   print_flag_error_message_if_needed(err, flag, err_msg);
 114   return err;
 115 }
 116 
 117 // set a int global flag
 118 JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 119   int value;
 120 
 121   if (sscanf(arg, "%d", &value) == 1) {
 122     return set_int_flag(name, value, origin, err_msg);
 123   }
 124   err_msg.print("flag value must be an integer");
 125   return JVMFlag::WRONG_FORMAT;
 126 }
 127 
 128 JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 129   JVMFlag* flag = JVMFlag::find_flag(name);
 130   JVMFlag::Error err = JVMFlag::intAtPut(flag, &value, origin);
 131   print_flag_error_message_if_needed(err, flag, err_msg);
 132   return err;
 133 }
 134 
 135 // set a uint global flag
 136 JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 137   uint value;
 138 
 139   if (sscanf(arg, "%u", &value) == 1) {
 140     return set_uint_flag(name, value, origin, err_msg);
 141   }
 142   err_msg.print("flag value must be an unsigned integer");
 143   return JVMFlag::WRONG_FORMAT;
 144 }
 145 
 146 JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 147   JVMFlag* flag = JVMFlag::find_flag(name);
 148   JVMFlag::Error err = JVMFlag::uintAtPut(flag, &value, origin);
 149   print_flag_error_message_if_needed(err, flag, err_msg);
 150   return err;
 151 }
 152 
 153 // set a intx global flag
 154 JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 155   intx value;
 156 
 157   if (sscanf(arg, INTX_FORMAT, &value) == 1) {
 158     return set_intx_flag(name, value, origin, err_msg);
 159   }
 160   err_msg.print("flag value must be an integer");
 161   return JVMFlag::WRONG_FORMAT;
 162 }
 163 
 164 JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 165   JVMFlag* flag = JVMFlag::find_flag(name);
 166   JVMFlag::Error err = JVMFlag::intxAtPut(flag, &value, origin);
 167   print_flag_error_message_if_needed(err, flag, err_msg);
 168   return err;
 169 }
 170 
 171 // set a uintx global flag
 172 JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 173   uintx value;
 174 
 175   if (sscanf(arg, UINTX_FORMAT, &value) == 1) {
 176     return set_uintx_flag(name, value, origin, err_msg);
 177   }
 178   err_msg.print("flag value must be an unsigned integer");
 179   return JVMFlag::WRONG_FORMAT;
 180 }
 181 
 182 JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 183   JVMFlag* flag = JVMFlag::find_flag(name);
 184   JVMFlag::Error err = JVMFlag::uintxAtPut(flag, &value, origin);
 185   print_flag_error_message_if_needed(err, flag, err_msg);
 186   return err;
 187 }
 188 
 189 // set a uint64_t global flag
 190 JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 191   uint64_t value;
 192 
 193   if (sscanf(arg, UINT64_FORMAT, &value) == 1) {
 194     return set_uint64_t_flag(name, value, origin, err_msg);
 195   }
 196   err_msg.print("flag value must be an unsigned 64-bit integer");
 197   return JVMFlag::WRONG_FORMAT;
 198 }
 199 
 200 JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 201   JVMFlag* flag = JVMFlag::find_flag(name);
 202   JVMFlag::Error err = JVMFlag::uint64_tAtPut(flag, &value, origin);
 203   print_flag_error_message_if_needed(err, flag, err_msg);
 204   return err;
 205 }
 206 
 207 // set a size_t global flag
 208 JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 209   size_t value;
 210 
 211   if (sscanf(arg, SIZE_FORMAT, &value) == 1) {
 212     return set_size_t_flag(name, value, origin, err_msg);
 213   }
 214   err_msg.print("flag value must be an unsigned integer");
 215   return JVMFlag::WRONG_FORMAT;
 216 }
 217 
 218 JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 219   JVMFlag* flag = JVMFlag::find_flag(name);
 220   JVMFlag::Error err = JVMFlag::size_tAtPut(flag, &value, origin);
 221   print_flag_error_message_if_needed(err, flag, err_msg);
 222   return err;
 223 }
 224 
 225 // set a double global flag
 226 JVMFlag::Error WriteableFlags::set_double_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 227   double value;
 228 
 229   if (sscanf(arg, "%lf", &value) == 1) {
 230     return set_double_flag(name, value, origin, err_msg);
 231   }
 232   err_msg.print("flag value must be a double");
 233   return JVMFlag::WRONG_FORMAT;
 234 }
 235 
 236 JVMFlag::Error WriteableFlags::set_double_flag(const char* name, double value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 237   JVMFlag* flag = JVMFlag::find_flag(name);
 238   JVMFlag::Error err = JVMFlag::doubleAtPut(flag, &value, origin);
 239   print_flag_error_message_if_needed(err, flag, err_msg);
 240   return err;
 241 }
 242 
 243 // set a string global flag using value from AttachOperation
 244 JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 245   JVMFlag* flag = JVMFlag::find_flag(name);
 246   JVMFlag::Error err = JVMFlag::ccstrAtPut(flag, &value, origin);
 247   print_flag_error_message_if_needed(err, flag, err_msg);
 248   return err;
 249 }
 250 
 251 /* sets a writeable flag to the provided value
 252  *
 253  * - return status is one of the WriteableFlags::err enum values
 254  * - an eventual error message will be generated to the provided err_msg buffer
 255  */
 256 JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 257   return set_flag(flag_name, &flag_value, set_flag_from_char, origin, err_msg);
 258 }
 259 
 260 /* sets a writeable flag to the provided value
 261  *
 262  * - return status is one of the WriteableFlags::err enum values
 263  * - an eventual error message will be generated to the provided err_msg buffer
 264  */
 265 JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 266   return set_flag(flag_name, &flag_value, set_flag_from_jvalue, origin, err_msg);
 267 }
 268 
 269 // a writeable flag setter accepting either 'jvalue' or 'char *' values
 270 JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*,const void*,JVMFlag::Flags,FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 271   if (name == NULL) {
 272     err_msg.print("flag name is missing");
 273     return JVMFlag::MISSING_NAME;
 274   }
 275   if (value == NULL) {
 276     err_msg.print("flag value is missing");
 277     return JVMFlag::MISSING_VALUE;
 278   }
 279 
 280   JVMFlag* f = JVMFlag::find_flag(name);
 281   if (f) {
 282     // only writeable flags are allowed to be set
 283     if (f->is_writeable()) {
 284       return setter(f, value, origin, err_msg);
 285     } else {
 286       err_msg.print("only 'writeable' flags can be set");
 287       return JVMFlag::NON_WRITABLE;
 288     }
 289   }
 290 
 291   err_msg.print("flag %s does not exist", name);
 292   return JVMFlag::INVALID_FLAG;
 293 }
 294 
 295 // a writeable flag setter accepting 'char *' values
 296 JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
 297   char* flag_value = *(char**)value;
 298   if (flag_value == NULL) {
 299     err_msg.print("flag value is missing");
 300     return JVMFlag::MISSING_VALUE;
 301   }
 302   if (f->is_bool()) {
 303     return set_bool_flag(f->_name, flag_value, origin, err_msg);
 304   } else if (f->is_int()) {
 305     return set_int_flag(f->_name, flag_value, origin, err_msg);
 306   } else if (f->is_uint()) {
 307     return set_uint_flag(f->_name, flag_value, origin, err_msg);
 308   } else if (f->is_intx()) {
 309     return set_intx_flag(f->_name, flag_value, origin, err_msg);
 310   } else if (f->is_uintx()) {
 311     return set_uintx_flag(f->_name, flag_value, origin, err_msg);
 312   } else if (f->is_uint64_t()) {
 313     return set_uint64_t_flag(f->_name, flag_value, origin, err_msg);
 314   } else if (f->is_size_t()) {
 315     return set_size_t_flag(f->_name, flag_value, origin, err_msg);
 316   } else if (f->is_double()) {
 317     return set_double_flag(f->_name, flag_value, origin, err_msg);
 318   } else if (f->is_ccstr()) {
 319     return set_ccstr_flag(f->_name, flag_value, origin, err_msg);
 320   } else {
 321     ShouldNotReachHere();
 322   }
 323   return JVMFlag::ERR_OTHER;
 324 }
 325 
 326 // a writeable flag setter accepting 'jvalue' values
 327 JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin,
 328                                                  FormatBuffer<80>& err_msg) {
 329   jvalue new_value = *(jvalue*)value;
 330   if (f->is_bool()) {
 331     bool bvalue = (new_value.z == JNI_TRUE ? true : false);
 332     return set_bool_flag(f->_name, bvalue, origin, err_msg);
 333   } else if (f->is_int()) {
 334     int ivalue = (int)new_value.j;
 335     return set_int_flag(f->_name, ivalue, origin, err_msg);
 336   } else if (f->is_uint()) {
 337     uint uvalue = (uint)new_value.j;
 338     return set_uint_flag(f->_name, uvalue, origin, err_msg);
 339   } else if (f->is_intx()) {
 340     intx ivalue = (intx)new_value.j;
 341     return set_intx_flag(f->_name, ivalue, origin, err_msg);
 342   } else if (f->is_uintx()) {
 343     uintx uvalue = (uintx)new_value.j;
 344     return set_uintx_flag(f->_name, uvalue, origin, err_msg);
 345   } else if (f->is_uint64_t()) {
 346     uint64_t uvalue = (uint64_t)new_value.j;
 347     return set_uint64_t_flag(f->_name, uvalue, origin, err_msg);
 348   } else if (f->is_size_t()) {
 349     size_t svalue = (size_t)new_value.j;
 350     return set_size_t_flag(f->_name, svalue, origin, err_msg);
 351   } else if (f->is_double()) {
 352     double dvalue = (double)new_value.d;
 353     return set_double_flag(f->_name, dvalue, origin, err_msg);
 354   } else if (f->is_ccstr()) {
 355     oop str = JNIHandles::resolve_external_guard(new_value.l);
 356     if (str == NULL) {
 357       err_msg.print("flag value is missing");
 358       return JVMFlag::MISSING_VALUE;
 359     }
 360     ccstr svalue = java_lang_String::as_utf8_string(str);
 361     JVMFlag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg);
 362     if (ret != JVMFlag::SUCCESS) {
 363       FREE_C_HEAP_ARRAY(char, svalue);
 364     }
 365     return ret;
 366   } else {
 367     ShouldNotReachHere();
 368   }
 369   return JVMFlag::ERR_OTHER;
 370 }