efl/src/bin/efl/efl_debug.c

266 lines
7.9 KiB
C

/* EINA - EFL data type library
* Copyright (C) 2015 Carsten Haitzler
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#include <Eina.h>
#include <Ecore.h>
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
#define EXTRACT(_buf, pval, sz) \
{ \
memcpy(pval, _buf, sz); \
_buf += sz; \
}
#define _EVLOG_INTERVAL 0.2
static int _evlog_max_times = 0;
static Ecore_Timer *_evlog_fetch_timer = NULL;
static FILE *_evlog_file = NULL;
static int _cl_stat_reg_opcode = EINA_DEBUG_OPCODE_INVALID;
static int _cid_from_pid_opcode = EINA_DEBUG_OPCODE_INVALID;
static int _prof_on_opcode = EINA_DEBUG_OPCODE_INVALID;
static int _prof_off_opcode = EINA_DEBUG_OPCODE_INVALID;
static int _cpufreq_on_opcode = EINA_DEBUG_OPCODE_INVALID;
static int _cpufreq_off_opcode = EINA_DEBUG_OPCODE_INVALID;
static int _evlog_get_opcode = EINA_DEBUG_OPCODE_INVALID;
static Eina_Debug_Session *_session = NULL;
static int _cid = 0;
static int my_argc = 0;
static char **my_argv = NULL;
static Eina_Bool
_evlog_get_cb(Eina_Debug_Session *session EINA_UNUSED, int src EINA_UNUSED, void *buffer, int size)
{
static int received_times = 0;
unsigned char *d = buffer;
unsigned int *overflow = (unsigned int *)(d + 0);
unsigned char *p = d + 4;
unsigned int blocksize = size - 4;
if(++received_times <= _evlog_max_times)
{
if ((_evlog_file) && (blocksize > 0))
{
unsigned int header[3];
header[0] = 0xffee211;
header[1] = blocksize;
header[2] = *overflow;
if (fwrite(header, 1, 12, _evlog_file) < 12 ||
fwrite(p, 1, blocksize, _evlog_file) < blocksize)
printf("Error writing bytes to evlog file\n");
}
}
if(received_times == _evlog_max_times)
{
printf("Received last evlog response\n");
if (_evlog_file) fclose(_evlog_file);
_evlog_file = NULL;
ecore_main_loop_quit();
}
return EINA_TRUE;
}
static Eina_Bool
_cb_evlog(void *data EINA_UNUSED)
{
static int sent_times = 0;
Eina_Bool ret = ECORE_CALLBACK_RENEW;
if(++sent_times <= _evlog_max_times)
eina_debug_session_send(_session, _cid, _evlog_get_opcode, NULL, 0);
if(sent_times == _evlog_max_times)
{
eina_debug_session_send(_session, _cid, _cpufreq_off_opcode, NULL, 0);
ecore_timer_del(_evlog_fetch_timer);
_evlog_fetch_timer = NULL;
ret = ECORE_CALLBACK_CANCEL;
}
return ret;
}
static Eina_Bool
_cid_get_cb(Eina_Debug_Session *session EINA_UNUSED, int cid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
{
_cid = *(int *)buffer;
const char *op_str = my_argv[1];
Eina_Bool quit = EINA_TRUE;
if ((!strcmp(op_str, "pon")) && (3 <= (my_argc - 1)))
{
int freq = atoi(my_argv[3]);
eina_debug_session_send(_session, _cid, _prof_on_opcode, &freq, sizeof(int));
}
else if (!strcmp(op_str, "poff"))
eina_debug_session_send(_session, _cid, _prof_off_opcode, NULL, 0);
else if (!strcmp(op_str, "evlogon") && (3 <= (my_argc - 1)))
{
double max_time;
sscanf(my_argv[3], "%lf", &max_time);
_evlog_max_times = max_time > 0 ? (max_time/_EVLOG_INTERVAL+1) : 1;
eina_debug_session_send(_session, 0, _cl_stat_reg_opcode, NULL, 0);
printf("Evlog request will be sent %d times\n", _evlog_max_times);
eina_debug_session_send(_session, _cid, _cpufreq_on_opcode, NULL, 0);
/* Creating the evlog file and setting the timer */
char path[4096];
int pid = atoi(my_argv[2]);
snprintf(path, sizeof(path), "%s/efl_debug_evlog-%ld.log",
getenv("HOME"), (long)pid);
_evlog_file = fopen(path, "wb");
_evlog_fetch_timer = ecore_timer_add(_EVLOG_INTERVAL, _cb_evlog, NULL);
quit = EINA_FALSE;
}
else if (!strcmp(op_str, "evlogoff"))
eina_debug_session_send(_session, _cid, _cpufreq_off_opcode, NULL, 0);
if(quit)
ecore_main_loop_quit();
return EINA_TRUE;
}
static Eina_Bool
_clients_info_added_cb(Eina_Debug_Session *session EINA_UNUSED, int src EINA_UNUSED, void *buffer, int size)
{
char *buf = buffer;
while(size)
{
int cid, pid, len;
EXTRACT(buf, &cid, sizeof(int));
EXTRACT(buf, &pid, sizeof(int));
/* We dont need client notifications on evlog */
if(!_evlog_fetch_timer)
printf("Added: CID: %d - PID: %d - Name: %s\n", cid, pid, buf);
len = strlen(buf) + 1;
buf += len;
size -= (2 * sizeof(int) + len);
}
return EINA_TRUE;
}
static Eina_Bool
_clients_info_deleted_cb(Eina_Debug_Session *session EINA_UNUSED, int src EINA_UNUSED, void *buffer, int size)
{
char *buf = buffer;
while(size)
{
int cid;
EXTRACT(buf, &cid, sizeof(int));
size -= sizeof(int);
/* If client deleted dont send anymore evlog requests */
if(_evlog_fetch_timer)
{
if(_cid == cid)
{
printf("Evlog debugged App closed (CID: %d), stopping evlog\n", cid);
ecore_timer_del(_evlog_fetch_timer);
_evlog_fetch_timer = NULL;
fclose(_evlog_file);
_evlog_file = NULL;
ecore_main_loop_quit();
}
}
else
printf("Deleted: CID: %d\n", cid);
}
return EINA_TRUE;
}
static void
_ecore_thread_dispatcher(void *data)
{
eina_debug_dispatch(_session, data);
}
Eina_Bool
_disp_cb(Eina_Debug_Session *session EINA_UNUSED, void *buffer)
{
ecore_main_loop_thread_safe_call_async(_ecore_thread_dispatcher, buffer);
return EINA_TRUE;
}
static void
_args_handle(void *data EINA_UNUSED, Eina_Bool flag)
{
if (!flag) exit(0);
eina_debug_session_dispatch_override(_session, _disp_cb);;
const char *op_str = my_argv[1];
if (op_str && !strcmp(op_str, "list"))
{
eina_debug_session_send(_session, 0, _cl_stat_reg_opcode, NULL, 0);
}
else if (2 <= my_argc - 1)
{
int pid = atoi(my_argv[2]);
eina_debug_session_send(_session, 0, _cid_from_pid_opcode, &pid, sizeof(int));
}
}
static const Eina_Debug_Opcode ops[] =
{
{"Daemon/Client/register_observer", &_cl_stat_reg_opcode, NULL},
{"Daemon/Client/added", NULL, &_clients_info_added_cb},
{"Daemon/Client/deleted", NULL, &_clients_info_deleted_cb},
{"Daemon/Client/cid_from_pid", &_cid_from_pid_opcode, &_cid_get_cb},
{"Profiler/on", &_prof_on_opcode, NULL},
{"Profiler/off", &_prof_off_opcode, NULL},
{"CPU/Freq/on", &_cpufreq_on_opcode, NULL},
{"CPU/Freq/off", &_cpufreq_off_opcode, NULL},
{"EvLog/get", &_evlog_get_opcode, _evlog_get_cb},
{NULL, NULL, NULL}
};
int
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
{
eina_init();
ecore_init();
my_argc = argc;
my_argv = argv;
_session = eina_debug_local_connect(EINA_TRUE);
if (!_session)
{
fprintf(stderr, "ERROR: Cannot connect to debug daemon.\n");
return -1;
}
eina_debug_opcodes_register(_session, ops, _args_handle, NULL);
ecore_main_loop_begin();
ecore_shutdown();
eina_shutdown();
return 0;
}