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