From cc9ee6059e4d3fb51c0695a8a57f75eb988a1786 Mon Sep 17 00:00:00 2001 From: fche Date: Mon, 5 Sep 2005 22:00:43 +0000 Subject: [PATCH] 2005-09-05 Frank Ch. Eigler PR 1172. * staptree.h, staptree.cxx: Make all ::print*(), operator<< functions take const staptree objects. (literal_string::print): \-prefix double-quotes. * translate.cxx (emit_common_header): Add context probe_point field. Switch to atomic_t busy flags. (emit_module_exit): Use atomic operations for busy flag. (visit_*): Use lex_cast_qstring for last_stmt strings. * tapsets.cxx (lex_cast_quoted): \-prefix double-quotes too. (*::emit_probe_entries): Populate probe_point. Use atomic operations for busy flag. * tapset/context.stp (pp): New function. * stapfuncs.5.in: Document it. * testsuite/buildok/context_test.stp: Test it. --- ChangeLog | 17 +++++ stapfuncs.5.in | 39 +++++----- staptree.cxx | 82 +++++++++++---------- staptree.h | 80 ++++++++++----------- tapset/context.stp | 4 ++ tapsets.cxx | 111 +++++++++++++++++------------ testsuite/buildok/context_test.stp | 30 +++----- translate.cxx | 54 +++++++++----- 8 files changed, 242 insertions(+), 175 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2a59812b3..71bf11ea7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2005-09-05 Frank Ch. Eigler + + PR 1172. + * staptree.h, staptree.cxx: Make all ::print*(), operator<< + functions take const staptree objects. + (literal_string::print): \-prefix double-quotes. + * translate.cxx (emit_common_header): Add context probe_point field. + Switch to atomic_t busy flags. + (emit_module_exit): Use atomic operations for busy flag. + (visit_*): Use lex_cast_qstring for last_stmt strings. + * tapsets.cxx (lex_cast_quoted): \-prefix double-quotes too. + (*::emit_probe_entries): Populate probe_point. Use atomic operations + for busy flag. + * tapset/context.stp (pp): New function. + * stapfuncs.5.in: Document it. + * testsuite/buildok/context_test.stp: Test it. + 2005-09-04 Frank Ch. Eigler * translate.cxx (visit_literal_string): \-prefix double-quotes. diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 212e51935..dbecf0d3a 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -15,13 +15,13 @@ Examples: .TP example1:long (v:string, k:long) -Function "example1" does something with the given string and integer. -It returns some integer. +In function "example1", do something with the given string and integer. +Return some integer. .TP example2:unknown () -Function "example2" does something. There is no explicit return value -and it takes no parameters. +In function "example2", do something. There is no explicit return value +and take no parameters. .SS LOGGING @@ -98,52 +98,57 @@ Return the number of seconds since the UNIX epoch. .TP execname:string () -Returns the name of the current process. +Return the name of the current process. .TP pexecname:string() -Returns the name of the parent process. +Return the name of the parent process. .TP pid:long () -Returns the current pid. +Return the current pid. .TP ppid:long () -Returns the current pid. +Return the current pid. .TP uid:long () -Returns the uid of the current process. +Return the uid of the current process. .TP euid:long () -Returns the effective uid of the current process. +Return the effective uid of the current process. .TP gid:long () -Returns the gid of the current process. +Return the gid of the current process. .TP egid:long () -Returns the effective gid of the current process. +Return the effective gid of the current process. .TP print_regs:unknown () -Prints a register dump. +Print a register dump. .TP print_backtrace:unknown () -Prints a symbolic backtrace. Use with care. May be timeconsuming. +Print a symbolic backtrace. Use with care. May be timeconsuming. .TP backtrace:string () -Returns a string of hex addresses that are a backtrace of the stack. +Return a string of hex addresses that are a backtrace of the stack. May be truncated due to maximum string length. .TP -print_stack(bt:string) -Does a symbolic lookup of the addresses in bt and prints one per line. +print_stack (bt:string) +Perform a symbolic lookup of the addresses in bt and prints one per line. + +.TP +pp:string () +Return the probe point associated with the currently running probe handler, +including alias and wildcard expansion effects. .SH FILES .nh diff --git a/staptree.cxx b/staptree.cxx index 8af920d69..47a5cd0ca 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -168,27 +168,32 @@ operator << (ostream& o, const exp_type& e) // ------------------------------------------------------------------------ // parse tree printing -ostream& operator << (ostream& o, expression& k) +ostream& operator << (ostream& o, const expression& k) { k.print (o); return o; } -void literal_string::print (ostream& o) +void literal_string::print (ostream& o) const { - // XXX: quote special chars - o << '"' << value << '"'; + o << '"'; + for (unsigned i=0; iindexes.size(); i++) @@ -212,13 +217,13 @@ void array_in::print (ostream& o) o << "] in " << operand->base; } -void post_crement::print (ostream& o) +void post_crement::print (ostream& o) const { o << '(' << *operand << ")" << op; } -void ternary_expression::print (ostream& o) +void ternary_expression::print (ostream& o) const { o << "(" << *cond << ")?(" << *truevalue << "):(" @@ -226,13 +231,13 @@ void ternary_expression::print (ostream& o) } -void symbol::print (ostream& o) +void symbol::print (ostream& o) const { o << name; } -void target_symbol::print (std::ostream& o) +void target_symbol::print (std::ostream& o) const { o << base_name; for (unsigned i = 0; i < components.size(); ++i) @@ -250,7 +255,7 @@ void target_symbol::print (std::ostream& o) } -void vardecl::print (ostream& o) +void vardecl::print (ostream& o) const { o << name; if (arity > 0 || index_types.size() > 0) @@ -258,7 +263,7 @@ void vardecl::print (ostream& o) } -void vardecl::printsig (ostream& o) +void vardecl::printsig (ostream& o) const { o << name << ":" << type; if (index_types.size() > 0) @@ -271,7 +276,7 @@ void vardecl::printsig (ostream& o) } -void functiondecl::print (ostream& o) +void functiondecl::print (ostream& o) const { o << "function " << name << " ("; for (unsigned i=0; iprint (o); @@ -347,7 +352,7 @@ void for_loop::print (ostream& o) } -void foreach_loop::print (ostream& o) +void foreach_loop::print (ostream& o) const { o << "foreach (["; for (unsigned i=0; i const & aliases): probe (), alias_names (aliases) { } -void probe_alias::printsig (ostream& o) +void probe_alias::printsig (ostream& o) const { for (unsigned i=0; i > components; - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -198,7 +198,7 @@ struct arrayindex: public expression std::vector indexes; vardecl *referent; arrayindex (); - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -210,7 +210,7 @@ struct functioncall: public expression std::vector args; functiondecl *referent; functioncall (); - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -226,18 +226,18 @@ struct symboldecl // unique object per (possibly implicit) exp_type type; symboldecl (); virtual ~symboldecl (); - virtual void print (std::ostream &o) = 0; - virtual void printsig (std::ostream &o) = 0; + virtual void print (std::ostream &o) const = 0; + virtual void printsig (std::ostream &o) const = 0; }; -std::ostream& operator << (std::ostream& o, symboldecl& k); +std::ostream& operator << (std::ostream& o, const symboldecl& k); struct vardecl: public symboldecl { - void print (std::ostream& o); - void printsig (std::ostream& o); + void print (std::ostream& o) const; + void printsig (std::ostream& o) const; vardecl (); void set_arity (int arity); bool compatible_arity (int a); @@ -258,8 +258,8 @@ struct functiondecl: public symboldecl std::vector locals; statement* body; functiondecl (); - void print (std::ostream& o); - void printsig (std::ostream& o); + void print (std::ostream& o) const; + void printsig (std::ostream& o) const; }; @@ -268,20 +268,20 @@ struct functiondecl: public symboldecl struct statement { - virtual void print (std::ostream& o) = 0; + virtual void print (std::ostream& o) const = 0; virtual void visit (visitor* u) = 0; const token* tok; statement (); virtual ~statement (); }; -std::ostream& operator << (std::ostream& o, statement& k); +std::ostream& operator << (std::ostream& o, const statement& k); struct embeddedcode: public statement { std::string code; - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -289,7 +289,7 @@ struct embeddedcode: public statement struct block: public statement { std::vector statements; - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -301,7 +301,7 @@ struct for_loop: public statement expression* cond; expr_statement* incr; statement* block; - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -314,14 +314,14 @@ struct foreach_loop: public statement vardecl* base_referent; statement* block; - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; struct null_statement: public statement { - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -329,7 +329,7 @@ struct null_statement: public statement struct expr_statement: public statement { expression* value; // executed for side-effects - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -339,42 +339,42 @@ struct if_statement: public statement expression* condition; statement* thenblock; statement* elseblock; - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; struct return_statement: public expr_statement { - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; struct delete_statement: public expr_statement { - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; struct break_statement: public statement { - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; struct continue_statement: public statement { - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; struct next_statement: public statement { - void print (std::ostream& o); + void print (std::ostream& o) const; void visit (visitor* u); }; @@ -392,7 +392,7 @@ struct stapfile std::vector embeds; bool privileged; stapfile (): privileged (false) {} - void print (std::ostream& o); + void print (std::ostream& o) const; }; @@ -409,12 +409,12 @@ struct probe_point }; std::vector components; const token* tok; // points to first component's functor - void print (std::ostream& o); + void print (std::ostream& o) const; probe_point (); probe_point(std::vector const & comps,const token * t); }; -std::ostream& operator << (std::ostream& o, probe_point& k); +std::ostream& operator << (std::ostream& o, const probe_point& k); struct probe @@ -424,8 +424,8 @@ struct probe const token* tok; std::vector locals; probe (); - void print (std::ostream& o); - virtual void printsig (std::ostream &o); + void print (std::ostream& o) const; + virtual void printsig (std::ostream &o) const; virtual ~probe() {} }; @@ -433,7 +433,7 @@ struct probe_alias: public probe { probe_alias(std::vector const & aliases); std::vector alias_names; - virtual void printsig (std::ostream &o); + virtual void printsig (std::ostream &o) const; }; diff --git a/tapset/context.stp b/tapset/context.stp index 4d8019561..3e7765472 100644 --- a/tapset/context.stp +++ b/tapset/context.stp @@ -88,3 +88,7 @@ function print_stack(stk:string) %{ tok = strsep(&ptr, " "); } %} + +function pp:string () %{ + strlcpy (THIS->__retvalue, CONTEXT->probe_point, MAXSTRINGLEN); +%} diff --git a/tapsets.cxx b/tapsets.cxx index 140313081..de80d3a24 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -38,6 +38,51 @@ extern "C" { using namespace std; + +// XXX: should standardize to these functions throughout translator + +template inline OUT +lex_cast(IN const & in) +{ + stringstream ss; + OUT out; + if (!(ss << in && ss >> out)) + throw runtime_error("bad lexical cast"); + return out; +} + +template inline OUT +lex_cast_hex(IN const & in) +{ + stringstream ss; + OUT out; + if (!(ss << hex << showbase << in && ss >> out)) + throw runtime_error("bad lexical cast"); + return out; +} + + +// return as quoted string, with at least '"' backslash-escaped +template inline string +lex_cast_qstring(IN const & in) +{ + stringstream ss; + string out, out2; + if (!(ss << in && ss >> out)) + throw runtime_error("bad lexical cast"); + + out2 += '"'; + for (unsigned i=0; inewline(1) << "struct context* c = & contexts [smp_processor_id()];"; + o->newline() << "const char* probe_point = " + << lex_cast_qstring(*l) << ";"; // A precondition for running a probe handler is that we're in STARTING // or STOPPING state (not ERROR), and that no one else is already using @@ -110,16 +157,15 @@ be_derived_probe::emit_probe_entries (translator_output* o, unsigned j) if (begin) o->line() << "STAP_SESSION_STARTING)"; else o->line() << "STAP_SESSION_STOPPING)"; o->newline(1) << "return;"; - o->newline(-1) << "if (c->busy) {"; - o->newline(1) << "printk (KERN_ERR \"probe reentrancy\");"; + o->newline(-1) << "if (atomic_inc_return (&c->busy) != 1) {"; + o->newline(1) << "printk (KERN_ERR \"probe reentrancy (%s vs %s)\", " + << "c->probe_point, probe_point);"; o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline() << "return;"; o->newline(-1) << "}"; o->newline(); - - o->newline() << "c->busy ++;"; - o->newline() << "mb ();"; // for smp o->newline() << "c->last_error = 0;"; + o->newline() << "c->probe_point = probe_point;"; o->newline() << "c->nesting = 0;"; o->newline() << "c->regs = 0;"; o->newline() << "c->actioncount = 0;"; @@ -132,8 +178,7 @@ be_derived_probe::emit_probe_entries (translator_output* o, unsigned j) o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; - o->newline() << "c->busy --;"; - o->newline() << "mb ();"; + o->newline() << "atomic_dec (&c->busy);"; o->newline(-1) << "}" << endl; } } @@ -156,27 +201,7 @@ static string TOK_LABEL("label"); static string TOK_RELATIVE("relative"); -// XXX: should standardize to these functions throughout translator -template inline OUT -lex_cast(IN const & in) -{ - stringstream ss; - OUT out; - if (!(ss << in && ss >> out)) - throw runtime_error("bad lexical cast"); - return out; -} - -template inline OUT -lex_cast_hex(IN const & in) -{ - stringstream ss; - OUT out; - if (!(ss << hex << showbase << in && ss >> out)) - throw runtime_error("bad lexical cast"); - return out; -} struct func_info @@ -1973,7 +1998,6 @@ dwarf_derived_probe::emit_deregistrations (translator_output* o, unsigned proben void dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum) { - // Construct a single entry function, and a struct kprobe pointing into // the entry function. The entry function will call the probe function. o->newline(); @@ -1985,22 +2009,23 @@ dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum o->line() << "struct kprobe *_ignored"; o->line() << ", struct pt_regs *regs) {"; o->newline(1) << "struct context *c = & contexts [smp_processor_id()];"; - o->newline(); + o->newline() << "const char* probe_point = " + << lex_cast_qstring(*locations[0]) << ";"; // A precondition for running a probe handler is that we're in RUNNING // state (not ERROR), and that no one else is already using this context. o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)"; o->newline(1) << "return 0;"; - o->newline(-1) << "if (c->busy) {"; - o->newline(1) << "printk (KERN_ERR \"probe reentrancy\");"; + o->newline(-1) << "if (atomic_inc_return (&c->busy) != 1) {"; + o->newline(1) << "printk (KERN_ERR \"probe reentrancy (%s vs %s)\", " + << "c->probe_point, probe_point);"; o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline() << "return 0;"; o->newline(-1) << "}"; o->newline(); - o->newline() << "c->busy ++;"; - o->newline() << "mb ();"; // for smp o->newline() << "c->last_error = 0;"; + o->newline() << "c->probe_point = probe_point;"; o->newline() << "c->nesting = 0;"; o->newline() << "c->regs = regs;"; o->newline() << "c->actioncount = 0;"; @@ -2013,9 +2038,7 @@ dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; - o->newline() << "c->busy --;"; - o->newline() << "mb ();"; - + o->newline() << "atomic_dec (& c->busy);"; o->newline() << "return 0;"; o->newline(-1) << "}" << endl; @@ -2140,7 +2163,8 @@ timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) o->newline() << "void enter_" << j << " (unsigned long val) {"; o->newline(1) << "struct context* c = & contexts [smp_processor_id()];"; - + o->newline() << "const char* probe_point = " + << lex_cast_qstring(*locations[0]) << ";"; o->newline() << "(void) val;"; // A precondition for running a probe handler is that we're in @@ -2149,8 +2173,9 @@ timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)"; o->newline(1) << "return;"; - o->newline(-1) << "if (c->busy) {"; - o->newline(1) << "printk (KERN_ERR \"probe reentrancy\");"; + o->newline(-1) << "if (atomic_inc_return (&c->busy) != 1) {"; + o->newline(1) << "printk (KERN_ERR \"probe reentrancy (%s vs %s)\", " + << "c->probe_point, probe_point);"; o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline() << "return;"; o->newline(-1) << "}"; @@ -2162,11 +2187,10 @@ timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) o->line() << " + _stp_random_pm(" << randomize << ")"; o->line() << ");"; - o->newline() << "c->busy ++;"; - o->newline() << "mb ();"; // for smp + o->newline() << "c->probe_point = probe_point;"; o->newline() << "c->last_error = 0;"; o->newline() << "c->nesting = 0;"; - o->newline() << "if (! in_interrupt())"; + o->newline() << "if (in_interrupt())"; o->newline(1) << "c->regs = 0;"; o->newline(-1) << "else"; o->newline(1) << "c->regs = task_pt_regs (current);"; @@ -2181,8 +2205,7 @@ timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; - o->newline() << "c->busy --;"; - o->newline() << "mb ();"; + o->newline() << "atomic_dec (&c->busy);"; o->newline(-1) << "}" << endl; } diff --git a/testsuite/buildok/context_test.stp b/testsuite/buildok/context_test.stp index 9059c04ce..c85bce67d 100755 --- a/testsuite/buildok/context_test.stp +++ b/testsuite/buildok/context_test.stp @@ -1,7 +1,6 @@ #! stap -p4 -probe kernel.function("uptime_read_proc") { - print("NOW IN UPTIME\n") +function print_stuff () { print_regs() print_backtrace() bt = backtrace() @@ -9,33 +8,26 @@ probe kernel.function("uptime_read_proc") { print("\n\n") print_stack(bt) print("\n\n") - log("name is " . execname()) + log("execname is \"" . execname() . "\"") log("pid is " . string(pid())) - log("parentname is " . pexecname()) + log("pexecname is \"" . pexecname() . "\"") log("ppid is " . string(ppid())) log("uid is " . string(uid())) log("euid is " . string(euid())) log("gid is " . string(gid())) log("egid is " . string(egid())) + log("pp is '" . pp() . "'") +} + +probe kernel.function("uptime_read_proc") { + print("NOW IN UPTIME\n") + print_stuff () } probe kernel.function("uptime_read_proc").return { print("DONE WITH UPTIME\n") - print_regs() - print_backtrace() - bt = backtrace() - print("the stack is " . bt) - print("\n\n") - print_stack(bt) - print("\n\n") - log("name is " . execname()) - log("pid is " . string(pid())) - log("parentname is " . pexecname()) - log("ppid is " . string(ppid())) - log("uid is " . string(uid())) - log("euid is " . string(euid())) - log("gid is " . string(gid())) - log("egid is " . string(egid())) + print_stuff () + exit () } probe begin { diff --git a/translate.cxx b/translate.cxx index c3412cda8..b71ef3794 100644 --- a/translate.cxx +++ b/translate.cxx @@ -30,6 +30,27 @@ stringify(T t) return s.str (); } +// return as quoted string, with at least '"' backslash-escaped +template inline string +lex_cast_qstring(IN const & in) +{ + stringstream ss; + string out, out2; + if (!(ss << in && ss >> out)) + throw runtime_error("bad lexical cast"); + + out2 += '"'; + for (unsigned i=0; inewline() << "atomic_t session_state = ATOMIC_INIT (STAP_SESSION_STARTING);"; o->newline(); o->newline() << "struct context {"; - o->newline(1) << "unsigned busy;"; // XXX: should be atomic_t ? + o->newline(1) << "atomic_t busy;"; + o->newline() << "const char *probe_point;"; o->newline() << "unsigned actioncount;"; o->newline() << "unsigned nesting;"; o->newline() << "const char *last_error;"; @@ -779,14 +801,13 @@ c_unparser::emit_module_exit () o->newline() << "do {"; o->newline(1) << "int i;"; o->newline() << "holdon = 0;"; - o->newline() << "mb ();"; o->newline() << "for (i=0; inewline(1) << "if (contexts[i].busy) holdon = 1;"; + o->newline(1) << "if (atomic_read (&contexts[i].busy)) holdon = 1;"; // o->newline(-1) << "if (holdon) msleep (5);"; o->newline(-1) << "} while (holdon);"; o->newline(-1); // XXX: might like to have an escape hatch, in case some probe is - // genuinely stuck + // genuinely stuck somehow for (int i=session->probes.size()-1; i>=0; i--) session->probes[i]->emit_deregistrations (o, i); @@ -797,7 +818,6 @@ c_unparser::emit_module_exit () if (v->index_types.size() > 0) o->newline() << getmap (v).fini(); } - // XXX: if anyrc, log badness o->newline(-1) << "}" << endl; } @@ -1335,7 +1355,7 @@ c_unparser::visit_statement (statement *s, unsigned actions) o->newline() << "if (unlikely (c->last_error)) goto " << outlabel << ";"; assert (s->tok); - o->newline() << "c->last_stmt = \"" << *s->tok << "\";"; + o->newline() << "c->last_stmt = " << lex_cast_qstring(*s->tok) << ";"; if (actions > 0) { o->newline() << "c->actioncount += " << actions << ";"; @@ -1709,9 +1729,7 @@ c_unparser::visit_binary_expression (binary_expression* e) tmpvar right = gensym (pe_long); o->line() << "({"; - - o->newline() << "c->last_stmt = \"" << *e->tok << "\";"; - + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; o->newline(1) << left << " = "; e->left->visit (this); o->line() << ";"; @@ -1800,7 +1818,7 @@ c_unparser::visit_array_in (array_in* e) vector idx; load_map_indices (e->operand, idx); - o->newline() << "c->last_stmt = \"" << *e->tok << "\";"; + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; tmpvar res = gensym (pe_long); @@ -1878,7 +1896,7 @@ c_unparser::visit_concatenation (concatenation* e) o->line() << "({ "; o->indent(1); - o->newline() << "c->last_stmt = \"" << *e->tok << "\";"; + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; c_assign (t.qname(), e->left, "assignment"); c_strcat (t.qname(), e->right); o->newline() << t << ";"; @@ -2045,7 +2063,7 @@ c_unparser_assignment::visit_symbol (symbol *e) if (e->referent->index_types.size() != 0) throw semantic_error ("unexpected reference to array", e->tok); - parent->o->newline() << "c->last_stmt = \"" << *e->tok << "\";"; + parent->o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; tmpvar rval = parent->gensym (e->type); tmpvar res = parent->gensym (e->type); @@ -2105,7 +2123,8 @@ c_unparser::load_map_indices(arrayindex *e, throw semantic_error ("array index type mismatch", e->indexes[i]->tok); tmpvar ix = gensym (r->index_types[i]); - o->newline() << "c->last_stmt = \"" << *e->indexes[i]->tok << "\";"; + o->newline() << "c->last_stmt = " + << lex_cast_qstring(*e->indexes[i]->tok) << ";"; c_assign (ix.qname(), e->indexes[i], "array index copy"); idx.push_back (ix); } @@ -2141,7 +2160,7 @@ c_unparser::visit_arrayindex (arrayindex* e) { // block used to control varlock_r lifespan mapvar mvar = getmap (e->referent, e->tok); // XXX: should be varlock_r, but runtime arrays reads mutate - o->newline() << "c->last_stmt = \"" << *e->tok << "\";"; + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; varlock_w guard (*this, mvar); o->newline() << mvar.seek (idx) << ";"; c_assign (res, mvar.get(), e->tok); @@ -2218,7 +2237,7 @@ c_unparser_assignment::visit_arrayindex (arrayindex *e) { // block used to control varlock_w lifespan mapvar mvar = parent->getmap (e->referent, e->tok); - o->newline() << "c->last_stmt = \"" << *e->tok << "\";"; + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; varlock_w guard (*parent, mvar); o->newline() << mvar.seek (idx) << ";"; if (op != "=") // don't bother fetch slot if we will just overwrite it @@ -2273,14 +2292,15 @@ c_unparser::visit_functioncall (functioncall* e) throw semantic_error ("function argument type mismatch", e->args[i]->tok, "vs", r->formal_args[i]->tok); - o->newline() << "c->last_stmt = \"" << *e->args[i]->tok << "\";"; + o->newline() << "c->last_stmt = " + << lex_cast_qstring(*e->args[i]->tok) << ";"; c_assign (t.qname(), e->args[i], "function actual argument evaluation"); } o->newline(); o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) {"; o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";"; - o->newline() << "c->last_stmt = \"" << *e->tok << "\";"; + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; o->newline(-1) << "} else if (likely (! c->last_error)) {"; o->indent(1); -- 2.43.5