tizen 2.4 release
[adaptation/xorg/driver/xserver-xorg-module-xdbg.git] / module / xdbg_module_command.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 <sys/types.h>
37 #include <sys/stat.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <windowstr.h>
43 #include <xacestr.h>
44 #include <xdbg.h>
45 #include "xdbg_types.h"
46 #include <xf86Priv.h>
47 #include "xdbg_dump_module.h"
48 #include "xdbg_module.h"
49 #include "xdbg_module_clist.h"
50 #include "xdbg_module_plist.h"
51 #include "xdbg_module_evlog.h"
52 #include "xdbg_module_drmevent.h"
53 #include "xdbg_module_fpsdebug.h"
54 #include "xdbg_module_command.h"
55
56 static void
57 _CommandDLog (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
58 {
59     int on;
60
61     if (argc != 3)
62     {
63         XDBG_REPLY ("DLog level: %d\n", xDbgGetLogEnableDlog() ? 1 : 0);
64         return;
65     }
66
67     on = atoi (argv[2]);
68
69     xDbgLogEnableDlog (on);
70
71     XDBG_REPLY ("Success\n");
72 }
73
74 static Bool
75 _CommandSetLogFile (int pid, char *path, char *reply, int *len, XDbgModule *pMod)
76 {
77     static int old_stderr = -1;
78     char fd_name[XDBG_PATH_MAX];
79     int  log_fd = -1;
80     FILE *log_fl;
81
82     if (!path || strlen (path) <= 0)
83     {
84         XDBG_REPLY ("failed: logpath is invalid\n");
85         return FALSE;
86     }
87
88     if (old_stderr == -1)
89         old_stderr = dup (STDERR_FILENO);
90
91     if (!strcmp (path, "console"))
92         snprintf (fd_name, XDBG_PATH_MAX, "/proc/%d/fd/1", pid);
93     else
94     {
95         if (path[0] == '/')
96             snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
97         else
98         {
99             if (pMod->cwd)
100                 snprintf (fd_name, XDBG_PATH_MAX, "%s/%s", pMod->cwd, path);
101             else
102                 snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
103         }
104     }
105
106     log_fl = fopen (fd_name, "a");
107     if (!log_fl)
108     {
109         XDBG_REPLY ("failed: open file(%s)\n", fd_name);
110         return FALSE;
111     }
112
113     fflush (stderr);
114     close (STDERR_FILENO);
115
116     setvbuf (log_fl, NULL, _IOLBF, 512);
117     log_fd = fileno (log_fl);
118
119     dup2 (log_fd, STDERR_FILENO);
120     fclose (log_fl);
121
122     if (pMod->log_path)
123         free (pMod->log_path);
124
125     pMod->log_path = strdup (fd_name);
126     XDBG_RETURN_VAL_IF_FAIL (pMod->log_path != NULL, FALSE);
127
128     XDBG_REPLY ("log path: %s\n", pMod->log_path);
129
130     return TRUE;
131 }
132
133
134 static void
135 _CommandLogPath (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
136 {
137     if (argc != 3)
138     {
139         XDBG_REPLY ("log path: %s\n", (pMod->log_path)?pMod->log_path:"stderr");
140         return;
141     }
142
143     _CommandSetLogFile (pid, argv[2], reply, len, pMod);
144 }
145
146 static void
147 _CommandSetLogLevel (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
148 {
149     Bool ret;
150     char *module_name;
151     int level;
152
153     if (argc < 4)
154     {
155         xDbgLogEnumModules (MODE_WITH_STATUS, reply, len);
156         return;
157     }
158
159     module_name = argv[2];
160     level = atoi (argv[3]);
161
162     if (level < 0 || level >= 5)
163     {
164         XDBG_REPLY ("Error : Not valid log level %d.\n", level);
165         return;
166     }
167
168     ret = xDbgLogSetLevel (xDbgLogGetModule (module_name), level);
169
170     if (ret)
171         XDBG_REPLY ("Log level for module %s was successfully set to %d\n",
172                   module_name, level);
173     else
174         XDBG_REPLY ("Error : An error was occured during log level setting\n");
175 }
176
177 static void
178 _CommandClientList (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
179 {
180     if (argc != 2)
181     {
182         XDBG_REPLY ("Error : too few arguments\n");
183         return;
184     }
185
186     xDbgModuleCList (pMod, reply, len);
187 }
188
189 static void
190 _CommandPixmapList (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
191 {
192     if (argc != 2)
193     {
194         XDBG_REPLY ("Error : too few arguments\n");
195         return;
196     }
197
198     xDbgModulePList (pMod, reply, len);
199 }
200
201 static void
202 _CommandEvlog (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
203 {
204     int on;
205     extern Bool xev_trace_on;
206
207     if (argc != 3)
208     {
209         XDBG_REPLY ("Evlog level: %d\n", xev_trace_on ? 1 : 0);
210         return;
211     }
212
213     on = atoi (argv[2]);
214
215     xDbgModuleEvlogPrintEvents (pMod, on, argv[0], reply, len);
216
217     XDBG_REPLY ("Success\n");
218 }
219
220 static void
221 _CommandEvlogDetail (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
222 {
223     int level;
224     extern int xev_trace_detail_level;
225
226     if (argc != 3)
227     {
228         XDBG_REPLY ("Detail Level: %d\n", xev_trace_detail_level);
229         return;
230     }
231
232     level = atoi(argv[2]);
233
234     xDbgModuleEvlogDetail (pMod, level, reply, len);
235     XDBG_REPLY ("Success\n");
236 }
237
238 static void
239 _CommandSetEvlogRule (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
240 {
241     if (argc < 2)
242     {
243         XDBG_REPLY ("Error : invalid number of arguments.\n");
244         return;
245     }
246
247     if (argc > 2 && argv[2] && !strcmp (argv[2], "file"))
248     {
249         if (argc < 4 || !argv[3])
250         {
251             XDBG_REPLY ("Error : no evlog rule file.\n");
252             return;
253         }
254
255         if (pMod->evlog_rule_path)
256             free (pMod->evlog_rule_path);
257
258         pMod->evlog_rule_path = strdup (argv[3]);
259     }
260
261     xDbgModuleEvlogInfoSetRule (pMod, argc - 2, (const char**)&(argv[2]), reply, len);
262 }
263
264 static void
265 _CommandSetEvlogPath (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
266 {
267     if (argc != 3)
268     {
269         XDBG_REPLY ("evlog path: %s\n", (pMod->evlog_path)?pMod->evlog_path:"none");
270         return;
271     }
272
273     if (!argv[2] || strlen (argv[2]) <= 0)
274     {
275         XDBG_REPLY ("invalid option\n");
276         return;
277     }
278
279     if (pMod->evlog_path)
280     {
281         free (pMod->evlog_path);
282         pMod->evlog_path=NULL;
283     }
284
285     if (!xDbgModuleEvlogSetEvlogPath (pMod, pid, argv[2], reply, len))
286     {
287         XDBG_REPLY ("Error: evlog path(%s)\n", argv[2]);
288         return;
289     }
290
291     pMod->evlog_path = strdup (argv[2]);
292     if (!pMod->evlog_path) {
293         XDBG_REPLY ("Failed to allocate memory to evlog_path\n");
294         return;
295     }
296
297     if (!strcmp (pMod->evlog_path, "console"))
298         XDBG_REPLY ("/proc/%d/fd/1", pid);
299     else if (pMod->evlog_path[0] == '/')
300         XDBG_REPLY ("evlog path: %s\n", pMod->evlog_path);
301     else
302         XDBG_REPLY ("evlog path: %s/%s\n", pMod->cwd, pMod->evlog_path);
303 }
304
305 static void
306 _CommandDrmEventPending (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
307 {
308     if (argc != 2)
309     {
310         XDBG_REPLY ("Error : too few arguments\n");
311         return;
312     }
313
314     xDbgModuleDrmEventPending (pMod, reply, len);
315 }
316
317 static void
318 _CommandFpsDebug (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
319 {
320     int on;
321
322     if (argc != 3)
323     {
324         XDBG_REPLY ("Error : too few arguments\n");
325         return;
326     }
327
328     on = atoi (argv[2]);
329
330     xDbgModuleFpsDebug (pMod, on, reply, len);
331
332     XDBG_REPLY ("Success\n");
333 }
334
335 static char *
336 _printDumpOption (char *reply, int *len)
337 {
338     if (xDbgDumpGetType ())
339         XDBG_REPLY ("type:%s ", xDbgDumpGetType ());
340     if (xDbgDumpGetCount ())
341         XDBG_REPLY ("count:%s ", xDbgDumpGetCount ());
342     if (xDbgDumpGetFile ())
343         XDBG_REPLY ("file:%s ", xDbgDumpGetFile ());
344     if (xDbgDumpGetCrop ())
345         XDBG_REPLY ("crop:%s ", xDbgDumpGetCrop ());
346
347     return reply;
348 }
349
350 static void
351 _CommandDump (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod)
352 {
353     int i;
354     char *c;
355
356     if (argc < 3)
357     {
358         reply = _printDumpOption (reply, len);
359         XDBG_REPLY("\n");
360         return;
361     }
362
363     for (i = 0; i < argc; i++)
364     {
365         char *c = argv[i];
366         if (*c != '-')
367             continue;
368
369         if (!strcmp (c, "-type"))
370         {
371             c = argv[++i];
372             if (!xDbgDumpSetType (c))
373             {
374                 XDBG_REPLY ("fail: set '%s' (already running)\n", c);
375                 return;
376             }
377         }
378         else if (!strcmp (c, "-count"))
379         {
380             c = argv[++i];
381             if (!xDbgDumpSetCount (c))
382             {
383                 XDBG_REPLY ("fail: set '%s' (already running)\n", c);
384                 return;
385             }
386         }
387         else if (!strcmp (c, "-file"))
388         {
389             c = argv[++i];
390             if (!xDbgDumpSetFile (c))
391             {
392                 XDBG_REPLY ("fail: set '%s' (already running)\n", c);
393                 return;
394             }
395         }
396         else if (!strcmp (c, "-crop"))
397         {
398             c = argv[++i];
399             if (!xDbgDumpSetCrop (c))
400             {
401                 XDBG_REPLY ("fail: set '%s' (already running)\n", c);
402                 return;
403             }
404         }
405     }
406
407     c = argv[2];
408     if (!strcmp (c, "on"))
409     {
410         xDbgDumpPrepare ();
411         XDBG_REPLY ("'%s'", c);
412         reply = _printDumpOption (reply, len);
413     }
414     else if (!strcmp (c, "off"))
415     {
416         xDbgDumpSave ();
417         xDbgDumpClear ();
418         XDBG_REPLY ("'%s' ", c);
419     }
420     else if (!strcmp (c, "clear"))
421     {
422         xDbgDumpClear ();
423         XDBG_REPLY ("'%s' ", c);
424     }
425     else if (*c != '-')
426     {
427         XDBG_REPLY ("unknown option '%s'\n", c);
428         return;
429     }
430
431     XDBG_REPLY ("success\n");
432 }
433
434 static struct
435 {
436     const char *Cmd;
437     const char *Description;
438     const char *Options;
439
440     int       (*DynamicUsage) (int, char*, int *);
441     const char *DetailedUsage;
442
443     void (*func) (int pid, int argc, char **argv, char *reply, int *len, XDbgModule *pMod);
444 } command_proc[] =
445 {
446     {
447         "dlog", "to enable dlog", "[0-1]",
448         NULL, "[OFF:0/ON:1]",
449         _CommandDLog
450     },
451
452     {
453         "log_path", "to set log path", "[console/filepath]",
454         NULL, "[console/filepath]",
455         _CommandLogPath
456     },
457
458     {
459         "log", "to set loglevel", "[MODULE] [0-4]",
460         (int(*)(int, char*, int*))xDbgLogEnumModules, "[DEBUG:0/TRACE:1/INFO:2/WARNING:3/ERROR:4]",
461         _CommandSetLogLevel
462     },
463
464     {
465         "clist", "to print clients", "",
466         NULL, "",
467         _CommandClientList
468     },
469
470     {
471         "plist", "to print pixmap list", "",
472         NULL, "",
473         _CommandPixmapList
474     },
475
476     {
477         "evlog", "to print x events", "[0-1]",
478         NULL, "[OFF:0/ON:1]",
479         _CommandEvlog
480     },
481
482     {
483         "evlog_detail", "to set printing detail log level", "[0-2]",
484         NULL, "[Primary logs:0/ More detail logs:1/ Supplementary Reply logs:2]",
485         _CommandEvlogDetail
486     },
487
488     {
489         "evlog_rule", "to set evlog rules", "[add/remove/file/print/help]",
490         NULL, "[add allow/deny rules / remove (index) / file(file_name) / print / help]",
491         _CommandSetEvlogRule
492     },
493
494     {
495         "evlog_path", "to set filepath of evlog", "[console/filepath]",
496         NULL, "[console/filepath]",
497         _CommandSetEvlogPath
498     },
499
500     {
501         "drmevent_pending", "to print pending drmvents", "",
502         NULL, "",
503         _CommandDrmEventPending
504     },
505
506     {
507         "fpsdebug", "to print fps", "[0-1]",
508         NULL, "[OFF:0/ON:1]",
509         _CommandFpsDebug
510     },
511
512     {
513         "dump", "to dump buffers", "[on,off,clear]",
514         NULL, "[on,off,clear] -type [ui,drawable,fb,video] -count [n] -file [bmp,raw]",
515         _CommandDump
516     },
517 };
518
519 static void _CommandPrintUsage (char *reply, int *len, const char * exec)
520 {
521     int option_cnt = sizeof (command_proc) / sizeof (command_proc[0]);
522     int i;
523
524     XDBG_REPLY ("Usage : %s [cmd] [options]\n", exec);
525     XDBG_REPLY ("     ex)\n");
526
527     for (i=0; i<option_cnt; i++)
528         XDBG_REPLY ("           %s %s %s\n", exec, command_proc[i].Cmd, command_proc[i].Options);
529
530     XDBG_REPLY (" options :\n");
531
532     for (i=0; i<option_cnt; i++)
533     {
534         if (command_proc[i].Cmd && command_proc[i].Description)
535             XDBG_REPLY ("  %s (%s)\n", command_proc[i].Cmd, command_proc[i].Description);
536         else
537             XDBG_REPLY ("  Cmd(%p) or Descriptiont(%p).\n", command_proc[i].Cmd, command_proc[i].Description);
538
539         if (command_proc[i].DynamicUsage)
540         {
541             char dyn[1024];
542             int  dynlen = sizeof (dyn);
543             command_proc[i].DynamicUsage (MODE_NAME_ONLY, dyn, &dynlen);
544             XDBG_REPLY ("     [MODULE:%s]\n", dyn);
545         }
546
547         if (command_proc[i].DetailedUsage)
548             XDBG_REPLY ("     %s\n", command_proc[i].DetailedUsage);
549         else
550             XDBG_REPLY ("  DetailedUsage(%p).\n", command_proc[i].DetailedUsage);
551     }
552 }
553
554 void
555 xDbgModuleCommand (void *data, int argc, char **argv, char *reply, int *len)
556 {
557     XDbgModule *pMod = (XDbgModule*)data;
558     int nproc = sizeof (command_proc) / sizeof (command_proc[0]);
559     int i, pid, new_argc;
560     char **new_argv;
561
562     pid = atoi (argv[0]);
563     pMod->cwd = strdup (argv[1]);
564
565     new_argc = argc - 2;
566     new_argv = (char**)malloc (new_argc * sizeof (char*));
567     if (!new_argv)
568     {
569         XDBG_REPLY ("Error : malloc new_argv\n");
570         return;
571     }
572
573     for (i = 0; i < new_argc; i++)
574         new_argv[i] = argv[i+2];
575
576     if (argc < 4)
577     {
578         _CommandPrintUsage (reply, len, new_argv[0]);
579         free (new_argv);
580         return;
581     }
582
583     for (i = 0; i < nproc; i++)
584     {
585         if (!strcmp (new_argv[1], command_proc[i].Cmd) ||
586             (new_argv[1][0] == '-' && !strcmp (1 + new_argv[1], command_proc[i].Cmd)))
587         {
588             command_proc[i].func (pid, new_argc, new_argv, reply, len, pMod);
589             free (new_argv);
590             return;
591         }
592     }
593
594     _CommandPrintUsage (reply, len, new_argv[0]);
595
596     free (new_argv);
597 }
598
599 Bool
600 xDbgModuleCommandInitLogPath (XDbgModule *pMod, char *log_path)
601 {
602     char reply[1024];
603     int len = sizeof (reply);
604
605     if (log_path && strlen (log_path) > 0)
606     {
607         char newname[XDBG_PATH_MAX];
608         char filename[XDBG_PATH_MAX];
609         struct stat status;
610         char *p = NULL, *last = NULL;
611         int i;
612
613         snprintf (newname, XDBG_PATH_MAX, "%s", log_path);
614
615         for (i = 0; i < strlen (newname); i++)
616         {
617             p = newname + i;
618             if (*p == '/')
619                 last = p;
620         }
621
622         snprintf (filename, XDBG_PATH_MAX, "%s", last + 1);
623         snprintf (last, XDBG_PATH_MAX - (last - newname), "/prev.%s", filename);
624
625         if (!stat (log_path, &status))
626         {
627             if (rename (log_path, newname))
628             {
629                 XDBG_ERROR (MXDBG, "Failed: rename %s -> %s\n", log_path, newname);
630                 return FALSE;
631             }
632         }
633
634         _CommandSetLogFile (0, log_path, reply, &len, pMod);
635     }
636     else
637         _CommandSetLogFile (0, "console", reply, &len, pMod);
638
639     return TRUE;
640 }
641
642 Bool
643 xDbgModuleCommandInitEvlogRulePath (XDbgModule *pMod, char *evlog_rule_path)
644 {
645     char reply[4096];
646     int len = sizeof (reply);
647     char *argv[4];
648     int argc = 4;
649
650     if (!evlog_rule_path || strlen (evlog_rule_path) <= 0)
651         return TRUE;
652
653     argv[0] = "unknown";
654     argv[1] = "evlog_rule";
655     argv[2] = "file";
656     argv[3] = evlog_rule_path;
657
658     _CommandSetEvlogRule (0, argc, argv, reply, &len, pMod);
659
660     xDbgModuleEvlogPrintEvents (pMod, TRUE, "", reply, &len);
661
662     return TRUE;
663 }