add xevlog_analyze function
[platform/adaptation/xf86-module-xdbg.git] / module / xdbg_module_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 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <sys/types.h>
40 #include <sys/fcntl.h>
41 #include <unistd.h>
42 #include <stdarg.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <time.h>
46
47 #define __USE_GNU
48 #include <sys/socket.h>
49 #include <linux/socket.h>
50
51 #ifdef HAS_GETPEERUCRED
52 # include <ucred.h>
53 #endif
54
55 #include <xace.h>
56 #include <xacestr.h>
57 #include <X11/Xatom.h>
58 #include <X11/extensions/XI2proto.h>
59 #include <windowstr.h>
60
61 #include <xdbg.h>
62 #include "xdbg_types.h"
63 #include "xdbg_module.h"
64 #include "xdbg_module_evlog.h"
65 #include "xdbg_evlog.h"
66
67 #define XREGISTRY
68 #include "registry.h"
69
70 #define FP1616toDBL(x) ((x) * 1.0 / (1 << 16))
71
72 static Bool     xev_trace_on = FALSE;
73 static int  xev_trace_fd = -1;
74 static int  xev_trace_record_fd = -1;
75 static Atom atom_rotate = None;
76 static Atom atom_client_pid = None;
77
78 static void evtRecord (int fd, EvlogInfo *evinfo)
79 {
80     int write_len = 0;
81
82     XDBG_RETURN_IF_FAIL (fd >= 0)
83
84     if (evinfo)
85     {
86         evinfo->mask = 0;
87
88         write_len = sizeof (int) +
89                     sizeof (EvlogType) +
90                     sizeof (int) +
91                     sizeof (CARD32);
92
93         evinfo->mask |= EVLOG_MASK_CLIENT;
94         write_len += sizeof (EvlogClient);
95
96         if (evinfo->type == REQUEST)
97         {
98             evinfo->mask |= EVLOG_MASK_REQUEST;
99             write_len += sizeof (EvlogRequest) + sizeof (xReq);
100         }
101         else if (evinfo->type == EVENT)
102         {
103             evinfo->mask |= EVLOG_MASK_EVENT;
104             write_len += sizeof (EvlogEvent) + sizeof (xEvent);
105         }
106     }
107
108     if (write (xev_trace_record_fd, &write_len, sizeof(int)) == -1)
109     {
110         XDBG_ERROR (MXDBG, "failed: write write_len\n");
111         return;
112     }
113
114     if (evinfo)
115     {
116         if (write (xev_trace_record_fd, &evinfo->time, sizeof(CARD32)) == -1)
117         {
118             XDBG_ERROR (MXDBG, "failed: write msec\n");
119             return;
120         }
121         if (write (xev_trace_record_fd, &evinfo->type, sizeof(EvlogType)) == -1)
122         {
123             XDBG_ERROR (MXDBG, "failed: write type\n");
124             return;
125         }
126         if (write (xev_trace_record_fd, &evinfo->mask, sizeof(int)) == -1)
127         {
128             XDBG_ERROR (MXDBG, "failed: write mask\n");
129             return;
130         }
131         if (write (xev_trace_record_fd, &evinfo->client, sizeof (EvlogClient)) == -1)
132         {
133             XDBG_ERROR (MXDBG, "failed: write client\n");
134             return;
135         }
136
137         if (evinfo->type == REQUEST)
138         {
139             if (write (xev_trace_record_fd, &evinfo->req, sizeof (EvlogRequest)) == -1)
140             {
141                 XDBG_ERROR (MXDBG, "failed: write request\n");
142                 return;
143             }
144             if (write (xev_trace_record_fd, evinfo->req.ptr, sizeof (xReq)) == -1)
145             {
146                 XDBG_ERROR (MXDBG, "failed: write request\n");
147                 return;
148             }
149         }
150         else if (evinfo->type == EVENT)
151         {
152             if (write (xev_trace_record_fd, &evinfo->evt, sizeof (EvlogEvent)) == -1)
153             {
154                 XDBG_ERROR (MXDBG, "failed: write event\n");
155                 return;
156             }
157             if (write (xev_trace_record_fd, evinfo->evt.ptr, sizeof (xEvent)) == -1)
158             {
159                 XDBG_ERROR (MXDBG, "failed: write event\n");
160                 return;
161             }
162         }
163     }
164 }
165
166 static void evtPrintF (int fd, EvlogInfo *evinfo)
167 {
168     char log[1024];
169     int size = sizeof (log);
170
171     xDbgEvlogFillLog (evinfo, log, &size);
172
173     if (fd < 0)
174         ErrorF ("%s", log);
175     else
176         dprintf (fd, "%s", log);
177 }
178
179 static void evtPrint (EvlogType type, ClientPtr client, xEvent *ev)
180 {
181     EvlogInfo evinfo = {0,};
182
183     if (xev_trace_on == FALSE)
184         return;
185
186     /* evinfo.type */
187     evinfo.type = type;
188
189     /* evinfo.client */
190     if (client)
191     {
192         ModuleClientInfo *info = GetClientInfo (client);
193         XDBG_RETURN_IF_FAIL (info != NULL);
194
195         evinfo.mask |= EVLOG_MASK_CLIENT;
196         evinfo.client.index = info->index;
197         evinfo.client.pid = info->pid;
198         evinfo.client.gid = info->gid;
199         evinfo.client.uid = info->uid;
200         strncpy (evinfo.client.command, info->command, strlen (info->command));
201
202         /* evinfo.req */
203         if (type == REQUEST)
204         {
205             REQUEST (xReq);
206
207             evinfo.mask |= EVLOG_MASK_REQUEST;
208             evinfo.req.id = stuff->reqType;
209             evinfo.req.length = client->req_len;
210             evinfo.req.ptr = client->requestBuffer;
211
212             if (stuff->reqType < EXTENSION_BASE)
213                 snprintf (evinfo.req.name, sizeof (evinfo.req.name), "%s",
214                           LookupRequestName (stuff->reqType, 0));
215             else
216                 snprintf (evinfo.req.name, sizeof (evinfo.req.name), "%s",
217                           LookupRequestName (stuff->reqType, stuff->data));
218         }
219     }
220
221     /* evinfo.evt */
222     if (ev)
223     {
224         XDBG_RETURN_IF_FAIL (type == EVENT);
225
226         evinfo.mask |= EVLOG_MASK_EVENT;
227         evinfo.evt.ptr = ev;
228         snprintf (evinfo.evt.name, sizeof (evinfo.evt.name), "%s",
229                   LookupEventName ((int)(ev->u.u.type)));
230     }
231
232     /* evinfo.time */
233     evinfo.time = GetTimeInMillis ();
234
235     if (!xDbgEvlogRuleValidate (&evinfo))
236         return;
237
238     if (xev_trace_record_fd >= 0)
239         evtRecord (xev_trace_record_fd, &evinfo);
240     else
241         evtPrintF (xev_trace_fd, &evinfo);
242 }
243
244 static const char*
245 _traceGetWindowName (ClientPtr client, Window window)
246 {
247     int rc;
248     WindowPtr pWin;
249     Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
250     Atom property;
251     PropertyPtr pProp;
252     static char winname[128];
253     int datalen;
254
255     rc = dixLookupWindow (&pWin, window, client, win_mode);
256     if (rc != Success)
257         return NULL;
258
259     property = MakeAtom ("WM_NAME", strlen ("WM_NAME"), TRUE);
260     while (pWin)
261     {
262         rc = dixLookupProperty (&pProp, pWin, property, client, prop_mode);
263         if (rc == Success && pProp->data)
264         {
265             datalen = (pProp->size>127) ?127:pProp->size;
266             strncpy (winname, pProp->data, datalen);
267             winname[datalen] = 0;
268
269             return winname;
270         }
271
272         pWin = pWin->parent;
273     }
274
275     return NULL;
276 }
277
278 static void
279 _traceFlush (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
280 {
281     evtPrint (FLUSH, NULL, NULL);
282 }
283
284 static void
285 _traceAReply (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
286 {
287     ReplyInfoRec *pri = (ReplyInfoRec*)calldata;
288
289     evtPrint (REPLY, pri->client, NULL);
290 }
291
292 static void
293 _traceEvent (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
294 {
295     EventInfoRec *pei = (EventInfoRec*)calldata;
296     ClientPtr pClient;
297     ModuleClientInfo *info;
298     int ev; /* event index */
299     static int xi2_opcode = -1;
300     xEvent *pev;
301     static char* ename[]=
302     {
303         "KeyPress",
304         "KeyRelease",
305         "ButtonPress",
306         "ButtonRelease",
307     };
308
309     XDBG_RETURN_IF_FAIL (pei != NULL);
310
311     pClient = pei->client;
312     XDBG_RETURN_IF_FAIL (pClient != NULL);
313
314     pev = pei->events;
315     XDBG_RETURN_IF_FAIL (pev != NULL);
316
317     info = GetClientInfo (pClient);
318     XDBG_RETURN_IF_FAIL (info != NULL);
319
320     for (ev=0; ev < pei->count; ev++, pev++)
321     {
322         int type = pev->u.u.type & 0177;
323
324         if (type < LASTEvent)
325         {
326             switch (type)
327             {
328             case KeyPress:
329             case KeyRelease:
330                 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
331                         , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
332                         , info->command, info->pid
333                         , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
334                         , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
335                         , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
336                 break;
337
338             case ButtonPress:
339             case ButtonRelease:
340                 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
341                         , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
342                         , info->command, info->pid
343                         , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
344                         , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
345                         , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
346                 break;
347             case GenericEvent:
348                 if(!xi2_opcode) break;
349                 if(xi2_opcode < 0)
350                 {
351                     ExtensionEntry *pExt = CheckExtension("XInputExtension");
352                     if(!pExt) xi2_opcode = 0;
353                     else xi2_opcode = pExt->base;
354                 }
355
356                 if(((xGenericEvent*)pev)->extension != xi2_opcode) break;
357
358                 xXIDeviceEvent *xidev = (xXIDeviceEvent *)pev;
359                 if(xidev->deviceid==2) break;
360                 if(xidev->evtype==XI_ButtonPress)
361                     XDBG_TRACE (MXDBG, "XI_ButtonPress(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_ButtonPress, xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
362                 else if(xidev->evtype==XI_ButtonRelease)
363                     XDBG_TRACE (MXDBG, "XI_ButtonRelease(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_ButtonRelease,  xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
364                 else if(xidev->evtype==XI_Motion)
365                     XDBG_TRACE (MXDBG, "XI_Motion(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_Motion, xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
366                 break;
367             default:
368                 break;
369             }
370         }
371
372         evtPrint (EVENT, pClient, pev);
373     }
374 }
375
376 static void
377 _traceACoreEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
378 {
379     XaceCoreDispatchRec *rec = calldata;
380
381     XDBG_RETURN_IF_FAIL (rec != NULL);
382
383     evtPrint (REQUEST, rec->client, NULL);
384 }
385
386 static void
387 _traceAExtEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
388 {
389     XaceExtAccessRec *rec = calldata;
390
391     XDBG_RETURN_IF_FAIL (rec != NULL);
392
393     evtPrint (REQUEST, rec->client, NULL);
394 }
395
396 static void
397 _traceProperty (CallbackListPtr *pcbl, pointer unused, pointer calldata)
398 {
399     XacePropertyAccessRec *rec = calldata;
400     ModuleClientInfo *info = GetClientInfo (rec->client);
401     PropertyPtr pProp = *rec->ppProp;
402     Atom name = pProp->propertyName;
403
404     /* Don't care about the new content check */
405     if (rec->client == serverClient || rec->access_mode & DixPostAccess)
406         return;
407
408     if (name == atom_client_pid && (rec->access_mode & DixWriteAccess))
409     {
410         XDBG_WARNING (MXDBG, "Invalid access X_CLINET_PID pid:%d, uid:%d\n", info->pid, info->uid);
411         rec->status = BadAccess;
412         return;
413     }
414
415     rec->status = Success;
416     return;
417 }
418
419 static void
420 _traceResource (CallbackListPtr *pcbl, pointer unused, pointer calldata)
421 {
422     XaceResourceAccessRec *rec = calldata;
423     Mask access_mode = rec->access_mode;
424     ModuleClientInfo *info = GetClientInfo (rec->client);
425
426     /* Perform the background none check on windows */
427     if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW)
428     {
429         WindowPtr pWin = (WindowPtr) rec->res;
430         int rc;
431         int pid = info->pid;
432
433         rc = dixChangeWindowProperty (serverClient,
434                                       pWin, atom_client_pid, XA_CARDINAL, 32,
435                                       PropModeReplace, 1, &pid, FALSE);
436         if (rc != Success)
437             XDBG_ERROR (MXDBG, "failed : set X_CLIENT_PID to %d.\n", pid);
438     }
439 }
440
441 static void
442 _traceReceive (CallbackListPtr *pcbl, pointer unused, pointer calldata)
443 {
444     XaceReceiveAccessRec *rec = calldata;
445
446     if (rec->events->u.u.type != VisibilityNotify)
447         return;
448
449     rec->status = BadAccess;
450 }
451
452 Bool
453 xDbgModuleEvlogInstallHooks (XDbgModule *pMod)
454 {
455     int ret = TRUE;
456
457     ret &= AddCallback (&EventCallback, _traceEvent, NULL);
458     ret &= AddCallback (&FlushCallback, _traceFlush, NULL);
459     ret &= AddCallback (&ReplyCallback, _traceAReply, NULL);
460     ret &= XaceRegisterCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
461     ret &= XaceRegisterCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
462
463     /*Disable Visibility Event*/
464     ret &= XaceRegisterCallback (XACE_RECEIVE_ACCESS, _traceReceive, NULL);
465
466     if (atom_client_pid == None)
467         atom_client_pid = MakeAtom ("X_CLIENT_PID", 12, TRUE);
468     if (atom_rotate == None)
469         atom_rotate = MakeAtom ("_E_ILLUME_ROTATE_ROOT_ANGLE", 12, TRUE);
470
471     if (!ret)
472     {
473         XDBG_ERROR (MXDBG, "failed: register one or more callbacks\n");
474         return FALSE;
475     }
476
477     if (pMod && pMod->evlog_path)
478         xDbgModuleEvlogSetEvlogPath (pMod, -1, pMod->evlog_path, NULL, NULL);
479
480     return TRUE;
481 }
482
483 void
484 xDbgModuleEvlogUninstallHooks (XDbgModule *pMod)
485 {
486     DeleteCallback (&EventCallback, _traceEvent, NULL);
487     DeleteCallback (&FlushCallback, _traceFlush, NULL);
488     DeleteCallback (&ReplyCallback, _traceAReply, NULL);
489     XaceDeleteCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
490     XaceDeleteCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
491 }
492
493 void
494 xDbgModuleEvlogPrintEvents (XDbgModule *pMod, Bool on, const char * client_name, char *reply, int *len)
495 {
496     int ret = TRUE;
497
498     xev_trace_on = on;
499
500     if (xev_trace_on)
501     {
502         int i;
503
504         //Find client's pid
505         for (i=1 ; i< currentMaxClients ; i++)
506         {
507             ClientPtr pClient;
508             ModuleClientInfo *info;
509
510             pClient = clients[i];
511             if (!pClient)
512                 continue;
513
514             info = GetClientInfo (pClient);
515             if (!info)
516                 continue;
517
518             if (strlen (info->command) > 0 && strstr (client_name, info->command))
519             {
520                 char fd_name[256];
521
522                 if (xev_trace_fd >= 0)
523                     close (xev_trace_fd);
524
525                 snprintf (fd_name, 256, "/proc/%d/fd/1", info->pid);
526                 xev_trace_fd = open (fd_name, O_RDWR);
527                 if (xev_trace_fd < 0)
528                     XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
529             }
530         }
531
532
533         ret &= XaceRegisterCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
534         ret &= XaceRegisterCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
535
536         if (!ret)
537         {
538             XDBG_REPLY ("failed: register one or more callbacks.\n");
539             return;
540         }
541     }
542     else
543     {
544         XaceDeleteCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
545         XaceDeleteCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
546     }
547
548     return;
549 }
550
551 int
552 xDbgModuleEvlogInfoSetRule (XDbgModule *pMod, const int argc, const char ** argv, char *reply, int *len)
553 {
554     return xDbgEvlogRuleSet (argc, argv, reply, len);
555 }
556
557 Bool
558 xDbgModuleEvlogSetEvlogPath (XDbgModule *pMod, int pid, char *path, char *reply, int *len)
559 {
560     char fd_name[XDBG_PATH_MAX];
561     char *temp[3] = {"/", "./", "../"};
562     Bool valid = FALSE;
563     int i;
564
565     if (!path || strlen (path) <= 0)
566     {
567         XDBG_REPLY ("failed: invalid path\n");
568         return FALSE;
569     }
570
571     if (xev_trace_record_fd >= 0)
572     {
573         close (xev_trace_record_fd);
574         xev_trace_record_fd = -1;
575     }
576
577     if (!strcmp (path, "console"))
578     {
579         if (pid > 0)
580         {
581             char fd_name[256];
582
583             if (xev_trace_fd >= 0)
584                 close (xev_trace_fd);
585
586             snprintf (fd_name, sizeof (fd_name), "/proc/%d/fd/1", pid);
587
588             xev_trace_fd = open (fd_name, O_RDWR);
589             if (xev_trace_fd < 0)
590                 XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
591         }
592
593         return TRUE;
594     }
595
596     for (i = 0; i < sizeof (temp) / sizeof (char*); i++)
597         if (path == strstr (path, temp[i]))
598         {
599             valid = TRUE;
600             break;
601         }
602
603     if (!valid)
604     {
605         XDBG_REPLY ("failed: invalid path(%s)\n", path);
606         return FALSE;
607     }
608
609     if (path[0] == '/')
610         snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
611     else
612     {
613         char cwd[128];
614         if (getcwd (cwd, sizeof (cwd)))
615             snprintf (fd_name, XDBG_PATH_MAX, "%s/%s", cwd, path);
616         else
617             snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
618     }
619
620     xev_trace_record_fd = open (fd_name, O_CREAT|O_RDWR|O_APPEND, 0755);
621     if (xev_trace_record_fd < 0)
622     {
623         XDBG_REPLY ("failed: open file '%s'. (%s)\n", fd_name, strerror(errno));
624         return FALSE;
625     }
626
627     return TRUE;
628 }