2004-01-29 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / trace.c
1 /*
2  * trace.c: Tracing facilities for the Mono Runtime.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include "mini.h"
16 #include <mono/metadata/debug-helpers.h>
17 #include "trace.h"
18
19 static MonoTraceSpec trace_spec;
20
21 gboolean
22 mono_trace_eval (MonoMethod *method)
23 {
24         MonoTraceSpec *s = mono_jit_trace_calls;
25         int include = 0;
26         int i;
27
28         for (i = 0; i < trace_spec.len; i++){
29                 MonoTraceOperation *op = &trace_spec.ops [i];
30                 int inc = 0;
31                 
32                 switch (op->op){
33                 case MONO_TRACEOP_ALL:
34                         inc = 1; break;
35                 case MONO_TRACEOP_PROGRAM:
36                         if (method->klass->image == trace_spec.assembly->image)
37                                 inc = 1; break;
38                 case MONO_TRACEOP_METHOD:
39                         if (mono_method_desc_match ((MonoMethodDesc *) op->data, method))
40                                 inc = 1; break;
41                 case MONO_TRACEOP_CLASS:
42                         if (strcmp (method->klass->name_space, op->data) == 0)
43                                 if (strcmp (method->klass->name, op->data2) == 0)
44                                         inc = 1;
45                         break;
46                 case MONO_TRACEOP_ASSEMBLY:
47                         if (strcmp (method->klass->image->assembly_name, op->data) == 0)
48                                 inc = 1; break;
49                 case MONO_TRACEOP_NAMESPACE:
50                         if (strcmp (method->klass->name_space, op->data) == 0)
51                                 inc = 1;
52                 }
53                 if (op->exclude){
54                         if (inc)
55                                 include = 0;
56                 } else if (inc)
57                         include = 1;
58         }
59         return include;
60 }
61
62 static int is_filenamechar (char p)
63 {
64         if (p >= 'A' && p <= 'Z')
65                 return TRUE;
66         if (p >= 'a' && p <= 'z')
67                 return TRUE;
68         if (p == '.' || p == ':')
69                 return TRUE;
70         return FALSE;
71 }
72
73 static char *input;
74 static char *value;
75
76 static void get_string (void)
77 {
78         char *start = input;
79         while (is_filenamechar (*input)){
80                 input++;
81         }
82         if (value != NULL)
83                 g_free (value);
84         value = g_malloc (input - start + 1);
85         strncpy (value, start, input-start);
86         value [input-start] = 0;
87 }
88
89 enum Token {
90         TOKEN_METHOD,
91         TOKEN_CLASS,
92         TOKEN_ALL,
93         TOKEN_PROGRAM,
94         TOKEN_NAMESPACE,
95         TOKEN_STRING,
96         TOKEN_EXCLUDE,
97         TOKEN_SEPARATOR,
98         TOKEN_END,
99         TOKEN_ERROR
100 };
101
102 static int
103 get_token (void)
104 {
105         while (*input != 0){
106                 if (input [0] == 'M' && input [1] == ':'){
107                         input += 2;
108                         get_string ();
109                         return TOKEN_METHOD;
110                 }
111                 if (input [0] == 'N' && input [1] == ':'){
112                         input += 2;
113                         get_string ();
114                         return TOKEN_NAMESPACE;
115                 }
116                 if (input [0] == 'T' && input [1] == ':'){
117                         input += 2;
118                         get_string ();
119                         return TOKEN_CLASS;
120                 }
121                 if (is_filenamechar (*input)){
122                         get_string ();
123                         if (strcmp (value, "all") == 0)
124                                 return TOKEN_ALL;
125                         if (strcmp (value, "program") == 0)
126                                 return TOKEN_PROGRAM;
127                         return TOKEN_STRING;
128                 }
129                 if (*input == '-'){
130                         input++;
131                         return TOKEN_EXCLUDE;
132                 }
133                 if (*input == ','){
134                         input++;
135                         return TOKEN_SEPARATOR;
136                 }
137                 input++;
138                         
139         }
140         return TOKEN_END;
141 }
142
143 static void
144 cleanup (void)
145 {
146         if (value != NULL)
147                 g_free (value);
148 }
149
150 static int
151 get_spec (int *last)
152 {
153         int token = get_token ();
154         if (token == TOKEN_EXCLUDE){
155                 token = get_spec (last);
156                 if (token == TOKEN_EXCLUDE){
157                         fprintf (stderr, "Expecting an expression");
158                         return TOKEN_ERROR;
159                 }
160                 if (token == TOKEN_ERROR)
161                         return token;
162                 trace_spec.ops [(*last)-1].exclude = 1;
163                 return TOKEN_SEPARATOR;
164         }
165         if (token == TOKEN_END || token == TOKEN_SEPARATOR || token == TOKEN_ERROR)
166                 return token;
167         
168         if (token == TOKEN_METHOD){
169                 MonoMethodDesc *desc = mono_method_desc_new (value, TRUE);
170                 if (desc == NULL){
171                         fprintf (stderr, "Invalid method name: %s\n", value);
172                         return TOKEN_ERROR;
173                 }
174                 trace_spec.ops [*last].op = MONO_TRACEOP_METHOD;
175                 trace_spec.ops [*last].data = desc;
176         } else if (token == TOKEN_ALL)
177                 trace_spec.ops [*last].op = MONO_TRACEOP_ALL;
178         else if (token == TOKEN_PROGRAM)
179                 trace_spec.ops [*last].op = MONO_TRACEOP_PROGRAM;
180         else if (token == TOKEN_NAMESPACE){
181                 trace_spec.ops [*last].op = MONO_TRACEOP_NAMESPACE;
182                 trace_spec.ops [*last].data = g_strdup (value);
183         } else if (token == TOKEN_CLASS){
184                 char *p = strrchr (value, '.');
185                 *p++ = 0;
186                 trace_spec.ops [*last].op = MONO_TRACEOP_CLASS;
187                 trace_spec.ops [*last].data = g_strdup (value);
188                 trace_spec.ops [*last].data2 = g_strdup (p);
189         } else if (token == TOKEN_STRING){
190                 trace_spec.ops [*last].op = MONO_TRACEOP_ASSEMBLY;
191                 trace_spec.ops [*last].data = g_strdup (value);
192         }
193         else {
194                 fprintf (stderr, "Syntax error in trace option specification\n");
195                 return TOKEN_ERROR;
196         }
197         (*last)++;
198         return TOKEN_SEPARATOR;
199 }
200
201 static const char *xmap (int idx)
202 {
203         switch (idx){
204         case MONO_TRACEOP_ALL: return "all";
205         case MONO_TRACEOP_PROGRAM: return "program";
206         case MONO_TRACEOP_METHOD: return "method"; 
207         case MONO_TRACEOP_ASSEMBLY: return "assembly";
208         case MONO_TRACEOP_CLASS: return "class";
209         }
210         return "UNKNOWN";
211 }
212
213 MonoTraceSpec *
214 mono_trace_parse_options (MonoAssembly *assembly, char *options)
215 {
216         char *p = options;
217         int size = 1;
218         int last_used;
219         int exclude = 0;
220         int token;
221         
222         trace_spec.assembly = assembly;
223         
224         if (*p == 0){
225                 trace_spec.len = 1;
226                 trace_spec.ops = g_new0 (MonoTraceOperation, 1);
227                 trace_spec.ops [0].op = MONO_TRACEOP_ALL;
228                 return &trace_spec;
229         }
230                 
231         for (p = options; *p != 0; p++)
232                 if (*p == ',')
233                         size++;
234         
235         trace_spec.ops = g_new0 (MonoTraceOperation, size);
236
237         input = options;
238         last_used = 0;
239         
240         while ((token = (get_spec (&last_used))) != TOKEN_END){
241                 if (token == TOKEN_ERROR)
242                         return NULL;
243                 if (token == TOKEN_SEPARATOR)
244                         continue;
245         }
246         trace_spec.len = last_used;
247         cleanup ();
248         return &trace_spec;
249 }