add supplementary log of reply type
[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 rule[8192];
122         int i;
123
124         if (argc < 3)
125         {
126             REPLY ("Error : Too few arguments.\n");
127             return FALSE;
128         }
129
130         if (!_strcasecmp (policy, "ALLOW"))
131             policy_type = ALLOW;
132         else if (!_strcasecmp (policy, "DENY"))
133             policy_type = DENY;
134         else
135         {
136             REPLY ("Error : Unknown policy : [%s].\n          Policy should be ALLOW or DENY.\n", policy);
137             return FALSE;
138         }
139
140         _mergeArgs (rule, argc - 2, &(argv[2]));
141
142         for (i = 0 ; i < strlen(rule) ; i++)
143         {
144             static int apply = 0;
145             if(rule[i] == '\"' || rule[i] == '\'')
146                 rule[i] = ' ';
147             if(rule[i] == '+')
148             {
149                 rule[i] = ' ';
150                 if (apply == 0)
151                    strcat(rule, "|| type=reply || type=error");
152                 apply = 1;
153             }
154         }
155
156         result = rulechecker_add_rule (rc, policy_type, rule);
157         if (result == RC_ERR_TOO_MANY_RULES)
158         {
159             REPLY ("Error : Too many rules were added.\n");
160             return FALSE;
161         }
162         else if (result == RC_ERR_PARSE_ERROR)
163         {
164             REPLY ("Error : An error occured during parsing the rule [%s]\n", rule);
165             return FALSE;
166         }
167
168         REPLY ("The rule was successfully added.\n\n");
169         rulechecker_print_rule (rc, reply);
170         return TRUE;
171     }
172     else if (!_strcasecmp (command, "remove"))
173     {
174         const char * remove_idx;
175         int i;
176
177         if (argc < 2)
178         {
179             REPLY ("Error : Too few arguments.\n");
180             return FALSE;
181         }
182
183         for (i=0; i<argc - 1; i++)
184         {
185             remove_idx = argv[i+1];
186
187             if (!_strcasecmp (remove_idx, "all"))
188             {
189                 rulechecker_destroy (rc);
190                 rc = rulechecker_init();
191                 REPLY ("Every rules were successfully removed.\n");
192             }
193             else
194             {
195                 int index = atoi (remove_idx);
196                 if (isdigit (*remove_idx) && rulechecker_remove_rule (rc, index) == 0)
197                     REPLY ("The rule [%d] was successfully removed.\n", index);
198                 else
199                     REPLY ("Rule remove fail : No such rule [%s].\n", remove_idx);
200             }
201         }
202         rulechecker_print_rule (rc, reply);
203         return TRUE;
204     }
205     else if (!_strcasecmp (command, "print"))
206     {
207         rulechecker_print_rule (rc, reply);
208         return TRUE;
209     }
210     else if (!_strcasecmp (command, "help"))
211     {
212         REPLY ("%s", rulechecker_print_usage());
213         return TRUE;
214     }
215
216     REPLY ("%s\nUnknown command : [%s].\n\n", rulechecker_print_usage(), command);
217
218     return TRUE;
219 }
220
221 Bool
222 xDbgEvlogRuleValidate (EvlogInfo *evinfo)
223 {
224     const char *evlog_name = "";
225     char *cmd = "";
226
227     if (rc == NULL)
228         rc = rulechecker_init ();
229
230     if (!rc)
231     {
232         XDBG_LOG ("failed: create rulechecker\n");
233         return FALSE;
234     }
235
236     cmd = xDbgEvlogGetCmd (evinfo->client.command);
237
238     if (evinfo->type == REQUEST)
239         evlog_name = evinfo->req.name;
240     else if (evinfo->type == EVENT)
241         evlog_name = evinfo->evt.name;
242     else if (evinfo ->type == REPLY)
243         evlog_name = evinfo->rep.name;
244
245     return rulechecker_validate_rule (rc,
246                                       evinfo->type,
247                                       evinfo->req.id,
248                                       evlog_name,
249                                       evinfo->client.pid,
250                                       cmd);
251 }
252
253
254 ExtensionInfo Evlog_extensions[] = {
255     {xDbgEvlogCompositeGetBase, 0, 0, 0, NULL, NULL},
256     {xDbgEvlogDamageGetBase, 0, 0, 0, NULL, NULL},
257     {xDbgEvlogDri2GetBase, 0, 0, 0, NULL, NULL},
258     {xDbgEvlogGestureGetBase, 0, 0, 0, NULL, NULL},
259     {xDbgEvlogXinputGetBase, 0, 0, 0, NULL, NULL},
260     {xDbgEvlogRandrGetBase, 0, 0, 0, NULL, NULL},
261     {xDbgEvlogXextDpmsGetBase, 0, 0, 0, NULL, NULL},
262     {xDbgEvlogXextShmGetBase, 0, 0, 0, NULL, NULL},
263     {xDbgEvlogXextSyncGetBase, 0, 0, 0, NULL, NULL},
264     {xDbgEvlogXextXtestGetBase, 0, 0, 0, NULL, NULL},
265     {xDbgEvlogXextXtestExt1GetBase, 0, 0, 0, NULL, NULL},
266     {xDbgEvlogXvGetBase, 0, 0, 0, NULL, NULL}
267 };
268 ExtensionInfo* Sorted_Evlog_extensions;
269 int Extensions_size = 0;
270
271 static void
272 _ExtensionsSwap(ExtensionInfo* first, ExtensionInfo* second)
273 {
274     ExtensionInfo temp;
275
276     temp = *first ;
277     *first = *second ;
278     *second = temp ;
279 }
280
281 static Bool
282 _SortEvlogExtensions ()
283 {
284     int i,j;
285     int swap;
286
287     Sorted_Evlog_extensions = (ExtensionInfo*)malloc(sizeof(Evlog_extensions));
288     RETURN_VAL_IF_FAIL (Sorted_Evlog_extensions != NULL, FALSE);
289
290     memcpy(Sorted_Evlog_extensions, Evlog_extensions, sizeof(Evlog_extensions));
291
292     for (i = 0 ; i < Extensions_size - 1 ; i++)
293     {
294         swap = 0;
295         for (j = 1 ; j < Extensions_size - i ; j++)
296         {
297             if(Sorted_Evlog_extensions[j-1].evt_base > Sorted_Evlog_extensions[j].evt_base)
298             {
299                 _ExtensionsSwap(&Sorted_Evlog_extensions[j-1], &Sorted_Evlog_extensions[j]);
300                 swap = 1;
301             }
302         }
303         if (!swap) break;
304     }
305
306     return TRUE;
307 }
308
309
310 Bool
311 xDbgEvlogGetExtensionEntry ()
312 {
313     static int init = 0;
314     static Bool success = FALSE;
315     int i;
316
317     if (init)
318         return success;
319
320     init = 1;
321     Extensions_size = sizeof(Evlog_extensions) / sizeof (ExtensionInfo);
322
323     for (i = 0 ; i < Extensions_size ; i++)
324     {
325         Evlog_extensions[i].get_base_func (Evlog_extensions + i);
326     }
327
328     if(!_SortEvlogExtensions ())
329         return FALSE;
330
331
332     success = TRUE;
333
334     return success;
335 }
336
337
338 void
339 xDbgEvlogFillLog (EvlogInfo *evinfo, Bool on, char *reply, int *len)
340 {
341     static CARD32 prev;
342
343     RETURN_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_dir) / sizeof (char*)));
344     RETURN_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_type) / sizeof (char*)));
345
346     if (evinfo->type == REPLY && !evinfo->rep.isStart)
347     {
348         if (on) // detail option is on
349             REPLY ("%67s"," ");
350         else
351             return;
352     }
353     else
354         REPLY ("[%10.3f][%5ld] %22s(%2d:%5d) %s %7s ",
355                     evinfo->time / 1000.0,
356                     evinfo->time - prev,
357                     xDbgEvlogGetCmd (evinfo->client.command),
358                     evinfo->client.index,
359                     evinfo->client.pid,
360                     evt_dir[evinfo->type],
361                     evt_type[evinfo->type]);
362
363     if (evinfo->type == REQUEST)
364     {
365         REPLY ("(");
366         reply = xDbgEvlogReqeust (evinfo, on, reply, len);
367         REPLY (")");
368     }
369     else if (evinfo->type == EVENT)
370     {
371         evinfo->evt.size = sizeof (xEvent);
372         REPLY ("(");
373         reply = xDbgEvlogEvent (evinfo, on, reply, len);
374         REPLY (")");
375     }
376     else if (evinfo->type == REPLY)
377     {
378         REPLY ("(");
379         reply = xDbgEvlogReply (evinfo, on, reply, len);
380         REPLY (")");
381     }
382     else if (evinfo->type == ERROR)
383     {
384         REPLY("(ErrorCode(0x%02x) resourceID(0x%lx) majorCode(%d) minorCode(%d))",
385             evinfo->err.errorCode,
386             evinfo->err.resourceID,
387             evinfo->err.majorCode,
388             evinfo->err.minorCode);
389     }
390     else
391     {
392         const char *evlog_name = "";
393         if (evinfo->type == REQUEST)
394             evlog_name = evinfo->req.name;
395         else if (evinfo->type == EVENT)
396             evlog_name = evinfo->evt.name;
397         else if (evinfo->type == REPLY)
398             evlog_name = evinfo->rep.name;
399         REPLY ("(%s)", evlog_name);
400     }
401
402     REPLY ("\n");
403
404     prev = evinfo->time;
405 }
406
407
408 void xDbgDistroyAtomList (EvlogInfo *evinfo)
409 {
410     EvlogAtomTable *cur, *next;
411
412     if (!evinfo->evatom.init)
413         return;
414
415     xorg_list_for_each_entry_safe(cur, next, &evinfo->evatom.list, link)
416     {
417         xorg_list_del(&cur->link);
418         free (cur);
419         cur = NULL;
420     }
421     evinfo->evatom.init = 0;
422     evinfo->evatom.size = 0;
423 }
424
425 void xDbgDistroyRegionList (EvlogInfo *evinfo)
426 {
427     EvlogRegionTable *cur, *next;
428
429     if (!evinfo->evregion.init)
430         return;
431
432     xorg_list_for_each_entry_safe(cur, next, &evinfo->evregion.list, link)
433     {
434         xorg_list_del(&cur->link);
435         free (cur);
436         cur = NULL;
437     }
438     evinfo->evregion.init = 0;
439     evinfo->evregion.size = 0;
440 }
441
442 char* xDbgGetAtom(Atom atom, EvlogInfo *evinfo, char *reply, int *len)
443 {
444     EvlogAtomTable *table;
445 #ifndef XDBG_CLIENT
446     table = malloc (sizeof(EvlogAtomTable));
447     if (!table)
448         return reply;
449
450     evinfo->mask |= EVLOG_MASK_ATOM;
451     table->xid = atom;
452
453     if (!evinfo->evatom.init)
454     {
455         xorg_list_init(&evinfo->evatom.list);
456         evinfo->evatom.init = 1;
457     }
458
459     if (NameForAtom(atom))
460         snprintf (table->buf, XDBG_BUF_SIZE, "%s", (char*)NameForAtom(atom));
461     else
462         snprintf (table->buf, XDBG_BUF_SIZE, "0x%lx", atom);
463
464     xorg_list_add(&table->link, &evinfo->evatom.list);
465     evinfo->evatom.size++;
466 #endif
467     xorg_list_for_each_entry(table, &evinfo->evatom.list, link)
468         if(table->xid == atom)
469         {
470             REPLY ("(%s)", table->buf);
471             break;
472         }
473
474     return reply;
475 }
476
477 char* xDbgGetRegion(XserverRegion region, EvlogInfo *evinfo, char *reply, int *len)
478 {
479     EvlogRegionTable *table;
480 #ifndef XDBG_CLIENT
481     extern _X_EXPORT RESTYPE RegionResType;
482     RegionPtr pRegion;
483     BoxPtr rects;
484     int nrect, i;
485     int s;
486     int err = dixLookupResourceByType((pointer *) &pRegion, region,
487                                        RegionResType, (ClientPtr)evinfo->client.pClient,
488                                        DixReadAccess);
489
490     evinfo->mask |= EVLOG_MASK_REGION;
491
492     if (!evinfo->evregion.init)
493     {
494         xorg_list_init(&evinfo->evregion.list);
495         evinfo->evregion.init = 1;
496     }
497
498         if (err != Success)
499         {
500         table = malloc (sizeof(EvlogAtomTable));
501         if (!table)
502             return reply;
503
504         table->xid = region;
505
506         snprintf (table->buf, XDBG_BUF_SIZE, "0x%lx", region);
507         xorg_list_add(&table->link, &evinfo->evregion.list);
508         evinfo->evregion.size++;
509     }
510     else
511     {
512         nrect = RegionNumRects(pRegion);
513         rects = RegionRects(pRegion);
514
515         for (i = 0; i < nrect; i++)
516         {
517             table = malloc (sizeof(EvlogAtomTable));
518             if (!table)
519                 return reply;
520
521             table->xid = region;
522
523             s = 0;
524             s += snprintf (table->buf + s, XDBG_BUF_SIZE - s,
525                            "[%d,%d %dx%d]",
526                                rects[i].x1,
527                                rects[i].y1,
528                                rects[i].x2 - rects[i].x1,
529                                rects[i].y2 - rects[i].y1);
530             xorg_list_add(&table->link, &evinfo->evregion.list);
531             evinfo->evregion.size++;
532         }
533     }
534
535 #endif
536     REPLY("(");
537     xorg_list_for_each_entry(table, &evinfo->evregion.list, link)
538         if(table->xid == region)
539         {
540             REPLY ("%s", table->buf);
541             if(table != xorg_list_last_entry(&evinfo->evregion.list, EvlogRegionTable, link))
542                 REPLY (", ");
543         }
544     REPLY(")");
545
546     return reply;
547 }