summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coregrind/m_options.c3
-rw-r--r--coregrind/pub_core_options.h2
-rw-r--r--include/pub_tool_options.h1
-rw-r--r--massif/ms_main.c79
4 files changed, 64 insertions, 21 deletions
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index febf82c7..cd35f668 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -96,6 +96,7 @@ static void revert_to_stderr ( void )
VG_(clo_log_fd) = 2; /* stderr */
}
+__attribute__((noreturn))
void VG_(err_bad_option) ( Char* opt )
{
revert_to_stderr();
@@ -104,6 +105,7 @@ void VG_(err_bad_option) ( Char* opt )
VG_(exit)(1);
}
+__attribute__((noreturn))
void VG_(err_missing_prog) ( void )
{
revert_to_stderr();
@@ -112,6 +114,7 @@ void VG_(err_missing_prog) ( void )
VG_(exit)(1);
}
+__attribute__((noreturn))
void VG_(err_config_error) ( Char* msg )
{
revert_to_stderr();
diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h
index 15d33f6b..39947dbd 100644
--- a/coregrind/pub_core_options.h
+++ b/coregrind/pub_core_options.h
@@ -191,10 +191,12 @@ extern HChar* VG_(clo_kernel_variant);
/* Call this if the executable is missing. This function prints an
error message, then shuts down the entire system. */
+__attribute__((noreturn))
extern void VG_(err_missing_prog) ( void );
/* Similarly - complain and stop if there is some kind of config
error. */
+__attribute__((noreturn))
extern void VG_(err_config_error) ( Char* msg );
diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h
index 364206df..369f8a28 100644
--- a/include/pub_tool_options.h
+++ b/include/pub_tool_options.h
@@ -124,6 +124,7 @@ extern VexControl VG_(clo_vex_control);
'False' from VG_(tdict).tool_process_cmd_line_option) to indicate
that. This function prints an error message, then shuts down the
entire system. */
+__attribute__((noreturn))
extern void VG_(err_bad_option) ( Char* opt );
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 76b43d9d..578bc16c 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -2054,7 +2054,7 @@ static void ms_fini(Int exit_status)
// Copies the string, prepending it with the startup working directory, and
// expanding %p and %q entries. Returns a new, malloc'd string.
-static Char* expand_file_name(Char* format)
+static Char* VG_(expand_file_name)(Char* option_name, Char* format)
{
static Char base_dir[VKI_PATH_MAX];
Int len, i = 0, j = 0;
@@ -2069,49 +2069,85 @@ static Char* expand_file_name(Char* format)
out = VG_(malloc)( len );
VG_(strcpy)(out, base_dir);
-#define GROW_IF_j_IS_GEQ_THAN(x) \
- if (j >= x) { \
- len *= 2; \
+#define ENSURE_THIS_MUCH_SPACE(x) \
+ if (j + x >= len) { \
+ len += (10 + x); \
out = VG_(realloc)(out, len); \
- OINK(len);\
}
out[j++] = '/';
while (format[i]) {
if (format[i] != '%') {
- GROW_IF_j_IS_GEQ_THAN(len);
+ ENSURE_THIS_MUCH_SPACE(1);
out[j++] = format[i++];
} else {
// We saw a '%'. What's next...
i++;
- if (0 == format[i]) {
- // At end of string, stop.
- break;
- }
- else if ('%' == format[i]) {
+ if ('%' == format[i]) {
// Replace '%%' with '%'.
- GROW_IF_j_IS_GEQ_THAN(len);
+ ENSURE_THIS_MUCH_SPACE(1);
out[j++] = format[i++];
}
else if ('p' == format[i]) {
- // Print the PID.
- GROW_IF_j_IS_GEQ_THAN(len - 10);
- j += VG_(sprintf)(&out[j], "%d", VG_(getpid)());
+ // Print the PID. Assume that it's not longer than 10 chars --
+ // reasonable since 'pid' is an Int (ie. 32 bits).
+ Int pid = VG_(getpid)();
+ ENSURE_THIS_MUCH_SPACE(10);
+ j += VG_(sprintf)(&out[j], "%d", pid);
i++;
}
+ else if ('q' == format[i] && '{' == format[i+1]) {
+ // Get the env var name, print its contents.
+ Char* qualname;
+ Char* qual;
+ i += 2;
+ qualname = &format[i];
+ while (True) {
+ if (0 == format[i]) {
+ VG_(message)(Vg_UserMsg, "%s: malformed %%q specifier",
+ option_name);
+ goto bad;
+ } else if ('}' == format[i]) {
+ // Temporarily replace the '}' with NUL to extract var name.
+ format[i] = 0;
+ qual = VG_(getenv)(qualname);
+ if (NULL == qual) {
+ VG_(message)(Vg_UserMsg,
+ "%s: environment variable %s is not set",
+ option_name, qualname);
+ goto bad;
+ }
+ format[i] = '}'; // Put the '}' back.
+ i++;
+ break;
+ }
+ i++;
+ }
+ ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual));
+ j += VG_(sprintf)(&out[j], "%s", qual);
+ }
else {
- // Other char, treat both the '%' and its subsequent normally.
- GROW_IF_j_IS_GEQ_THAN(len - 1);
- out[j++] = '%';
- out[j++] = format[i++];
+ // Something else, abort.
+ VG_(message)(Vg_UserMsg,
+ "%s: expected 'p' or 'q' or '%%' after '%%'", option_name);
+ goto bad;
}
}
}
- GROW_IF_j_IS_GEQ_THAN(len);
+ ENSURE_THIS_MUCH_SPACE(1);
out[j++] = 0;
return out;
+
+ bad: {
+ Char* opt = // 2: 1 for the '=', 1 for the NUL.
+ VG_(malloc)( VG_(strlen)(option_name) + VG_(strlen)(format) + 2 );
+ VG_(strcpy)(opt, option_name);
+ VG_(strcat)(opt, "=");
+ VG_(strcat)(opt, format);
+ VG_(err_bad_option)(opt);
+ }
}
@@ -2174,7 +2210,8 @@ static void ms_post_clo_init(void)
sanity_check_snapshots_array();
// Setup output filename.
- massif_out_file = expand_file_name(clo_massif_out_file);
+ massif_out_file =
+ VG_(expand_file_name)("--massif-out-file", clo_massif_out_file);
}
static void ms_pre_clo_init(void)