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