repo-fixing: fixup #1.
[profile/ivi/murphy.git] / src / common / debug.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *  * Neither the name of Intel Corporation nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdarg.h>
31 #include <limits.h>
32
33 #include <murphy/common/macros.h>
34 #include <murphy/common/mm.h>
35 #include <murphy/common/list.h>
36 #include <murphy/common/log.h>
37 #include <murphy/common/hashtbl.h>
38 #include <murphy/common/utils.h>
39 #include <murphy/common/debug.h>
40
41 #define WILDCARD  "*"
42
43 int mrp_debug_stamp = 0;     /* debug config stamp */
44
45 static int         debug_enabled;           /* debug messages enabled */
46 static mrp_htbl_t *rules_on;                /* enabling rules */
47 static mrp_htbl_t *rules_off;               /* disabling rules */
48 static mrp_htbl_t *files;                   /* table of per-file debug info */
49 static MRP_LIST_HOOK(debug_files);
50
51 static void populate_file_table(void);
52
53 static void free_rule_cb(void *key, void *entry)
54 {
55     MRP_UNUSED(key);
56
57     mrp_free(entry);
58 }
59
60
61 static int init_rules(void)
62 {
63     mrp_htbl_config_t hcfg;
64
65     mrp_clear(&hcfg);
66     hcfg.comp = mrp_string_comp;
67     hcfg.hash = mrp_string_hash;
68     hcfg.free = free_rule_cb;
69
70     rules_on  = mrp_htbl_create(&hcfg);
71     rules_off = mrp_htbl_create(&hcfg);
72
73     if (rules_on == NULL || rules_off == NULL)
74         return FALSE;
75     else
76         return TRUE;
77 }
78
79
80 static void reset_rules(void)
81 {
82     if (rules_on != NULL)
83         mrp_htbl_destroy(rules_on , TRUE);
84     if (rules_off != NULL)
85         mrp_htbl_destroy(rules_off, TRUE);
86 }
87
88
89 void mrp_debug_reset(void)
90 {
91     debug_enabled = FALSE;
92     reset_rules();
93 }
94
95
96 int mrp_debug_enable(int enabled)
97 {
98     int prev = debug_enabled;
99
100     debug_enabled = !!enabled;
101     mrp_log_enable(MRP_LOG_MASK_DEBUG);
102
103     return prev;
104 }
105
106
107 static int add_rule(const char *func, const char *file, int line, int off)
108 {
109     mrp_htbl_t  *ht;
110     char        *rule, *r, buf[PATH_MAX * 2];
111
112     if (rules_on == NULL)
113         if (!init_rules())
114             return FALSE;
115
116     r = rule = NULL;
117
118     if (!off)
119         ht = rules_on;
120     else
121         ht = rules_off;
122
123     if (func != NULL && file == NULL && line == 0) {
124         r    = mrp_htbl_lookup(ht, (void *)func);
125         rule = (char *)func;
126     }
127     else if (func != NULL && file != NULL && line == 0) {
128         snprintf(buf, sizeof(buf), "%s@%s", func, file);
129         r    = mrp_htbl_lookup(ht, (void *)buf);
130         rule = buf;
131     }
132     else if (func == NULL && file != NULL && line == 0) {
133         snprintf(buf, sizeof(buf), "@%s", file);
134         r    = mrp_htbl_lookup(ht, (void *)buf);
135         rule = buf;
136     }
137     else if (func == NULL && file != NULL && line > 0) {
138         snprintf(buf, sizeof(buf), "%s:%d", file, line);
139         r    = mrp_htbl_lookup(ht, (void *)buf);
140         rule = buf;
141     }
142
143     if (r != NULL)
144         return FALSE;
145
146     rule = mrp_strdup(rule);
147     if (rule == NULL)
148         return FALSE;
149
150     if (mrp_htbl_insert(ht, rule, rule)) {
151         mrp_debug_stamp++;
152
153         return TRUE;
154     }
155     else {
156         mrp_free(rule);
157
158         return FALSE;
159     }
160 }
161
162
163 static int del_rule(const char *func, const char *file, int line, int off)
164 {
165     mrp_htbl_t  *ht;
166     char        *r, buf[PATH_MAX * 2];
167
168     if (rules_on == NULL)
169         if (!init_rules())
170             return FALSE;
171
172     r = NULL;
173
174     if (!off)
175         ht = rules_on;
176     else
177         ht = rules_off;
178
179     if (func != NULL && file == NULL && line == 0) {
180         r = mrp_htbl_remove(ht, (void *)func, TRUE);
181     }
182     else if (func != NULL && file != NULL && line == 0) {
183         snprintf(buf, sizeof(buf), "%s@%s", func, file);
184         r = mrp_htbl_remove(ht, (void *)buf, TRUE);
185     }
186     else if (func == NULL && file != NULL && line == 0) {
187         snprintf(buf, sizeof(buf), "@%s", file);
188         r = mrp_htbl_remove(ht, (void *)buf, TRUE);
189     }
190     else if (func == NULL && file != NULL && line > 0) {
191         snprintf(buf, sizeof(buf), "%s:%d", file, line);
192         r = mrp_htbl_remove(ht, (void *)buf, TRUE);
193     }
194
195     if (r != NULL) {
196         mrp_debug_stamp++;
197
198         return TRUE;
199     }
200     else
201         return FALSE;
202 }
203
204
205 int mrp_debug_set_config(const char *cmd)
206 {
207     char    buf[2 * PATH_MAX + 1], *colon, *at, *eq;
208     char   *func, *file, *end;
209     size_t  len;
210     int     del, off, line;
211
212     if (*cmd == '+' || *cmd == '-')
213         del = (*cmd++ == '-');
214     else
215         del = FALSE;
216
217     eq = strchr(cmd, '=');
218
219     if (eq == NULL) {
220         strncpy(buf, cmd, sizeof(buf) - 1);
221         buf[sizeof(buf) - 1] = '\0';
222         off = FALSE;
223     }
224     else {
225         if (!strcmp(eq + 1, "on"))
226             off = FALSE;
227         else if (!strcmp(eq + 1, "off"))
228             off = TRUE;
229         else
230             return FALSE;
231
232         len = eq - cmd;
233         if (len >= sizeof(buf))
234             len = sizeof(buf) - 1;
235
236         strncpy(buf, cmd, len);
237         buf[len] = '\0';
238     }
239
240     colon = strchr(buf, ':');
241
242     if (colon != NULL) {
243         if (strchr(buf, '@') != NULL)
244             return FALSE;
245
246         *colon = '\0';
247         func   = NULL;
248         file   = buf;
249         line   = strtoul(colon + 1, &end, 10);
250
251         if (end && *end)
252             return FALSE;
253
254         mrp_log_info("%s file='%s', line=%d, %s", del ? "del" : "add",
255                      file, line, off ? "off" : "on");
256     }
257     else {
258         at = strchr(buf, '@');
259
260         if (at != NULL) {
261             *at = '\0';
262             func = (at == buf ? NULL : buf);
263             file = at + 1;
264             line = 0;
265
266             mrp_log_info("%s func='%s', file='%s', %s", del ? "del" : "add",
267                          func ? func : "", file, off ? "off" : "on");
268         }
269         else {
270             func = buf;
271             file = NULL;
272             line = 0;
273
274             mrp_log_info("%s func='%s' %s", del ? "del" : "add",
275                          func, off ? "off" : "on");
276         }
277     }
278
279     if (!del)
280         return add_rule(func, file, line, off);
281     else
282         return del_rule(func, file, line, off);
283
284     return TRUE;
285 }
286
287
288 typedef struct {
289     FILE *fp;
290     int   on;
291 } dump_t;
292
293
294 static int dump_rule_cb(void *key, void *object, void *user_data)
295 {
296     dump_t     *d     = (dump_t *)user_data;
297     FILE       *fp    = d->fp;
298     const char *state = d->on ? "on" : "off";
299
300     MRP_UNUSED(key);
301
302     fprintf(fp, "    %s %s\n", (char *)object, state);
303
304     return MRP_HTBL_ITER_MORE;
305 }
306
307
308 int mrp_debug_dump_config(FILE *fp)
309 {
310     dump_t d;
311
312     fprintf(fp, "Debugging is %sabled\n", debug_enabled ? "en" : "dis");
313
314     if (rules_on != NULL) {
315         fprintf(fp, "Debugging rules:\n");
316
317         d.fp = fp;
318         d.on = TRUE;
319         mrp_htbl_foreach(rules_on , dump_rule_cb, &d);
320         d.on = FALSE;
321         mrp_htbl_foreach(rules_off, dump_rule_cb, &d);
322     }
323     else
324         fprintf(fp, "No debugging rules defined.\n");
325
326     return TRUE;
327 }
328
329
330 void mrp_debug_msg(const char *site, const char *file, int line,
331                    const char *func, const char *format, ...)
332 {
333     va_list ap;
334
335     MRP_UNUSED(site);
336
337     va_start(ap, format);
338     mrp_log_msgv(MRP_LOG_DEBUG, file, line, func, format, ap);
339     va_end(ap);
340 }
341
342
343 int mrp_debug_check(const char *func, const char *file, int line)
344 {
345     char  buf[2 * PATH_MAX], *base;
346     void *key;
347
348     if (!debug_enabled || rules_on == NULL)
349         return FALSE;
350
351     key = (void *)func;
352     if (mrp_htbl_lookup(rules_on, key) != NULL)
353         goto check_suppress;
354
355     base = strrchr(file, '/');
356     if (base != NULL) {
357         key = base + 1;
358         if (mrp_htbl_lookup(rules_on, key) != NULL)
359             goto check_suppress;
360     }
361
362     key = buf;
363
364     snprintf(buf, sizeof(buf), "@%s", file);
365     if (mrp_htbl_lookup(rules_on, key) != NULL)
366         goto check_suppress;
367
368     snprintf(buf, sizeof(buf), "%s@%s", func, file);
369     if (mrp_htbl_lookup(rules_on, key) != NULL)
370         goto check_suppress;
371
372     snprintf(buf, sizeof(buf), "%s:%d", file, line);
373     if (mrp_htbl_lookup(rules_on, key) != NULL)
374         goto check_suppress;
375
376     if (mrp_htbl_lookup(rules_on, (void *)WILDCARD) == NULL)
377         return FALSE;
378
379
380  check_suppress:
381     if (rules_off == NULL)
382         return TRUE;
383
384     key = (void *)func;
385     if (mrp_htbl_lookup(rules_off, key) != NULL)
386         return FALSE;
387
388     base = strrchr(file, '/');
389     if (base != NULL) {
390         key = base + 1;
391         if (mrp_htbl_lookup(rules_on, key) != NULL)
392             return FALSE;
393     }
394
395     key = buf;
396
397     snprintf(buf, sizeof(buf), "@%s", file);
398     if (mrp_htbl_lookup(rules_off, key) != NULL)
399         return FALSE;
400
401     snprintf(buf, sizeof(buf), "%s@%s", func, file);
402     if (mrp_htbl_lookup(rules_off, key) != NULL)
403         return FALSE;
404
405     snprintf(buf, sizeof(buf), "%s:%d", file, line);
406     if (mrp_htbl_lookup(rules_off, key) != NULL)
407         return FALSE;
408
409     return TRUE;
410 }
411
412
413 int mrp_debug_register_file(mrp_debug_file_t *df)
414 {
415     mrp_list_append(&debug_files, &df->hook);
416
417     return TRUE;
418 }
419
420
421 int mrp_debug_unregister_file(mrp_debug_file_t *df)
422 {
423     mrp_list_delete(&df->hook);
424
425     if (files != NULL)
426         mrp_htbl_remove(files, (void *)df->file, FALSE);
427
428     return TRUE;
429 }
430
431
432 const char *mrp_debug_site_function(const char *file, int line)
433 {
434     mrp_debug_info_t *info;
435     const char       *func;
436
437     if (files == NULL)
438         populate_file_table();
439
440     func = NULL;
441
442     if (files != NULL) {
443         info = mrp_htbl_lookup(files, (void *)file);
444
445         if (info != NULL) {
446             while (info->func != NULL) {
447                 if (info->line < line) {
448                     func = info->func;
449                     info++;
450                 }
451                 else
452                     break;
453             }
454         }
455     }
456
457     return func;
458 }
459
460
461 static void populate_file_table(void)
462 {
463     mrp_htbl_config_t  hcfg;
464     mrp_debug_file_t  *df;
465     mrp_list_hook_t   *p, *n;
466
467     if (files == NULL) {
468         mrp_clear(&hcfg);
469         hcfg.comp = mrp_string_comp;
470         hcfg.hash = mrp_string_hash;
471
472         files = mrp_htbl_create(&hcfg);
473     }
474
475     if (files != NULL) {
476         mrp_list_foreach(&debug_files, p, n) {
477             df = mrp_list_entry(p, typeof(*df), hook);
478
479             mrp_htbl_insert(files, (void *)df->file, df->info);
480         }
481     }
482 }
483
484
485 static void flush_file_table(void)
486 {
487     mrp_debug_file_t  *df;
488     mrp_list_hook_t   *p, *n;
489
490     if (files != NULL) {
491         mrp_htbl_reset(files, FALSE);
492         files = NULL;
493
494         mrp_list_foreach(&debug_files, p, n) {
495             df = mrp_list_entry(p, typeof(*df), hook);
496
497             mrp_htbl_insert(files, (void *)df->file, df->info);
498         }
499     }
500 }
501
502