diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | NEWS | 29 | ||||
-rw-r--r-- | elaborate.cxx | 57 | ||||
-rw-r--r-- | elaborate.h | 1 | ||||
-rw-r--r-- | staptree.cxx | 54 | ||||
-rw-r--r-- | staptree.h | 25 |
6 files changed, 161 insertions, 27 deletions
@@ -1,3 +1,25 @@ +2008-02-21 Dave Brolley <brolley@redhat.com> + + PR5189 + * staptree.h (print_format::conv_memory): New enumerator. + (print_format::width_type): New enumeration. + (print_format::precision_type): New enumeration. + (format_component::widthtype): New member. + (format_component::prectype): New member. + (format_component::is_empty): Test widthtype and prectype. + (format_component::clear): Clear widthtype and prectype. + * staptree.cxx (print_format::components_to_string): Handle dynamic width and precision. + Handle conv_memory. + (print_format::string_to_components): Parse dynamic width and precision specifiers. + Set widthtype and prectype. Parse %m format specifier. + * elaborate.h (typeresolution_info::check_arg_type): New method. + * elaborate.cxx (typeresolution_info::visit_print_format): Account for dynamic width + and precision when computing the expected number of arguments. Check the types of + arguments for dynamic width and precision. Use check_arg_type to check the types of + all arguments. Handle print_format::conv_memory. + (typeresolution_info::check_arg_type): New method. + * NEWS: Describe the enhancements above. + 2008-02-27 David Smith <dsmith@redhat.com> PR5729 @@ -1,5 +1,34 @@ * What's new in version 0.6 / 0.6.1 +- There is a new format specifier, %m, for the printf family of + functions. It functions like %s, except that it does not stop when + a nul ('\0') byte is encountered. The number of bytes output is + determined by the precision specifier. The default precision is 1. + For example: + + printf ("%m", "My String") // prints one character: M + printf ("%.5", myString) // prints 5 bytes beginning at the start + // of myString + +- The %b format specifier for the printf family of functions has been enhanced + as follows: + + 1) When the width and precision are both unspecified, the default is %8.8b. + 2) When only one of the width or precision is specified, the other defaults + to the same value. For example, %4b == %.4b == %4.4b + 3) Nul ('\0') bytes are used for field width padding. For example, + + printf ("%b", 0x1111deadbeef2222) // prints all eight bytes + printf ("%4.2b", 0xdeadbeef) // prints \0\0\xbe\xef + +- Dynamic width and precision are now supported for all printf family format + specifiers. For example: + + four = 4 + two = 2 + printf ("%*.*b", four, two, 0xdeadbbeef) // prints \0\0\xbe\xef + printf ("%*d", four, two) // prints <space><space><space>2 + - Preprocessor conditional expressions can now include wildcard style matches on kernel versions. %( kernel_vr != "*xen" %? foo %: bar %) diff --git a/elaborate.cxx b/elaborate.cxx index bc0d1489..7f4ccf35 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -2854,6 +2854,7 @@ typeresolution_info::visit_print_format (print_format* e) // First we extract the subsequence of formatting components // which are conversions (not just literal string components) + unsigned expected_num_args = 0; std::vector<print_format::format_component> components; for (size_t i = 0; i < e->components.size(); ++i) { @@ -2864,19 +2865,39 @@ typeresolution_info::visit_print_format (print_format* e) || e->components[i].type == print_format::conv_size) continue; components.push_back(e->components[i]); + ++expected_num_args; + if (e->components[i].widthtype == print_format::width_dynamic) + ++expected_num_args; + if (e->components[i].prectype == print_format::prec_dynamic) + ++expected_num_args; } // Then we check that the number of conversions and the number // of args agree. - if (components.size() != e->args.size()) + if (expected_num_args != e->args.size()) throw semantic_error ("Wrong number of args to formatted print operator", e->tok); // Then we check that the types of the conversions match the types // of the args. + unsigned argno = 0; for (size_t i = 0; i < components.size(); ++i) { + // Check the dynamic width, if specified + if (components[i].widthtype == print_format::width_dynamic) + { + check_arg_type (pe_long, e->args[argno]); + ++argno; + } + + // Check the dynamic precision, if specified + if (components[i].prectype == print_format::prec_dynamic) + { + check_arg_type (pe_long, e->args[argno]); + ++argno; + } + exp_type wanted = pe_unknown; switch (components[i].type) @@ -2898,24 +2919,14 @@ typeresolution_info::visit_print_format (print_format* e) break; case print_format::conv_string: + case print_format::conv_memory: wanted = pe_string; break; } assert (wanted != pe_unknown); - - t = wanted; - e->args[i]->visit (this); - - if (e->args[i]->type == pe_unknown) - { - e->args[i]->type = wanted; - resolved (e->args[i]->tok, wanted); - } - else if (e->args[i]->type != wanted) - { - mismatch (e->args[i]->tok, e->args[i]->type, wanted); - } + check_arg_type (wanted, e->args[argno]); + ++argno; } } else @@ -2976,6 +2987,24 @@ typeresolution_info::visit_hist_op (hist_op* e) void +typeresolution_info::check_arg_type (exp_type wanted, expression* arg) +{ + t = wanted; + arg->visit (this); + + if (arg->type == pe_unknown) + { + arg->type = wanted; + resolved (arg->tok, wanted); + } + else if (arg->type != wanted) + { + mismatch (arg->tok, arg->type, wanted); + } +} + + +void typeresolution_info::unresolved (const token* tok) { num_still_unresolved ++; diff --git a/elaborate.h b/elaborate.h index 607f8689..fc8fbbcb 100644 --- a/elaborate.h +++ b/elaborate.h @@ -54,6 +54,7 @@ struct typeresolution_info: public visitor functiondecl* current_function; derived_probe* current_probe; + void check_arg_type (exp_type wanted, expression* arg); void mismatch (const token* tok, exp_type t1, exp_type t2); void unresolved (const token* tok); void resolved (const token* tok, exp_type t); diff --git a/staptree.cxx b/staptree.cxx index 36ef04f5..63c1fcf7 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -442,10 +442,14 @@ print_format::components_to_string(vector<format_component> const & components) if (i->flags & static_cast<unsigned long>(fmt_flag_special)) oss << '#'; - if (i->width > 0) + if (i->widthtype == width_dynamic) + oss << '*'; + else if (i->widthtype != width_unspecified && i->width > 0) oss << i->width; - if (i->precision > 0) + if (i->prectype == prec_dynamic) + oss << ".*"; + else if (i->prectype != prec_unspecified && i->precision > 0) oss << '.' << i->precision; switch (i->type) @@ -482,6 +486,10 @@ print_format::components_to_string(vector<format_component> const & components) oss << 's'; break; + case conv_memory: + oss << 'm'; + break; + case conv_size: oss << 'n'; break; @@ -574,14 +582,27 @@ print_format::string_to_components(string const & str) break; } + if (i == str.end()) + break; + // Parse optional width - - while (i != str.end() && isdigit(*i)) + if (*i == '*') { - curr.width *= 10; - curr.width += (*i - '0'); + curr.widthtype = width_dynamic; ++i; } + else if (isdigit(*i)) + { + curr.widthtype = width_static; + curr.width = 0; + do + { + curr.width *= 10; + curr.width += (*i - '0'); + ++i; + } + while (i != str.end() && isdigit(*i)); + } if (i == str.end()) break; @@ -592,12 +613,23 @@ print_format::string_to_components(string const & str) ++i; if (i == str.end()) break; - while (i != str.end() && isdigit(*i)) + if (*i == '*') { - curr.precision *= 10; - curr.precision += (*i - '0'); + curr.prectype = prec_dynamic; ++i; } + else if (isdigit(*i)) + { + curr.prectype = prec_static; + curr.precision = 0; + do + { + curr.precision *= 10; + curr.precision += (*i - '0'); + ++i; + } + while (i != str.end() && isdigit(*i)); + } } if (i == str.end()) @@ -615,6 +647,10 @@ print_format::string_to_components(string const & str) curr.type = conv_string; break; + case 'm': + curr.type = conv_memory; + break; + case 'd': case 'i': curr.type = conv_signed_decimal; @@ -287,31 +287,48 @@ struct print_format: public expression conv_unsigned_uppercase_hex, conv_unsigned_lowercase_hex, conv_string, + conv_memory, conv_literal, conv_binary, conv_size }; + enum width_type + { + width_unspecified, + width_static, + width_dynamic + }; + + enum precision_type + { + prec_unspecified, + prec_static, + prec_dynamic + }; + struct format_component { unsigned long flags; unsigned width; unsigned precision; + width_type widthtype; + precision_type prectype; conversion_type type; std::string literal_string; bool is_empty() const { return flags == 0 - && width == 0 - && precision == 0 + && widthtype == width_unspecified + && prectype == prec_unspecified && type == conv_unspecified && literal_string.empty(); } void clear() { flags = 0; - width = 0; - precision = 0; + widthtype = width_unspecified; + prectype = prec_unspecified; type = conv_unspecified; literal_string.clear(); } |