modify detail option (to print supplementary log)
[adaptation/xorg/driver/xserver-xorg-module-xdbg.git] / common / xdbg_evlog.c
1 /**************************************************************************
2
3 xdbg
4
5 Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
6
7 Contact: Boram Park <boram1288.park@samsung.com>
8          Sangjin LEE <lsj119@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <sys/types.h>
36 #include <sys/fcntl.h>
37 #include <unistd.h>
38 #include <stdarg.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <time.h>
42 #include <X11/Xlib.h>
43
44 #include "xdbg_types.h"
45 #include "xdbg_evlog.h"
46 #include "bool_exp_rule_checker.h"
47 #include <X11/Xlibint.h>
48
49 #ifndef XDBG_CLIENT
50 #include "resource.h"
51 #include "region.h"
52 #include "dix.h"
53 #endif
54
55 static char *evt_type[] = { "Event", "Request", "Reply", "Flush", "Error" };
56 static char *evt_dir[]  = { "<====", "---->",   "<----", "*****", "<----"};
57
58 static RULE_CHECKER rc = NULL;
59
60 static void
61 _mergeArgs (char * target, int argc, const char ** argv)
62 {
63     int i;
64     int len;
65
66     for (i=0; i<argc; i++)
67     {
68         len = sprintf (target, "%s", argv[i]);
69         target += len;
70
71         if (i != argc - 1)
72             *(target++) = ' ';
73     }
74 }
75
76 static int
77 _strcasecmp(const char *str1, const char *str2)
78 {
79     const u_char *us1 = (const u_char *) str1, *us2 = (const u_char *) str2;
80
81     while (tolower(*us1) == tolower(*us2)) {
82         if (*us1++ == '\0')
83             return 0;
84         us2++;
85     }
86
87     return (tolower(*us1) - tolower(*us2));
88 }
89
90 char*
91 xDbgEvlogGetCmd (char *path)
92 {
93     char *p;
94     if (!path)
95         return NULL;
96     p = strrchr (path, '/');
97     return (p)?p+1:path;
98 }
99
100 Bool
101 xDbgEvlogRuleSet (const int argc, const char **argv, char *reply, int *len)
102 {
103     const char * command;
104
105     if (rc == NULL)
106         rc = rulechecker_init();
107
108     if (argc == 0)
109     {
110         rulechecker_print_rule (rc, reply);
111         return TRUE;
112     }
113
114     command = argv[0];
115
116     if (!_strcasecmp (command, "add"))
117     {
118         POLICY_TYPE policy_type;
119         RC_RESULT_TYPE result;
120         const char * policy = argv[1];
121         char merge[8192], rule[8192]={0,};
122         int i, index = 0;
123         int apply = 0;
124
125         if (argc < 3)
126         {
127             REPLY ("Error : Too few arguments.\n");
128             return FALSE;
129         }
130
131         if (!_strcasecmp (policy, "ALLOW"))
132             policy_type = ALLOW;
133         else if (!_strcasecmp (policy, "DENY"))
134             policy_type = DENY;
135         else
136         {
137             REPLY ("Error : Unknown policy : [%s].\n          Policy should be ALLOW or DENY.\n", policy);
138             return FALSE;
139         }
140
141         _mergeArgs (merge, argc - 2, &(argv[2]));
142
143         for (i = 0 ; i < strlen(merge) ; i++)
144         {
145             if(merge[i] == '\"' || merge[i] == '\'')
146             {
147                 rule[index++] = ' ';
148                 continue;
149             }
150
151             if(merge[i] == '+')
152             {
153                 rule[index++] = ' ';
154
155                 if (apply == 0)
156                 {
157                     const char* plus = "|| type=reply || type=error";
158
159                     strcat(rule, plus);
160                     index += strlen(plus);
161
162                     apply = 1;
163                 }
164                 continue;
165             }
166             rule[index++] = merge[i];
167         }
168
169         result = rulechecker_add_rule (rc, policy_type, rule);
170         if (result == RC_ERR_TOO_MANY_RULES)
171         {
172             REPLY ("Error : Too many rules were added.\n");
173             return FALSE;
174         }
175         else if (result == RC_ERR_PARSE_ERROR)
176         {
177             REPLY ("Error : An error occured during parsing the rule [%s]\n", rule);
178             return FALSE;
179         }
180
181         REPLY ("The rule was successfully added.\n\n");
182         rulechecker_print_rule (rc, reply);
183         return TRUE;
184     }
185     else if (!_strcasecmp (command, "remove"))
186     {
187         const char * remove_idx;
188         int i;
189
190         if (argc < 2)
191         {
192             REPLY ("Error : Too few arguments.\n");
193             return FALSE;
194         }
195
196         for (i=0; i<argc - 1; i++)
197         {
198             remove_idx = argv[i+1];
199
200             if (!_strcasecmp (remove_idx, "all"))
201             {
202                 rulechecker_destroy (rc);
203                 rc = rulechecker_init();
204                 REPLY ("Every rules were successfully removed.\n");
205             }
206             else
207             {
208                 int index = atoi (remove_idx);
209                 if (isdigit (*remove_idx) && rulechecker_remove_rule (rc, index) == 0)
210                     REPLY ("The rule [%d] was successfully removed.\n", index);
211                 else
212                     REPLY ("Rule remove fail : No such rule [%s].\n", remove_idx);
213             }
214         }
215         rulechecker_print_rule (rc, reply);
216         return TRUE;
217     }
218     else if (!_strcasecmp (command, "print"))
219     {
220         rulechecker_print_rule (rc, reply);
221         return TRUE;
222     }
223     else if (!_strcasecmp (command, "help"))
224     {
225         REPLY ("%s", rulechecker_print_usage());
226         return TRUE;
227     }
228
229     REPLY ("%s\nUnknown command : [%s].\n\n", rulechecker_print_usage(), command);
230
231     return TRUE;
232 }
233
234 Bool
235 xDbgEvlogRuleValidate (EvlogInfo *evinfo)
236 {
237     const char *evlog_name = "";
238     char *cmd = "";
239
240     if (rc == NULL)
241         rc = rulechecker_init ();
242
243     if (!rc)
244     {
245         XDBG_LOG ("failed: create rulechecker\n");
246         return FALSE;
247     }
248
249     cmd = xDbgEvlogGetCmd (evinfo->client.command);
250
251     if (evinfo->type == REQUEST)
252         evlog_name = evinfo->req.name;
253     else if (evinfo->type == EVENT)
254         evlog_name = evinfo->evt.name;
255     else if (evinfo ->type == REPLY)
256         evlog_name = evinfo->rep.name;
257
258     return rulechecker_validate_rule (rc,
259                                       evinfo->type,
260                                       evinfo->req.id,
261                                       evlog_name,
262                                       evinfo->client.pid,
263                                       cmd);
264 }
265
266
267 ExtensionInfo Evlog_extensions[] = {
268     {xDbgEvlogCompositeGetBase, 0, 0, 0, NULL, NULL},
269     {xDbgEvlogDamageGetBase, 0, 0, 0, NULL, NULL},
270     {xDbgEvlogDri2GetBase, 0, 0, 0, NULL, NULL},
271     {xDbgEvlogGestureGetBase, 0, 0, 0, NULL, NULL},
272     {xDbgEvlogXinputGetBase, 0, 0, 0, NULL, NULL},
273     {xDbgEvlogRandrGetBase, 0, 0, 0, NULL, NULL},
274     {xDbgEvlogXextDpmsGetBase, 0, 0, 0, NULL, NULL},
275     {xDbgEvlogXextShmGetBase, 0, 0, 0, NULL, NULL},
276     {xDbgEvlogXextSyncGetBase, 0, 0, 0, NULL, NULL},
277     {xDbgEvlogXextXtestGetBase, 0, 0, 0, NULL, NULL},
278     {xDbgEvlogXextXtestExt1GetBase, 0, 0, 0, NULL, NULL},
279     {xDbgEvlogXvGetBase, 0, 0, 0, NULL, NULL}
280 };
281 ExtensionInfo* Sorted_Evlog_extensions;
282 int Extensions_size = 0;
283
284 static void
285 _ExtensionsSwap(ExtensionInfo* first, ExtensionInfo* second)
286 {
287     ExtensionInfo temp;
288
289     temp = *first ;
290     *first = *second ;
291     *second = temp ;
292 }
293
294 static Bool
295 _SortEvlogExtensions ()
296 {
297     int i,j;
298     int swap;
299
300     Sorted_Evlog_extensions = (ExtensionInfo*)malloc(sizeof(Evlog_extensions));
301     RETURN_VAL_IF_FAIL (Sorted_Evlog_extensions != NULL, FALSE);
302
303     memcpy(Sorted_Evlog_extensions, Evlog_extensions, sizeof(Evlog_extensions));
304
305     for (i = 0 ; i < Extensions_size - 1 ; i++)
306     {
307         swap = 0;
308         for (j = 1 ; j < Extensions_size - i ; j++)
309         {
310             if(Sorted_Evlog_extensions[j-1].evt_base > Sorted_Evlog_extensions[j].evt_base)
311             {
312                 _ExtensionsSwap(&Sorted_Evlog_extensions[j-1], &Sorted_Evlog_extensions[j]);
313                 swap = 1;
314             }
315         }
316         if (!swap) break;
317     }
318
319     return TRUE;
320 }
321
322
323 Bool
324 xDbgEvlogGetExtensionEntry ()
325 {
326     static int init = 0;
327     static Bool success = FALSE;
328     int i;
329
330     if (init)
331         return success;
332
333     init = 1;
334     Extensions_size = sizeof(Evlog_extensions) / sizeof (ExtensionInfo);
335
336     for (i = 0 ; i < Extensions_size ; i++)
337     {
338         Evlog_extensions[i].get_base_func (Evlog_extensions + i);
339     }
340
341     if(!_SortEvlogExtensions ())
342         return FALSE;
343
344
345     success = TRUE;
346
347     return success;
348 }
349
350
351 Bool
352 xDbgEvlogFillLog (EvlogInfo *evinfo, int detail_level, char *reply, int *len)
353 {
354     static CARD32 prev;
355
356     RETURN_VAL_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_dir) / sizeof (char*)), FALSE);
357     RETURN_VAL_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_type) / sizeof (char*)), FALSE);
358
359     if (evinfo->type == REPLY && !evinfo->rep.isStart)
360     {
361         if (detail_level >= EVLOG_PRINT_REPLY_DETAIL)
362             REPLY ("%67s"," ");
363         else
364             return FALSE;
365     }
366     else
367         REPLY ("[%10.3f][%5ld] %22s(%2d:%5d) %s %7s ",
368                     evinfo->time / 1000.0,
369                     evinfo->time - prev,
370                     xDbgEvlogGetCmd (evinfo->client.command),
371                     evinfo->client.index,
372                     evinfo->client.pid,
373                     evt_dir[evinfo->type],
374                     evt_type[evinfo->type]);
375
376     if (evinfo->type == REQUEST)
377     {
378         REPLY ("(");
379         reply = xDbgEvlogReqeust (evinfo, detail_level, reply, len);
380         REPLY (")");
381     }
382     else if (evinfo->type == EVENT)
383     {
384         evinfo->evt.size = sizeof (xEvent);
385         REPLY ("(");
386         reply = xDbgEvlogEvent (evinfo, detail_level, reply, len);
387         REPLY (")");
388     }
389     else if (evinfo->type == REPLY)
390     {
391         REPLY ("(");
392         reply = xDbgEvlogReply (evinfo, detail_level, reply, len);
393         REPLY (")");
394     }
395     else if (evinfo->type == ERROR)
396     {
397         REPLY("(ErrorCode(0x%02x) resourceID(0x%lx) majorCode(%d) minorCode(%d))",
398             evinfo->err.errorCode,
399             evinfo->err.resourceID,
400             evinfo->err.majorCode,
401             evinfo->err.minorCode);
402     }
403     else
404     {
405         const char *evlog_name = "";
406         if (evinfo->type == REQUEST)
407             evlog_name = evinfo->req.name;
408         else if (evinfo->type == EVENT)
409             evlog_name = evinfo->evt.name;
410         else if (evinfo->type == REPLY)
411             evlog_name = evinfo->rep.name;
412         REPLY ("(%s)", evlog_name);
413     }
414
415     REPLY ("\n");
416
417     prev = evinfo->time;
418
419     return TRUE;
420 }
421
422
423 void xDbgDistroyAtomList (EvlogInfo *evinfo)
424 {
425     EvlogAtomTable *cur, *next;
426
427     if (!evinfo->evatom.init)
428         return;
429
430     xorg_list_for_each_entry_safe(cur, next, &evinfo->evatom.list, link)
431     {
432         xorg_list_del(&cur->link);
433         free (cur);
434         cur = NULL;
435     }
436     evinfo->evatom.init = 0;
437     evinfo->evatom.size = 0;
438 }
439
440 void xDbgDistroyRegionList (EvlogInfo *evinfo)
441 {
442     EvlogRegionTable *cur, *next;
443
444     if (!evinfo->evregion.init)
445         return;
446
447     xorg_list_for_each_entry_safe(cur, next, &evinfo->evregion.list, link)
448     {
449         xorg_list_del(&cur->link);
450         free (cur);
451         cur = NULL;
452     }
453     evinfo->evregion.init = 0;
454     evinfo->evregion.size = 0;
455 }
456
457 char* xDbgGetAtom(Atom atom, EvlogInfo *evinfo, char *reply, int *len)
458 {
459     EvlogAtomTable *table;
460 #ifndef XDBG_CLIENT
461     table = malloc (sizeof(EvlogAtomTable));
462     if (!table)
463         return reply;
464
465     evinfo->mask |= EVLOG_MASK_ATOM;
466     table->xid = atom;
467
468     if (!evinfo->evatom.init)
469     {
470         xorg_list_init(&evinfo->evatom.list);
471         evinfo->evatom.init = 1;
472     }
473
474     if (NameForAtom(atom))
475         snprintf (table->buf, XDBG_BUF_SIZE, "%s", (char*)NameForAtom(atom));
476     else
477         snprintf (table->buf, XDBG_BUF_SIZE, "0x%lx", atom);
478
479     xorg_list_add(&table->link, &evinfo->evatom.list);
480     evinfo->evatom.size++;
481 #endif
482     xorg_list_for_each_entry(table, &evinfo->evatom.list, link)
483         if(table->xid == atom)
484         {
485             REPLY ("(%s)", table->buf);
486             break;
487         }
488
489     return reply;
490 }
491
492 char* xDbgGetRegion(XserverRegion region, EvlogInfo *evinfo, char *reply, int *len)
493 {
494     EvlogRegionTable *table;
495 #ifndef XDBG_CLIENT
496     extern _X_EXPORT RESTYPE RegionResType;
497     RegionPtr pRegion;
498     BoxPtr rects;
499     int nrect, i;
500     int s;
501     int err = dixLookupResourceByType((pointer *) &pRegion, region,
502                                        RegionResType, (ClientPtr)evinfo->client.pClient,
503                                        DixReadAccess);
504
505     evinfo->mask |= EVLOG_MASK_REGION;
506
507     if (!evinfo->evregion.init)
508     {
509         xorg_list_init(&evinfo->evregion.list);
510         evinfo->evregion.init = 1;
511     }
512
513         if (err != Success)
514         {
515         table = malloc (sizeof(EvlogAtomTable));
516         if (!table)
517             return reply;
518
519         table->xid = region;
520
521         snprintf (table->buf, XDBG_BUF_SIZE, "0x%lx", region);
522         xorg_list_add(&table->link, &evinfo->evregion.list);
523         evinfo->evregion.size++;
524     }
525     else
526     {
527         nrect = RegionNumRects(pRegion);
528         rects = RegionRects(pRegion);
529
530         for (i = 0; i < nrect; i++)
531         {
532             table = malloc (sizeof(EvlogAtomTable));
533             if (!table)
534                 return reply;
535
536             table->xid = region;
537
538             s = 0;
539             s += snprintf (table->buf + s, XDBG_BUF_SIZE - s,
540                            "[%d,%d %dx%d]",
541                                rects[i].x1,
542                                rects[i].y1,
543                                rects[i].x2 - rects[i].x1,
544                                rects[i].y2 - rects[i].y1);
545             xorg_list_add(&table->link, &evinfo->evregion.list);
546             evinfo->evregion.size++;
547         }
548     }
549
550 #endif
551     REPLY("(");
552     xorg_list_for_each_entry(table, &evinfo->evregion.list, link)
553         if(table->xid == region)
554         {
555             REPLY ("%s", table->buf);
556             if(table != xorg_list_last_entry(&evinfo->evregion.list, EvlogRegionTable, link))
557                 REPLY (", ");
558         }
559     REPLY(")");
560
561     return reply;
562 }