1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * trace-event-perl. Feed perf script events to an embedded Perl interpreter.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
7*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
8*4882a593Smuzhiyun * the Free Software Foundation; either version 2 of the License, or
9*4882a593Smuzhiyun * (at your option) any later version.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
12*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*4882a593Smuzhiyun * GNU General Public License for more details.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License
17*4882a593Smuzhiyun * along with this program; if not, write to the Free Software
18*4882a593Smuzhiyun * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <inttypes.h>
23*4882a593Smuzhiyun #include <stdio.h>
24*4882a593Smuzhiyun #include <stdlib.h>
25*4882a593Smuzhiyun #include <string.h>
26*4882a593Smuzhiyun #include <ctype.h>
27*4882a593Smuzhiyun #include <errno.h>
28*4882a593Smuzhiyun #include <linux/bitmap.h>
29*4882a593Smuzhiyun #include <linux/time64.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <stdbool.h>
32*4882a593Smuzhiyun /* perl needs the following define, right after including stdbool.h */
33*4882a593Smuzhiyun #define HAS_BOOL
34*4882a593Smuzhiyun #include <EXTERN.h>
35*4882a593Smuzhiyun #include <perl.h>
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include "../callchain.h"
38*4882a593Smuzhiyun #include "../dso.h"
39*4882a593Smuzhiyun #include "../machine.h"
40*4882a593Smuzhiyun #include "../map.h"
41*4882a593Smuzhiyun #include "../symbol.h"
42*4882a593Smuzhiyun #include "../thread.h"
43*4882a593Smuzhiyun #include "../event.h"
44*4882a593Smuzhiyun #include "../trace-event.h"
45*4882a593Smuzhiyun #include "../evsel.h"
46*4882a593Smuzhiyun #include "../debug.h"
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun void boot_Perf__Trace__Context(pTHX_ CV *cv);
49*4882a593Smuzhiyun void boot_DynaLoader(pTHX_ CV *cv);
50*4882a593Smuzhiyun typedef PerlInterpreter * INTERP;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun void xs_init(pTHX);
53*4882a593Smuzhiyun
xs_init(pTHX)54*4882a593Smuzhiyun void xs_init(pTHX)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun const char *file = __FILE__;
57*4882a593Smuzhiyun dXSUB_SYS;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
60*4882a593Smuzhiyun file);
61*4882a593Smuzhiyun newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun INTERP my_perl;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #define TRACE_EVENT_TYPE_MAX \
67*4882a593Smuzhiyun ((1 << (sizeof(unsigned short) * 8)) - 1)
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static DECLARE_BITMAP(events_defined, TRACE_EVENT_TYPE_MAX);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun extern struct scripting_context *scripting_context;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun static char *cur_field_name;
74*4882a593Smuzhiyun static int zero_flag_atom;
75*4882a593Smuzhiyun
define_symbolic_value(const char * ev_name,const char * field_name,const char * field_value,const char * field_str)76*4882a593Smuzhiyun static void define_symbolic_value(const char *ev_name,
77*4882a593Smuzhiyun const char *field_name,
78*4882a593Smuzhiyun const char *field_value,
79*4882a593Smuzhiyun const char *field_str)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun unsigned long long value;
82*4882a593Smuzhiyun dSP;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun value = eval_flag(field_value);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun ENTER;
87*4882a593Smuzhiyun SAVETMPS;
88*4882a593Smuzhiyun PUSHMARK(SP);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
91*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
92*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(value)));
93*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun PUTBACK;
96*4882a593Smuzhiyun if (get_cv("main::define_symbolic_value", 0))
97*4882a593Smuzhiyun call_pv("main::define_symbolic_value", G_SCALAR);
98*4882a593Smuzhiyun SPAGAIN;
99*4882a593Smuzhiyun PUTBACK;
100*4882a593Smuzhiyun FREETMPS;
101*4882a593Smuzhiyun LEAVE;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
define_symbolic_values(struct tep_print_flag_sym * field,const char * ev_name,const char * field_name)104*4882a593Smuzhiyun static void define_symbolic_values(struct tep_print_flag_sym *field,
105*4882a593Smuzhiyun const char *ev_name,
106*4882a593Smuzhiyun const char *field_name)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun define_symbolic_value(ev_name, field_name, field->value, field->str);
109*4882a593Smuzhiyun if (field->next)
110*4882a593Smuzhiyun define_symbolic_values(field->next, ev_name, field_name);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
define_symbolic_field(const char * ev_name,const char * field_name)113*4882a593Smuzhiyun static void define_symbolic_field(const char *ev_name,
114*4882a593Smuzhiyun const char *field_name)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun dSP;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun ENTER;
119*4882a593Smuzhiyun SAVETMPS;
120*4882a593Smuzhiyun PUSHMARK(SP);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
123*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun PUTBACK;
126*4882a593Smuzhiyun if (get_cv("main::define_symbolic_field", 0))
127*4882a593Smuzhiyun call_pv("main::define_symbolic_field", G_SCALAR);
128*4882a593Smuzhiyun SPAGAIN;
129*4882a593Smuzhiyun PUTBACK;
130*4882a593Smuzhiyun FREETMPS;
131*4882a593Smuzhiyun LEAVE;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
define_flag_value(const char * ev_name,const char * field_name,const char * field_value,const char * field_str)134*4882a593Smuzhiyun static void define_flag_value(const char *ev_name,
135*4882a593Smuzhiyun const char *field_name,
136*4882a593Smuzhiyun const char *field_value,
137*4882a593Smuzhiyun const char *field_str)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun unsigned long long value;
140*4882a593Smuzhiyun dSP;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun value = eval_flag(field_value);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun ENTER;
145*4882a593Smuzhiyun SAVETMPS;
146*4882a593Smuzhiyun PUSHMARK(SP);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
149*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
150*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(value)));
151*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun PUTBACK;
154*4882a593Smuzhiyun if (get_cv("main::define_flag_value", 0))
155*4882a593Smuzhiyun call_pv("main::define_flag_value", G_SCALAR);
156*4882a593Smuzhiyun SPAGAIN;
157*4882a593Smuzhiyun PUTBACK;
158*4882a593Smuzhiyun FREETMPS;
159*4882a593Smuzhiyun LEAVE;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
define_flag_values(struct tep_print_flag_sym * field,const char * ev_name,const char * field_name)162*4882a593Smuzhiyun static void define_flag_values(struct tep_print_flag_sym *field,
163*4882a593Smuzhiyun const char *ev_name,
164*4882a593Smuzhiyun const char *field_name)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun define_flag_value(ev_name, field_name, field->value, field->str);
167*4882a593Smuzhiyun if (field->next)
168*4882a593Smuzhiyun define_flag_values(field->next, ev_name, field_name);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
define_flag_field(const char * ev_name,const char * field_name,const char * delim)171*4882a593Smuzhiyun static void define_flag_field(const char *ev_name,
172*4882a593Smuzhiyun const char *field_name,
173*4882a593Smuzhiyun const char *delim)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun dSP;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun ENTER;
178*4882a593Smuzhiyun SAVETMPS;
179*4882a593Smuzhiyun PUSHMARK(SP);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
182*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
183*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(delim, 0)));
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun PUTBACK;
186*4882a593Smuzhiyun if (get_cv("main::define_flag_field", 0))
187*4882a593Smuzhiyun call_pv("main::define_flag_field", G_SCALAR);
188*4882a593Smuzhiyun SPAGAIN;
189*4882a593Smuzhiyun PUTBACK;
190*4882a593Smuzhiyun FREETMPS;
191*4882a593Smuzhiyun LEAVE;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
define_event_symbols(struct tep_event * event,const char * ev_name,struct tep_print_arg * args)194*4882a593Smuzhiyun static void define_event_symbols(struct tep_event *event,
195*4882a593Smuzhiyun const char *ev_name,
196*4882a593Smuzhiyun struct tep_print_arg *args)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun if (args == NULL)
199*4882a593Smuzhiyun return;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun switch (args->type) {
202*4882a593Smuzhiyun case TEP_PRINT_NULL:
203*4882a593Smuzhiyun break;
204*4882a593Smuzhiyun case TEP_PRINT_ATOM:
205*4882a593Smuzhiyun define_flag_value(ev_name, cur_field_name, "0",
206*4882a593Smuzhiyun args->atom.atom);
207*4882a593Smuzhiyun zero_flag_atom = 0;
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun case TEP_PRINT_FIELD:
210*4882a593Smuzhiyun free(cur_field_name);
211*4882a593Smuzhiyun cur_field_name = strdup(args->field.name);
212*4882a593Smuzhiyun break;
213*4882a593Smuzhiyun case TEP_PRINT_FLAGS:
214*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->flags.field);
215*4882a593Smuzhiyun define_flag_field(ev_name, cur_field_name, args->flags.delim);
216*4882a593Smuzhiyun define_flag_values(args->flags.flags, ev_name, cur_field_name);
217*4882a593Smuzhiyun break;
218*4882a593Smuzhiyun case TEP_PRINT_SYMBOL:
219*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->symbol.field);
220*4882a593Smuzhiyun define_symbolic_field(ev_name, cur_field_name);
221*4882a593Smuzhiyun define_symbolic_values(args->symbol.symbols, ev_name,
222*4882a593Smuzhiyun cur_field_name);
223*4882a593Smuzhiyun break;
224*4882a593Smuzhiyun case TEP_PRINT_HEX:
225*4882a593Smuzhiyun case TEP_PRINT_HEX_STR:
226*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->hex.field);
227*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->hex.size);
228*4882a593Smuzhiyun break;
229*4882a593Smuzhiyun case TEP_PRINT_INT_ARRAY:
230*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->int_array.field);
231*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->int_array.count);
232*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->int_array.el_size);
233*4882a593Smuzhiyun break;
234*4882a593Smuzhiyun case TEP_PRINT_BSTRING:
235*4882a593Smuzhiyun case TEP_PRINT_DYNAMIC_ARRAY:
236*4882a593Smuzhiyun case TEP_PRINT_DYNAMIC_ARRAY_LEN:
237*4882a593Smuzhiyun case TEP_PRINT_STRING:
238*4882a593Smuzhiyun case TEP_PRINT_BITMASK:
239*4882a593Smuzhiyun break;
240*4882a593Smuzhiyun case TEP_PRINT_TYPE:
241*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->typecast.item);
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun case TEP_PRINT_OP:
244*4882a593Smuzhiyun if (strcmp(args->op.op, ":") == 0)
245*4882a593Smuzhiyun zero_flag_atom = 1;
246*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->op.left);
247*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->op.right);
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun case TEP_PRINT_FUNC:
250*4882a593Smuzhiyun default:
251*4882a593Smuzhiyun pr_err("Unsupported print arg type\n");
252*4882a593Smuzhiyun /* we should warn... */
253*4882a593Smuzhiyun return;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if (args->next)
257*4882a593Smuzhiyun define_event_symbols(event, ev_name, args->next);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
perl_process_callchain(struct perf_sample * sample,struct evsel * evsel,struct addr_location * al)260*4882a593Smuzhiyun static SV *perl_process_callchain(struct perf_sample *sample,
261*4882a593Smuzhiyun struct evsel *evsel,
262*4882a593Smuzhiyun struct addr_location *al)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun AV *list;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun list = newAV();
267*4882a593Smuzhiyun if (!list)
268*4882a593Smuzhiyun goto exit;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (!symbol_conf.use_callchain || !sample->callchain)
271*4882a593Smuzhiyun goto exit;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
274*4882a593Smuzhiyun sample, NULL, NULL, scripting_max_stack) != 0) {
275*4882a593Smuzhiyun pr_err("Failed to resolve callchain. Skipping\n");
276*4882a593Smuzhiyun goto exit;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun callchain_cursor_commit(&callchain_cursor);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun while (1) {
282*4882a593Smuzhiyun HV *elem;
283*4882a593Smuzhiyun struct callchain_cursor_node *node;
284*4882a593Smuzhiyun node = callchain_cursor_current(&callchain_cursor);
285*4882a593Smuzhiyun if (!node)
286*4882a593Smuzhiyun break;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun elem = newHV();
289*4882a593Smuzhiyun if (!elem)
290*4882a593Smuzhiyun goto exit;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun if (!hv_stores(elem, "ip", newSVuv(node->ip))) {
293*4882a593Smuzhiyun hv_undef(elem);
294*4882a593Smuzhiyun goto exit;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun if (node->ms.sym) {
298*4882a593Smuzhiyun HV *sym = newHV();
299*4882a593Smuzhiyun if (!sym) {
300*4882a593Smuzhiyun hv_undef(elem);
301*4882a593Smuzhiyun goto exit;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun if (!hv_stores(sym, "start", newSVuv(node->ms.sym->start)) ||
304*4882a593Smuzhiyun !hv_stores(sym, "end", newSVuv(node->ms.sym->end)) ||
305*4882a593Smuzhiyun !hv_stores(sym, "binding", newSVuv(node->ms.sym->binding)) ||
306*4882a593Smuzhiyun !hv_stores(sym, "name", newSVpvn(node->ms.sym->name,
307*4882a593Smuzhiyun node->ms.sym->namelen)) ||
308*4882a593Smuzhiyun !hv_stores(elem, "sym", newRV_noinc((SV*)sym))) {
309*4882a593Smuzhiyun hv_undef(sym);
310*4882a593Smuzhiyun hv_undef(elem);
311*4882a593Smuzhiyun goto exit;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun if (node->ms.map) {
316*4882a593Smuzhiyun struct map *map = node->ms.map;
317*4882a593Smuzhiyun const char *dsoname = "[unknown]";
318*4882a593Smuzhiyun if (map && map->dso) {
319*4882a593Smuzhiyun if (symbol_conf.show_kernel_path && map->dso->long_name)
320*4882a593Smuzhiyun dsoname = map->dso->long_name;
321*4882a593Smuzhiyun else
322*4882a593Smuzhiyun dsoname = map->dso->name;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) {
325*4882a593Smuzhiyun hv_undef(elem);
326*4882a593Smuzhiyun goto exit;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun callchain_cursor_advance(&callchain_cursor);
331*4882a593Smuzhiyun av_push(list, newRV_noinc((SV*)elem));
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun exit:
335*4882a593Smuzhiyun return newRV_noinc((SV*)list);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
perl_process_tracepoint(struct perf_sample * sample,struct evsel * evsel,struct addr_location * al)338*4882a593Smuzhiyun static void perl_process_tracepoint(struct perf_sample *sample,
339*4882a593Smuzhiyun struct evsel *evsel,
340*4882a593Smuzhiyun struct addr_location *al)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun struct thread *thread = al->thread;
343*4882a593Smuzhiyun struct tep_event *event = evsel->tp_format;
344*4882a593Smuzhiyun struct tep_format_field *field;
345*4882a593Smuzhiyun static char handler[256];
346*4882a593Smuzhiyun unsigned long long val;
347*4882a593Smuzhiyun unsigned long s, ns;
348*4882a593Smuzhiyun int pid;
349*4882a593Smuzhiyun int cpu = sample->cpu;
350*4882a593Smuzhiyun void *data = sample->raw_data;
351*4882a593Smuzhiyun unsigned long long nsecs = sample->time;
352*4882a593Smuzhiyun const char *comm = thread__comm_str(thread);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun dSP;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
357*4882a593Smuzhiyun return;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (!event) {
360*4882a593Smuzhiyun pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config);
361*4882a593Smuzhiyun return;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun pid = raw_field_value(event, "common_pid", data);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun sprintf(handler, "%s::%s", event->system, event->name);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (!test_and_set_bit(event->id, events_defined))
369*4882a593Smuzhiyun define_event_symbols(event, handler, event->print_fmt.args);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun s = nsecs / NSEC_PER_SEC;
372*4882a593Smuzhiyun ns = nsecs - s * NSEC_PER_SEC;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun scripting_context->event_data = data;
375*4882a593Smuzhiyun scripting_context->pevent = evsel->tp_format->tep;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun ENTER;
378*4882a593Smuzhiyun SAVETMPS;
379*4882a593Smuzhiyun PUSHMARK(SP);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(handler, 0)));
382*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
383*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(cpu)));
384*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(s)));
385*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(ns)));
386*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSViv(pid)));
387*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(comm, 0)));
388*4882a593Smuzhiyun XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /* common fields other than pid can be accessed via xsub fns */
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun for (field = event->format.fields; field; field = field->next) {
393*4882a593Smuzhiyun if (field->flags & TEP_FIELD_IS_STRING) {
394*4882a593Smuzhiyun int offset;
395*4882a593Smuzhiyun if (field->flags & TEP_FIELD_IS_DYNAMIC) {
396*4882a593Smuzhiyun offset = *(int *)(data + field->offset);
397*4882a593Smuzhiyun offset &= 0xffff;
398*4882a593Smuzhiyun } else
399*4882a593Smuzhiyun offset = field->offset;
400*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
401*4882a593Smuzhiyun } else { /* FIELD_IS_NUMERIC */
402*4882a593Smuzhiyun val = read_size(event, data + field->offset,
403*4882a593Smuzhiyun field->size);
404*4882a593Smuzhiyun if (field->flags & TEP_FIELD_IS_SIGNED) {
405*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSViv(val)));
406*4882a593Smuzhiyun } else {
407*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(val)));
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun PUTBACK;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if (get_cv(handler, 0))
415*4882a593Smuzhiyun call_pv(handler, G_SCALAR);
416*4882a593Smuzhiyun else if (get_cv("main::trace_unhandled", 0)) {
417*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(handler, 0)));
418*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
419*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(cpu)));
420*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVuv(nsecs)));
421*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSViv(pid)));
422*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpv(comm, 0)));
423*4882a593Smuzhiyun XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));
424*4882a593Smuzhiyun call_pv("main::trace_unhandled", G_SCALAR);
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun SPAGAIN;
427*4882a593Smuzhiyun PUTBACK;
428*4882a593Smuzhiyun FREETMPS;
429*4882a593Smuzhiyun LEAVE;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
perl_process_event_generic(union perf_event * event,struct perf_sample * sample,struct evsel * evsel)432*4882a593Smuzhiyun static void perl_process_event_generic(union perf_event *event,
433*4882a593Smuzhiyun struct perf_sample *sample,
434*4882a593Smuzhiyun struct evsel *evsel)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun dSP;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (!get_cv("process_event", 0))
439*4882a593Smuzhiyun return;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun ENTER;
442*4882a593Smuzhiyun SAVETMPS;
443*4882a593Smuzhiyun PUSHMARK(SP);
444*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size)));
445*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->core.attr, sizeof(evsel->core.attr))));
446*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample))));
447*4882a593Smuzhiyun XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size)));
448*4882a593Smuzhiyun PUTBACK;
449*4882a593Smuzhiyun call_pv("process_event", G_SCALAR);
450*4882a593Smuzhiyun SPAGAIN;
451*4882a593Smuzhiyun PUTBACK;
452*4882a593Smuzhiyun FREETMPS;
453*4882a593Smuzhiyun LEAVE;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
perl_process_event(union perf_event * event,struct perf_sample * sample,struct evsel * evsel,struct addr_location * al)456*4882a593Smuzhiyun static void perl_process_event(union perf_event *event,
457*4882a593Smuzhiyun struct perf_sample *sample,
458*4882a593Smuzhiyun struct evsel *evsel,
459*4882a593Smuzhiyun struct addr_location *al)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun perl_process_tracepoint(sample, evsel, al);
462*4882a593Smuzhiyun perl_process_event_generic(event, sample, evsel);
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
run_start_sub(void)465*4882a593Smuzhiyun static void run_start_sub(void)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun dSP; /* access to Perl stack */
468*4882a593Smuzhiyun PUSHMARK(SP);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (get_cv("main::trace_begin", 0))
471*4882a593Smuzhiyun call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun /*
475*4882a593Smuzhiyun * Start trace script
476*4882a593Smuzhiyun */
perl_start_script(const char * script,int argc,const char ** argv)477*4882a593Smuzhiyun static int perl_start_script(const char *script, int argc, const char **argv)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun const char **command_line;
480*4882a593Smuzhiyun int i, err = 0;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun command_line = malloc((argc + 2) * sizeof(const char *));
483*4882a593Smuzhiyun command_line[0] = "";
484*4882a593Smuzhiyun command_line[1] = script;
485*4882a593Smuzhiyun for (i = 2; i < argc + 2; i++)
486*4882a593Smuzhiyun command_line[i] = argv[i - 2];
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun my_perl = perl_alloc();
489*4882a593Smuzhiyun perl_construct(my_perl);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
492*4882a593Smuzhiyun (char **)NULL)) {
493*4882a593Smuzhiyun err = -1;
494*4882a593Smuzhiyun goto error;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (perl_run(my_perl)) {
498*4882a593Smuzhiyun err = -1;
499*4882a593Smuzhiyun goto error;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun if (SvTRUE(ERRSV)) {
503*4882a593Smuzhiyun err = -1;
504*4882a593Smuzhiyun goto error;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun run_start_sub();
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun free(command_line);
510*4882a593Smuzhiyun return 0;
511*4882a593Smuzhiyun error:
512*4882a593Smuzhiyun perl_free(my_perl);
513*4882a593Smuzhiyun free(command_line);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun return err;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
perl_flush_script(void)518*4882a593Smuzhiyun static int perl_flush_script(void)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun return 0;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /*
524*4882a593Smuzhiyun * Stop trace script
525*4882a593Smuzhiyun */
perl_stop_script(void)526*4882a593Smuzhiyun static int perl_stop_script(void)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun dSP; /* access to Perl stack */
529*4882a593Smuzhiyun PUSHMARK(SP);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun if (get_cv("main::trace_end", 0))
532*4882a593Smuzhiyun call_pv("main::trace_end", G_DISCARD | G_NOARGS);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun perl_destruct(my_perl);
535*4882a593Smuzhiyun perl_free(my_perl);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun return 0;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
perl_generate_script(struct tep_handle * pevent,const char * outfile)540*4882a593Smuzhiyun static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun int i, not_first, count, nr_events;
543*4882a593Smuzhiyun struct tep_event **all_events;
544*4882a593Smuzhiyun struct tep_event *event = NULL;
545*4882a593Smuzhiyun struct tep_format_field *f;
546*4882a593Smuzhiyun char fname[PATH_MAX];
547*4882a593Smuzhiyun FILE *ofp;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun sprintf(fname, "%s.pl", outfile);
550*4882a593Smuzhiyun ofp = fopen(fname, "w");
551*4882a593Smuzhiyun if (ofp == NULL) {
552*4882a593Smuzhiyun fprintf(stderr, "couldn't open %s\n", fname);
553*4882a593Smuzhiyun return -1;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun fprintf(ofp, "# perf script event handlers, "
557*4882a593Smuzhiyun "generated by perf script -g perl\n");
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun fprintf(ofp, "# Licensed under the terms of the GNU GPL"
560*4882a593Smuzhiyun " License version 2\n\n");
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun fprintf(ofp, "# The common_* event handler fields are the most useful "
563*4882a593Smuzhiyun "fields common to\n");
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun fprintf(ofp, "# all events. They don't necessarily correspond to "
566*4882a593Smuzhiyun "the 'common_*' fields\n");
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun fprintf(ofp, "# in the format files. Those fields not available as "
569*4882a593Smuzhiyun "handler params can\n");
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun fprintf(ofp, "# be retrieved using Perl functions of the form "
572*4882a593Smuzhiyun "common_*($context).\n");
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun fprintf(ofp, "# See Context.pm for the list of available "
575*4882a593Smuzhiyun "functions.\n\n");
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
578*4882a593Smuzhiyun "Perf-Trace-Util/lib\";\n");
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
581*4882a593Smuzhiyun fprintf(ofp, "use Perf::Trace::Core;\n");
582*4882a593Smuzhiyun fprintf(ofp, "use Perf::Trace::Context;\n");
583*4882a593Smuzhiyun fprintf(ofp, "use Perf::Trace::Util;\n\n");
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
586*4882a593Smuzhiyun fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n");
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun fprintf(ofp, "\n\
590*4882a593Smuzhiyun sub print_backtrace\n\
591*4882a593Smuzhiyun {\n\
592*4882a593Smuzhiyun my $callchain = shift;\n\
593*4882a593Smuzhiyun for my $node (@$callchain)\n\
594*4882a593Smuzhiyun {\n\
595*4882a593Smuzhiyun if(exists $node->{sym})\n\
596*4882a593Smuzhiyun {\n\
597*4882a593Smuzhiyun printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\
598*4882a593Smuzhiyun }\n\
599*4882a593Smuzhiyun else\n\
600*4882a593Smuzhiyun {\n\
601*4882a593Smuzhiyun printf( \"\\t[\\%%x]\\n\", $node{ip});\n\
602*4882a593Smuzhiyun }\n\
603*4882a593Smuzhiyun }\n\
604*4882a593Smuzhiyun }\n\n\
605*4882a593Smuzhiyun ");
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun nr_events = tep_get_events_count(pevent);
608*4882a593Smuzhiyun all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun for (i = 0; all_events && i < nr_events; i++) {
611*4882a593Smuzhiyun event = all_events[i];
612*4882a593Smuzhiyun fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
613*4882a593Smuzhiyun fprintf(ofp, "\tmy (");
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun fprintf(ofp, "$event_name, ");
616*4882a593Smuzhiyun fprintf(ofp, "$context, ");
617*4882a593Smuzhiyun fprintf(ofp, "$common_cpu, ");
618*4882a593Smuzhiyun fprintf(ofp, "$common_secs, ");
619*4882a593Smuzhiyun fprintf(ofp, "$common_nsecs,\n");
620*4882a593Smuzhiyun fprintf(ofp, "\t $common_pid, ");
621*4882a593Smuzhiyun fprintf(ofp, "$common_comm, ");
622*4882a593Smuzhiyun fprintf(ofp, "$common_callchain,\n\t ");
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun not_first = 0;
625*4882a593Smuzhiyun count = 0;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun for (f = event->format.fields; f; f = f->next) {
628*4882a593Smuzhiyun if (not_first++)
629*4882a593Smuzhiyun fprintf(ofp, ", ");
630*4882a593Smuzhiyun if (++count % 5 == 0)
631*4882a593Smuzhiyun fprintf(ofp, "\n\t ");
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun fprintf(ofp, "$%s", f->name);
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun fprintf(ofp, ") = @_;\n\n");
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
638*4882a593Smuzhiyun "$common_secs, $common_nsecs,\n\t "
639*4882a593Smuzhiyun "$common_pid, $common_comm, $common_callchain);\n\n");
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun fprintf(ofp, "\tprintf(\"");
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun not_first = 0;
644*4882a593Smuzhiyun count = 0;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun for (f = event->format.fields; f; f = f->next) {
647*4882a593Smuzhiyun if (not_first++)
648*4882a593Smuzhiyun fprintf(ofp, ", ");
649*4882a593Smuzhiyun if (count && count % 4 == 0) {
650*4882a593Smuzhiyun fprintf(ofp, "\".\n\t \"");
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun count++;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun fprintf(ofp, "%s=", f->name);
655*4882a593Smuzhiyun if (f->flags & TEP_FIELD_IS_STRING ||
656*4882a593Smuzhiyun f->flags & TEP_FIELD_IS_FLAG ||
657*4882a593Smuzhiyun f->flags & TEP_FIELD_IS_SYMBOLIC)
658*4882a593Smuzhiyun fprintf(ofp, "%%s");
659*4882a593Smuzhiyun else if (f->flags & TEP_FIELD_IS_SIGNED)
660*4882a593Smuzhiyun fprintf(ofp, "%%d");
661*4882a593Smuzhiyun else
662*4882a593Smuzhiyun fprintf(ofp, "%%u");
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun fprintf(ofp, "\\n\",\n\t ");
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun not_first = 0;
668*4882a593Smuzhiyun count = 0;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun for (f = event->format.fields; f; f = f->next) {
671*4882a593Smuzhiyun if (not_first++)
672*4882a593Smuzhiyun fprintf(ofp, ", ");
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun if (++count % 5 == 0)
675*4882a593Smuzhiyun fprintf(ofp, "\n\t ");
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun if (f->flags & TEP_FIELD_IS_FLAG) {
678*4882a593Smuzhiyun if ((count - 1) % 5 != 0) {
679*4882a593Smuzhiyun fprintf(ofp, "\n\t ");
680*4882a593Smuzhiyun count = 4;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun fprintf(ofp, "flag_str(\"");
683*4882a593Smuzhiyun fprintf(ofp, "%s::%s\", ", event->system,
684*4882a593Smuzhiyun event->name);
685*4882a593Smuzhiyun fprintf(ofp, "\"%s\", $%s)", f->name,
686*4882a593Smuzhiyun f->name);
687*4882a593Smuzhiyun } else if (f->flags & TEP_FIELD_IS_SYMBOLIC) {
688*4882a593Smuzhiyun if ((count - 1) % 5 != 0) {
689*4882a593Smuzhiyun fprintf(ofp, "\n\t ");
690*4882a593Smuzhiyun count = 4;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun fprintf(ofp, "symbol_str(\"");
693*4882a593Smuzhiyun fprintf(ofp, "%s::%s\", ", event->system,
694*4882a593Smuzhiyun event->name);
695*4882a593Smuzhiyun fprintf(ofp, "\"%s\", $%s)", f->name,
696*4882a593Smuzhiyun f->name);
697*4882a593Smuzhiyun } else
698*4882a593Smuzhiyun fprintf(ofp, "$%s", f->name);
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun fprintf(ofp, ");\n\n");
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun fprintf(ofp, "}\n\n");
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
709*4882a593Smuzhiyun "$common_cpu, $common_secs, $common_nsecs,\n\t "
710*4882a593Smuzhiyun "$common_pid, $common_comm, $common_callchain) = @_;\n\n");
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
713*4882a593Smuzhiyun "$common_secs, $common_nsecs,\n\t $common_pid, "
714*4882a593Smuzhiyun "$common_comm, $common_callchain);\n");
715*4882a593Smuzhiyun fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
716*4882a593Smuzhiyun fprintf(ofp, "}\n\n");
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun fprintf(ofp, "sub print_header\n{\n"
719*4882a593Smuzhiyun "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
720*4882a593Smuzhiyun "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
721*4882a593Smuzhiyun "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n");
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun fprintf(ofp,
724*4882a593Smuzhiyun "\n# Packed byte string args of process_event():\n"
725*4882a593Smuzhiyun "#\n"
726*4882a593Smuzhiyun "# $event:\tunion perf_event\tutil/event.h\n"
727*4882a593Smuzhiyun "# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n"
728*4882a593Smuzhiyun "# $sample:\tstruct perf_sample\tutil/event.h\n"
729*4882a593Smuzhiyun "# $raw_data:\tperf_sample->raw_data\tutil/event.h\n"
730*4882a593Smuzhiyun "\n"
731*4882a593Smuzhiyun "sub process_event\n"
732*4882a593Smuzhiyun "{\n"
733*4882a593Smuzhiyun "\tmy ($event, $attr, $sample, $raw_data) = @_;\n"
734*4882a593Smuzhiyun "\n"
735*4882a593Smuzhiyun "\tmy @event\t= unpack(\"LSS\", $event);\n"
736*4882a593Smuzhiyun "\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n"
737*4882a593Smuzhiyun "\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n"
738*4882a593Smuzhiyun "\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n"
739*4882a593Smuzhiyun "\n"
740*4882a593Smuzhiyun "\tuse Data::Dumper;\n"
741*4882a593Smuzhiyun "\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n"
742*4882a593Smuzhiyun "}\n");
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun fclose(ofp);
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun fprintf(stderr, "generated Perl script: %s\n", fname);
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun return 0;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun struct scripting_ops perl_scripting_ops = {
752*4882a593Smuzhiyun .name = "Perl",
753*4882a593Smuzhiyun .start_script = perl_start_script,
754*4882a593Smuzhiyun .flush_script = perl_flush_script,
755*4882a593Smuzhiyun .stop_script = perl_stop_script,
756*4882a593Smuzhiyun .process_event = perl_process_event,
757*4882a593Smuzhiyun .generate_script = perl_generate_script,
758*4882a593Smuzhiyun };
759