1 /*
   2  * Copyright (c) 2011, 2013, 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 "memory/allocation.inline.hpp"
  27 #include "runtime/thread.hpp"
  28 #include "services/diagnosticArgument.hpp"
  29 
  30 void GenDCmdArgument::read_value(const char* str, size_t len, TRAPS) {
  31   /* NOTE:Some argument types doesn't require a value,
  32    * for instance boolean arguments: "enableFeatureX". is
  33    * equivalent to "enableFeatureX=true". In these cases,
  34    * str will be null. This is perfectly valid.
  35    * All argument types must perform null checks on str.
  36    */
  37 
  38   if (is_set() && !allow_multiple()) {
  39     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
  40             "Duplicates in diagnostic command arguments\n");
  41   }
  42   parse_value(str, len, CHECK);
  43   set_is_set(true);
  44 }
  45 
  46 void GenDCmdArgument::to_string(jlong l, char* buf, size_t len) {
  47   jio_snprintf(buf, len, INT64_FORMAT, l);
  48 }
  49 
  50 void GenDCmdArgument::to_string(bool b, char* buf, size_t len) {
  51   jio_snprintf(buf, len, b ? "true" : "false");
  52 }
  53 
  54 void GenDCmdArgument::to_string(NanoTimeArgument n, char* buf, size_t len) {
  55   jio_snprintf(buf, len, INT64_FORMAT, n._nanotime);
  56 }
  57 
  58 void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) {
  59   jio_snprintf(buf, len, INT64_FORMAT, m._size);
  60 }
  61 
  62 void GenDCmdArgument::to_string(char* c, char* buf, size_t len) {
  63   jio_snprintf(buf, len, "%s", c);
  64 }
  65 
  66 void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) {
  67   int length = f->array()->length();
  68   size_t written = 0;
  69   buf[0] = 0;
  70   for (int i = 0; i < length; i++) {
  71     char* next_str = f->array()->at(i);
  72     size_t next_size = strlen(next_str);
  73     //Check if there's room left to write next element
  74     if (written + next_size > len) {
  75       return;
  76     }
  77     //Actually write element
  78     strcat(buf, next_str);
  79     written += next_size;
  80     //Check if there's room left for the comma
  81     if (i < length-1 && len - written > 0) {
  82       strcat(buf, ",");
  83     }
  84   }
  85 }
  86 
  87 template <> void DCmdArgument<jlong>::parse_value(const char* str,
  88                                                   size_t len, TRAPS) {
  89     if (str == NULL || sscanf(str, JLONG_FORMAT, &_value) != 1) {
  90     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
  91       "Integer parsing error in diagnostic command arguments\n");
  92   }
  93 }
  94 
  95 template <> void DCmdArgument<jlong>::init_value(TRAPS) {
  96   if (has_default()) {
  97     this->parse_value(_default_string, strlen(_default_string), THREAD);
  98     if (HAS_PENDING_EXCEPTION) {
  99       fatal("Default string must be parsable");
 100     }
 101   } else {
 102     set_value(0);
 103   }
 104 }
 105 
 106 template <> void DCmdArgument<jlong>::destroy_value() { }
 107 
 108 template <> void DCmdArgument<bool>::parse_value(const char* str,
 109                                                  size_t len, TRAPS) {
 110   // len is the length of the current token starting at str
 111   if (len == 0) {
 112     set_value(true);
 113   } else {
 114     if (len == strlen("true") && strncasecmp(str, "true", len) == 0) {
 115        set_value(true);
 116     } else if (len == strlen("false") && strncasecmp(str, "false", len) == 0) {
 117        set_value(false);
 118     } else {
 119       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 120         "Boolean parsing error in diagnostic command arguments");
 121     }
 122   }
 123 }
 124 
 125 template <> void DCmdArgument<bool>::init_value(TRAPS) {
 126   if (has_default()) {
 127     this->parse_value(_default_string, strlen(_default_string), THREAD);
 128     if (HAS_PENDING_EXCEPTION) {
 129       fatal("Default string must be parsable");
 130     }
 131   } else {
 132     set_value(false);
 133   }
 134 }
 135 
 136 template <> void DCmdArgument<bool>::destroy_value() { }
 137 
 138 template <> void DCmdArgument<char*>::parse_value(const char* str,
 139                                                   size_t len, TRAPS) {
 140   if (str == NULL) {
 141     _value = NULL;
 142   } else {
 143     _value = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
 144     strncpy(_value, str, len);
 145     _value[len] = 0;
 146   }
 147 }
 148 
 149 template <> void DCmdArgument<char*>::init_value(TRAPS) {
 150   if (has_default() && _default_string != NULL) {
 151     this->parse_value(_default_string, strlen(_default_string), THREAD);
 152     if (HAS_PENDING_EXCEPTION) {
 153      fatal("Default string must be parsable");
 154     }
 155   } else {
 156     set_value(NULL);
 157   }
 158 }
 159 
 160 template <> void DCmdArgument<char*>::destroy_value() {
 161   if (_value != NULL) {
 162     FREE_C_HEAP_ARRAY(char, _value, mtInternal);
 163     set_value(NULL);
 164   }
 165 }
 166 
 167 template <> void DCmdArgument<NanoTimeArgument>::parse_value(const char* str,
 168                                                  size_t len, TRAPS) {
 169   if (str == NULL) {
 170     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 171               "Integer parsing error nanotime value: syntax error");
 172   }
 173 
 174   int argc = sscanf(str, JLONG_FORMAT, &_value._time);
 175   if (argc != 1) {
 176     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 177               "Integer parsing error nanotime value: syntax error");
 178   }
 179   size_t idx = 0;
 180   while(idx < len && isdigit(str[idx])) {
 181     idx++;
 182   }
 183   if (idx == len) {
 184     // only accept missing unit if the value is 0
 185     if (_value._time != 0) {
 186       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 187                 "Integer parsing error nanotime value: unit required");
 188     } else {
 189       _value._nanotime = 0;
 190       strcpy(_value._unit, "ns");
 191       return;
 192     }
 193   } else if(len - idx > 2) {
 194     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 195               "Integer parsing error nanotime value: illegal unit");
 196   } else {
 197     strncpy(_value._unit, &str[idx], len - idx);
 198     /*Write an extra null termination. This is safe because _value._unit
 199      * is declared as char[3], and length is checked to be not larger than
 200      * two above. Also, this is necessary, since length might be 1, and the
 201      * default value already in the string is ns, which is two chars.
 202      */
 203     _value._unit[len-idx] = '\0';
 204   }
 205 
 206   if (strcmp(_value._unit, "ns") == 0) {
 207     _value._nanotime = _value._time;
 208   } else if (strcmp(_value._unit, "us") == 0) {
 209     _value._nanotime = _value._time * 1000;
 210   } else if (strcmp(_value._unit, "ms") == 0) {
 211     _value._nanotime = _value._time * 1000 * 1000;
 212   } else if (strcmp(_value._unit, "s") == 0) {
 213     _value._nanotime = _value._time * 1000 * 1000 * 1000;
 214   } else if (strcmp(_value._unit, "m") == 0) {
 215     _value._nanotime = _value._time * 60 * 1000 * 1000 * 1000;
 216   } else if (strcmp(_value._unit, "h") == 0) {
 217     _value._nanotime = _value._time * 60 * 60 * 1000 * 1000 * 1000;
 218   } else if (strcmp(_value._unit, "d") == 0) {
 219     _value._nanotime = _value._time * 24 * 60 * 60 * 1000 * 1000 * 1000;
 220   } else {
 221      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 222                "Integer parsing error nanotime value: illegal unit");
 223   }
 224 }
 225 
 226 template <> void DCmdArgument<NanoTimeArgument>::init_value(TRAPS) {
 227   if (has_default()) {
 228     this->parse_value(_default_string, strlen(_default_string), THREAD);
 229     if (HAS_PENDING_EXCEPTION) {
 230       fatal("Default string must be parsable");
 231     }
 232   } else {
 233     _value._time = 0;
 234     _value._nanotime = 0;
 235     strcmp(_value._unit, "ns");
 236   }
 237 }
 238 
 239 template <> void DCmdArgument<NanoTimeArgument>::destroy_value() { }
 240 
 241 // WARNING StringArrayArgument can only be used as an option, it cannot be
 242 // used as an argument with the DCmdParser
 243 
 244 template <> void DCmdArgument<StringArrayArgument*>::parse_value(const char* str,
 245                                                   size_t len, TRAPS) {
 246   _value->add(str,len);
 247 }
 248 
 249 template <> void DCmdArgument<StringArrayArgument*>::init_value(TRAPS) {
 250   _value = new StringArrayArgument();
 251   _allow_multiple = true;
 252   if (has_default()) {
 253     fatal("StringArrayArgument cannot have default value");
 254   }
 255 }
 256 
 257 template <> void DCmdArgument<StringArrayArgument*>::destroy_value() {
 258   if (_value != NULL) {
 259     delete _value;
 260     set_value(NULL);
 261   }
 262 }
 263 
 264 template <> void DCmdArgument<MemorySizeArgument>::parse_value(const char* str,
 265                                                   size_t len, TRAPS) {
 266   if (str == NULL) {
 267     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 268               "Integer parsing error nanotime value: syntax error");
 269   }
 270 
 271   if (*str == '-') {
 272     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 273                "Parsing error memory size value: negative values not allowed");
 274   }
 275   int res = sscanf(str, UINT64_FORMAT "%c", &_value._val, &_value._multiplier);
 276   if (res == 2) {
 277      switch (_value._multiplier) {
 278       case 'k': case 'K':
 279          _value._size = _value._val * 1024;
 280          break;
 281       case 'm': case 'M':
 282          _value._size = _value._val * 1024 * 1024;
 283          break;
 284       case 'g': case 'G':
 285          _value._size = _value._val * 1024 * 1024 * 1024;
 286          break;
 287        default:
 288          _value._size = _value._val;
 289          _value._multiplier = ' ';
 290          //default case should be to break with no error, since user
 291          //can write size in bytes, or might have a delimiter and next arg
 292          break;
 293      }
 294    } else if (res == 1) {
 295      _value._size = _value._val;
 296    } else {
 297      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
 298                "Parsing error memory size value: invalid value");
 299    }
 300 }
 301 
 302 template <> void DCmdArgument<MemorySizeArgument>::init_value(TRAPS) {
 303   if (has_default()) {
 304     this->parse_value(_default_string, strlen(_default_string), THREAD);
 305     if (HAS_PENDING_EXCEPTION) {
 306       fatal("Default string must be parsable");
 307     }
 308   } else {
 309     _value._size = 0;
 310     _value._val = 0;
 311     _value._multiplier = ' ';
 312   }
 313 }
 314 
 315 template <> void DCmdArgument<MemorySizeArgument>::destroy_value() { }