Merge remote-tracking branch 'origin/t_tracer_w32' into develop_integration_2018_w33
This commit is contained in:
@@ -1880,9 +1880,13 @@ endif (${T_TRACER})
|
||||
#This rule and the following deal with it.
|
||||
add_custom_command (
|
||||
OUTPUT ${OPENAIR_DIR}/common/utils/T/T_IDs.h
|
||||
COMMAND make
|
||||
COMMAND $(MAKE) clean
|
||||
COMMAND $(MAKE)
|
||||
COMMAND $(MAKE) check_vcd
|
||||
WORKING_DIRECTORY ${OPENAIR_DIR}/common/utils/T
|
||||
DEPENDS ${OPENAIR_DIR}/common/utils/T/T_messages.txt
|
||||
${OPENAIR_DIR}/common/utils/LOG/vcd_signal_dumper.c
|
||||
${OPENAIR_DIR}/common/utils/LOG/vcd_signal_dumper.h
|
||||
)
|
||||
|
||||
#This rule is specifically needed to generate T files
|
||||
@@ -2187,7 +2191,8 @@ if (${T_TRACER})
|
||||
oai_eth_transpro
|
||||
FLPT_MSG ASYNC_IF FLEXRAN_AGENT HASHTABLE MSC UTIL OMG_SUMO SECU_OSA
|
||||
SECU_CN SCHED_LIB PHY L2 default_sched remote_sched RAL CN_UTILS
|
||||
GTPV1U SCTP_CLIENT UDP LIB_NAS_UE LFDS LFDS7 SIMU OPENAIR0_LIB PHY_MEX)
|
||||
GTPV1U SCTP_CLIENT UDP LIB_NAS_UE LFDS LFDS7 SIMU OPENAIR0_LIB PHY_MEX
|
||||
coding)
|
||||
if (TARGET ${i})
|
||||
add_dependencies(${i} generate_T)
|
||||
endif()
|
||||
@@ -2230,7 +2235,7 @@ function(make_driver name dir)
|
||||
endforeach()
|
||||
CONFIGURE_FILE(${OPENAIR_CMAKE}/tools/Kbuild.cmake ${OPENAIR_BIN_DIR}/${name}/Kbuild)
|
||||
add_custom_command(OUTPUT ${name}.ko
|
||||
COMMAND make -C ${module_build_path} M=${OPENAIR_BIN_DIR}/${name}
|
||||
COMMAND $(MAKE) -C ${module_build_path} M=${OPENAIR_BIN_DIR}/${name}
|
||||
WORKING_DIRECTORY ${OPENAIR_BIN_DIR}/${name}
|
||||
COMMENT "building ${module}.ko"
|
||||
VERBATIM
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
/* WARNING: if you edit the enums below, update also string definitions in vcd_signal_dumper.c */
|
||||
typedef enum {
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB = 0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB=0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_ENB,
|
||||
@@ -91,12 +91,12 @@ typedef enum {
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_SEQ_NUM,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_ITTI_SEND_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_ITTI_POLL_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_ITTI_RECV_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_ITTI_ALLOC_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_MP_ALLOC,
|
||||
VCD_SIGNAL_DUMPER_VARIABLE_MP_FREE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_SEND_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_POLL_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_RECV_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_ALLOC_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_MP_ALLOC,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_MP_FREE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_TX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,
|
||||
|
||||
@@ -15,4 +15,5 @@ tracer/to_vcd
|
||||
tracer/extract_input_subframe
|
||||
tracer/extract_output_subframe
|
||||
tracer/extract
|
||||
tracer/multi
|
||||
tracee/tracee
|
||||
|
||||
+11
-2
@@ -18,6 +18,15 @@ T_messages.txt.h: T_messages.txt
|
||||
T_IDs.h: $(GENIDS) T_messages.txt
|
||||
./$(GENIDS) T_messages.txt T_IDs.h
|
||||
|
||||
check_vcd:
|
||||
gcc -Wall -I. -I.. -I../itti -Itracer -o _check_vcd check_vcd.c tracer/database.c tracer/utils.c -lm -pthread
|
||||
./_check_vcd || (rm -f ./_check_vcd ./T_IDs.h ./T_messages.txt.h && false)
|
||||
rm -f ./_check_vcd
|
||||
|
||||
.PHONY: check_vcd
|
||||
|
||||
clean:
|
||||
rm -f *.o $(GENIDS) core T_IDs.h T_messages.txt.h
|
||||
cd tracer && make clean
|
||||
rm -f *.o $(GENIDS) core T_IDs.h T_messages.txt.h _check_vcd
|
||||
|
||||
cleanall: clean
|
||||
cd tracer && $(MAKE) clean
|
||||
|
||||
+37
-26
@@ -31,6 +31,12 @@ volatile int _T_freelist_head;
|
||||
volatile int *T_freelist_head = &_T_freelist_head;
|
||||
T_cache_t *T_cache;
|
||||
|
||||
#if BASIC_SIMULATOR
|
||||
/* global variables used by T_GET_SLOT, see in T.h */
|
||||
volatile uint64_t T_next_id;
|
||||
volatile uint64_t T_active_id;
|
||||
#endif
|
||||
|
||||
static void get_message(int s)
|
||||
{
|
||||
char t;
|
||||
@@ -91,7 +97,7 @@ static void new_thread(void *(*f)(void *), void *data)
|
||||
|
||||
/* defined in local_tracer.c */
|
||||
void T_local_tracer_main(int remote_port, int wait_for_tracer,
|
||||
int local_socket, char *shm_file);
|
||||
int local_socket, void *shm_array);
|
||||
|
||||
/* We monitor the tracee and the local tracer processes.
|
||||
* When one dies we forcefully kill the other.
|
||||
@@ -114,22 +120,31 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
|
||||
{
|
||||
int socket_pair[2];
|
||||
int s;
|
||||
int T_shm_fd;
|
||||
int child1, child2;
|
||||
char shm_file[128];
|
||||
|
||||
sprintf(shm_file, "/%s%d", T_SHM_FILENAME, getpid());
|
||||
int i;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
|
||||
{ perror("socketpair"); abort(); }
|
||||
|
||||
/* setup shared memory */
|
||||
T_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (T_cache == MAP_FAILED)
|
||||
{ perror("mmap"); abort(); }
|
||||
|
||||
/* let's garbage the memory to catch some potential problems
|
||||
* (think multiprocessor sync issues, barriers, etc.)
|
||||
*/
|
||||
memset(T_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t));
|
||||
for (i = 0; i < T_CACHE_SIZE; i++) T_cache[i].busy = 0;
|
||||
|
||||
/* child1 runs the local tracer and child2 (or main) runs the tracee */
|
||||
|
||||
child1 = fork(); if (child1 == -1) abort();
|
||||
if (child1 == 0) {
|
||||
close(socket_pair[1]);
|
||||
T_local_tracer_main(remote_port, wait_for_tracer, socket_pair[0],
|
||||
shm_file);
|
||||
T_cache);
|
||||
exit(0);
|
||||
}
|
||||
close(socket_pair[0]);
|
||||
@@ -138,6 +153,7 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
|
||||
child2 = fork(); if (child2 == -1) abort();
|
||||
if (child2 != 0) {
|
||||
close(socket_pair[1]);
|
||||
munmap(T_cache, T_CACHE_SIZE * sizeof(T_cache_t));
|
||||
monitor_and_kill(child1, child2);
|
||||
}
|
||||
}
|
||||
@@ -148,34 +164,29 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
|
||||
|
||||
T_socket = s;
|
||||
|
||||
/* setup shared memory */
|
||||
T_shm_fd = shm_open(shm_file, O_RDWR /*| O_SYNC*/, 0666);
|
||||
shm_unlink(shm_file);
|
||||
if (T_shm_fd == -1) { perror(shm_file); abort(); }
|
||||
T_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, T_shm_fd, 0);
|
||||
if (T_cache == MAP_FAILED)
|
||||
{ perror(shm_file); abort(); }
|
||||
close(T_shm_fd);
|
||||
|
||||
new_thread(T_receive_thread, NULL);
|
||||
}
|
||||
|
||||
void T_Config_Init(void)
|
||||
{
|
||||
int T_port; /* by default we wait for the tracer */
|
||||
int T_nowait; /* default port to listen to to wait for the tracer */
|
||||
int T_dont_fork; /* default is to fork, see 'T_init' to understand */
|
||||
int T_port; /* by default we wait for the tracer */
|
||||
int T_nowait; /* default port to listen to to wait for the tracer */
|
||||
int T_dont_fork; /* default is to fork, see 'T_init' to understand */
|
||||
|
||||
paramdef_t ttraceparams[] = CMDLINE_TTRACEPARAMS_DESC ;
|
||||
paramdef_t ttraceparams[] = CMDLINE_TTRACEPARAMS_DESC;
|
||||
|
||||
/* for a cleaner config file, TTracer params should be defined in a specific section... */
|
||||
config_get( ttraceparams,sizeof(ttraceparams)/sizeof(paramdef_t),TTRACER_CONFIG_PREFIX);
|
||||
/* for a cleaner config file, TTracer params should be defined in a
|
||||
* specific section...
|
||||
*/
|
||||
config_get(ttraceparams,
|
||||
sizeof(ttraceparams) / sizeof(paramdef_t),
|
||||
TTRACER_CONFIG_PREFIX);
|
||||
|
||||
/* compatibility: look for TTracer command line options in root section */
|
||||
config_process_cmdline( ttraceparams,sizeof(ttraceparams)/sizeof(paramdef_t),NULL);
|
||||
/* compatibility: look for TTracer command line options in root section */
|
||||
config_process_cmdline(ttraceparams,
|
||||
sizeof(ttraceparams) / sizeof(paramdef_t),
|
||||
NULL);
|
||||
|
||||
if (T_stdout == 0) {
|
||||
if (T_stdout == 0)
|
||||
T_init(T_port, 1-T_nowait, T_dont_fork);
|
||||
}
|
||||
}
|
||||
|
||||
+36
-11
@@ -112,13 +112,37 @@ extern volatile int *T_freelist_head;
|
||||
extern T_cache_t *T_cache;
|
||||
extern int *T_active;
|
||||
/* When running the basic simulator, we may fill the T cache too fast.
|
||||
* Let's not crash if it's full, just wait.
|
||||
* Let's serialize write accesses to the T cache. For that, we use a
|
||||
* 'ticket' mechanism. To acquire a T slot the caller needs to own the
|
||||
* current active ticket. We also wait for the slot to be free if
|
||||
* it is already in use.
|
||||
*/
|
||||
#if BASIC_SIMULATOR
|
||||
# define T_BASIC_SIMULATOR_WAIT \
|
||||
while (T_cache[T_LOCAL_slot].busy) usleep(100)
|
||||
# define T_GET_SLOT \
|
||||
do { \
|
||||
extern volatile uint64_t T_next_id; \
|
||||
extern volatile uint64_t T_active_id; \
|
||||
uint64_t id; \
|
||||
/* get a ticket */ \
|
||||
id = __sync_fetch_and_add(&T_next_id, 1); \
|
||||
/* wait for our turn */ \
|
||||
while (id != __sync_fetch_and_add(&T_active_id, 0)) /* busy wait */; \
|
||||
/* this is our turn, try to acquire the slot until it's free */ \
|
||||
do { \
|
||||
T_LOCAL_busy = __sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x01); \
|
||||
if (T_LOCAL_busy & 0x01) usleep(100); \
|
||||
} while (T_LOCAL_busy & 0x01); \
|
||||
/* check that there are still some tickets */ \
|
||||
if (__sync_fetch_and_add(&T_active_id, 0) == 0xffffffffffffffff) { \
|
||||
printf("T: reached the end of times, bye...\n"); \
|
||||
abort(); \
|
||||
} \
|
||||
/* free our ticket, which signals the next waiter that it's its turn */ \
|
||||
(void)__sync_fetch_and_add(&T_active_id, 1); \
|
||||
} while (0)
|
||||
#else
|
||||
# define T_BASIC_SIMULATOR_WAIT /* */
|
||||
# define T_GET_SLOT \
|
||||
T_LOCAL_busy = __sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x01);
|
||||
#endif
|
||||
|
||||
/* used at header of Tn, allocates buffer */
|
||||
@@ -126,11 +150,12 @@ extern int *T_active;
|
||||
char *T_LOCAL_buf; \
|
||||
int T_LOCAL_size = 0; \
|
||||
int T_LOCAL_slot; \
|
||||
int T_LOCAL_busy; \
|
||||
T_LOCAL_slot = __sync_fetch_and_add(T_freelist_head, 1) \
|
||||
& (T_CACHE_SIZE - 1); \
|
||||
(void)__sync_fetch_and_and(T_freelist_head, T_CACHE_SIZE - 1); \
|
||||
T_BASIC_SIMULATOR_WAIT; \
|
||||
if (T_cache[T_LOCAL_slot].busy) { \
|
||||
T_GET_SLOT; \
|
||||
if (T_LOCAL_busy & 0x01) { \
|
||||
printf("%s:%d:%s: T cache is full - consider increasing its size\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__); \
|
||||
abort(); \
|
||||
@@ -142,7 +167,7 @@ extern int *T_active;
|
||||
#define T_COMMIT() \
|
||||
T_cache[T_LOCAL_slot].length = T_LOCAL_size; \
|
||||
__sync_synchronize(); \
|
||||
T_cache[T_LOCAL_slot].busy = 1; \
|
||||
(void)__sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x02);
|
||||
|
||||
#define T_CHECK_SIZE(len, argnum) \
|
||||
if (T_LOCAL_size + (len) > T_BUFFER_MAX) { \
|
||||
@@ -578,10 +603,10 @@ extern int *T_active;
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define CMDLINE_TTRACEPARAMS_DESC { \
|
||||
{"T_port", CONFIG_HLP_TPORT, 0, iptr:&T_port, defintval:2021, TYPE_INT, 0}, \
|
||||
{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, iptr:&T_nowait, defintval:0, TYPE_INT, 0}, \
|
||||
{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, iptr:&T_dont_fork, defintval:0, TYPE_INT, 0}, \
|
||||
{"T_stdout", CONFIG_HLP_STDOUT, PARAMFLAG_BOOL, iptr:&T_stdout, defintval:1, TYPE_INT, 0}, \
|
||||
{"T_port", CONFIG_HLP_TPORT, 0, iptr:&T_port, defintval:2021, TYPE_INT, 0}, \
|
||||
{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, iptr:&T_nowait, defintval:0, TYPE_INT, 0}, \
|
||||
{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, iptr:&T_dont_fork, defintval:0, TYPE_INT, 0}, \
|
||||
{"T_stdout", CONFIG_HLP_STDOUT, PARAMFLAG_BOOL, iptr:&T_stdout, defintval:1, TYPE_INT, 0}, \
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,13 +31,15 @@
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/* 'busy' is a bit field
|
||||
* bit 0: 1 means that slot is acquired by writer
|
||||
* bit 1: 1 means that slot is ready for consumption
|
||||
*/
|
||||
volatile int busy;
|
||||
char buffer[T_BUFFER_MAX];
|
||||
int length;
|
||||
} T_cache_t;
|
||||
|
||||
#define T_SHM_FILENAME "/T_shm_segment"
|
||||
|
||||
/* number of VCD functions (to be kept up to date! see in T_messages.txt) */
|
||||
#define VCD_NUM_FUNCTIONS 190
|
||||
|
||||
|
||||
+324
-24
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* To disable the checks done by this program, see below at the beginning
|
||||
* of the function 'main'.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "database.h"
|
||||
|
||||
#define T_TRACER 1
|
||||
#include "T.h"
|
||||
|
||||
/* VCD specific defines and includes
|
||||
* If the codebase changes, it may need to be updated
|
||||
*/
|
||||
#define ENB_MODE
|
||||
#define ENABLE_USE_CPU_EXECUTION_TIME
|
||||
#include "../LOG/vcd_signal_dumper.c"
|
||||
|
||||
void err(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void err(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
printf("\x1b[31m");
|
||||
printf("error: ");
|
||||
vprintf(fmt, ap);
|
||||
printf("\n"
|
||||
"\x1b[33m\n"
|
||||
"You probably added a VCD trace (variable or function) but you did not\n"
|
||||
"update T_messages.txt and/or T_defs.h in common/utils/T/\n"
|
||||
"\n"
|
||||
"Be sure to add the new trace to T_messages.txt, at the right place in the\n"
|
||||
"file. Do not forget to define VCD_NAME with an identical value as found\n"
|
||||
"in the array eurecomVariablesNames or eurecomFunctionsNames.\n"
|
||||
"\n"
|
||||
"Be sure to update VCD_NUM_FUNCTIONS, VCD_NUM_VARIABLES, VCD_FIRST_FUNCTION\n"
|
||||
"and VCD_FIRST_VARIABLE in T_defs.h\n"
|
||||
"\n"
|
||||
"The same procedure has to be followed when you delete a VCD trace.\n"
|
||||
"Delete it in T_messages.txt as well and update T_defs.h\n"
|
||||
"\n"
|
||||
"You can disable those VCD checks at development time.\n"
|
||||
"To disable the VCD checks see the file common/utils/T/check_vcd.c\n"
|
||||
"Do not push any modification that disables the VCD checks to the\n"
|
||||
"main repository.\n");
|
||||
|
||||
printf("\x1b[m\n");
|
||||
|
||||
va_end(ap);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* to disable the checks done by this program, uncomment the following
|
||||
* line, ie. remove the leading '//'
|
||||
*/
|
||||
//return 0;
|
||||
|
||||
void *database = parse_database("T_messages.txt");
|
||||
int number_of_events;
|
||||
int first_var = -1;
|
||||
int last_var;
|
||||
int first_fun = -1;
|
||||
int last_fun;
|
||||
char *prefix;
|
||||
int prefix_len;
|
||||
char *name;
|
||||
char *vcd_name;
|
||||
int i;
|
||||
FILE *in;
|
||||
char *l = NULL;
|
||||
size_t lsize;
|
||||
|
||||
if (database == NULL) err("something wrong with T_messages.txt");
|
||||
|
||||
/* check the value of VCD_NUM_FUNCTIONS */
|
||||
if (VCD_NUM_FUNCTIONS != sizeof(eurecomFunctionsNames) / sizeof(char *))
|
||||
err("VCD_NUM_FUNCTIONS (%d) must be equal to %zd",
|
||||
VCD_NUM_FUNCTIONS,
|
||||
sizeof(eurecomFunctionsNames) / sizeof(char *));
|
||||
|
||||
/* check the value of VCD_NUM_VARIABLES */
|
||||
if (VCD_NUM_VARIABLES != sizeof(eurecomVariablesNames) / sizeof(char *))
|
||||
err("VCD_NUM_VARIABLES (%d) must be equal to %zd",
|
||||
VCD_NUM_VARIABLES,
|
||||
sizeof(eurecomVariablesNames) / sizeof(char *));
|
||||
|
||||
number_of_events = number_of_ids(database);
|
||||
if (number_of_events == 0) err("no event defined in T_messages.txt");
|
||||
|
||||
/* T_messages.txt ends with VCD VARIABLES followed by VCD FUNCTIONS
|
||||
* followed by nothing.
|
||||
* Let's check.
|
||||
*/
|
||||
|
||||
/* check VCD VARIABLES traces in T_messages.txt */
|
||||
prefix = "VCD_VARIABLE_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) continue;
|
||||
first_var = i;
|
||||
break;
|
||||
}
|
||||
if (first_var == -1)
|
||||
err("no VCD_VARIABLE_ found in T_messages.txt");
|
||||
for (; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) break;
|
||||
}
|
||||
last_var = i-1;
|
||||
|
||||
/* check VCD FUNCTIONS traces in T_messages.txt */
|
||||
if (i == number_of_events)
|
||||
err("no VCD_FUNCTION_ found in T_messages.txt");
|
||||
|
||||
prefix = "VCD_FUNCTION_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
first_fun = i;
|
||||
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len))
|
||||
err("last VCD_VARIABLE_ not followed by a VCD_FUNCTION_ in T_messages.txt");
|
||||
|
||||
for (; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) break;
|
||||
}
|
||||
|
||||
if (i != number_of_events)
|
||||
err("T_messages.txt does not end with a VCD_FUNCTION_ trace");
|
||||
|
||||
last_fun = i-1;
|
||||
|
||||
if (first_var != (unsigned)VCD_FIRST_VARIABLE)
|
||||
err("VCD_FIRST_VARIABLE is not correct in T_defs.h");
|
||||
if (first_fun != (unsigned)VCD_FIRST_FUNCTION)
|
||||
err("VCD_FIRST_FUNCTION is not correct in T_defs.h");
|
||||
if (last_var-first_var+1 != VCD_NUM_VARIABLES)
|
||||
err("VCD_NUM_VARIABLES is not correct in T_defs.h");
|
||||
if (last_fun-first_fun+1 != VCD_NUM_FUNCTIONS)
|
||||
err("VCD_NUM_FUNCTIONS is not correct in T_defs.h");
|
||||
|
||||
/* check that VCD_NAME is identical to
|
||||
* eurecomVariablesNames[x]/eurecomFunctionsNames[x]
|
||||
*/
|
||||
prefix = "VCD_VARIABLE_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) continue;
|
||||
vcd_name = event_vcd_name_from_id(database, i);
|
||||
if (vcd_name == NULL)
|
||||
err("%s has no VCD_NAME in T_messages.txt", name);
|
||||
if (strcmp(vcd_name, eurecomVariablesNames[i - first_var]))
|
||||
err("%s has a wrong VCD_NAME in T_messages.txt", name);
|
||||
}
|
||||
|
||||
prefix = "VCD_FUNCTION_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) continue;
|
||||
vcd_name = event_vcd_name_from_id(database, i);
|
||||
if (vcd_name == NULL)
|
||||
err("%s has no VCD_NAME in T_messages.txt", name);
|
||||
if (strcmp(vcd_name, eurecomFunctionsNames[i - first_fun]))
|
||||
err("%s has a wrong VCD_NAME in T_messages.txt", name);
|
||||
}
|
||||
|
||||
/* check IDs - these checks are difficult because we parse
|
||||
* common/utils/LOG/vcd_signal_dumper.h which is expected to
|
||||
* be formatted as is:
|
||||
* - define vcd_signal_dump_variables then vcd_signal_dump_functions
|
||||
* - one VCD_XXXX per line starting with two spaces
|
||||
* followed by ',' or '=' with no space in between
|
||||
* - no #ifdef / #if is taken into account
|
||||
* - we require VCD_SIGNAL_DUMPER_VARIABLES_END and
|
||||
* VCD_SIGNAL_DUMPER_FUNCTIONS_END at the end of each array,
|
||||
* each on a line of its own with two spaces before and nothing after.
|
||||
*
|
||||
* If these checks fail, consider formatting
|
||||
* common/utils/LOG/vcd_signal_dumper.h as expected here, if
|
||||
* it makes sense of course. Otherwise, change the code below.
|
||||
*
|
||||
* In common/utils/LOG/vcd_signal_dumper.h a valid name is
|
||||
* either VCD_SIGNAL_DUMPER_VARIABLES_ABC or
|
||||
* VCD_SIGNAL_DUMPER_FUNCTIONS_XYZ
|
||||
* and in T_messages.txt the corresponding name has to be
|
||||
* VCD_VARIABLE_ABC or VCD_FUNCTION_XYZ
|
||||
*/
|
||||
i = first_var;
|
||||
in = fopen("../LOG/vcd_signal_dumper.h", "r");
|
||||
if (in == NULL) err("could not open ../LOG/vcd_signal_dumper.h");
|
||||
while (1) {
|
||||
char *x = " VCD_SIGNAL_DUMPER_VARIABLES_";
|
||||
ssize_t r;
|
||||
free(l);
|
||||
l = NULL;
|
||||
lsize = 0;
|
||||
r = getline(&l, &lsize, in);
|
||||
if (r == -1) break;
|
||||
if (!strcmp(l, " VCD_SIGNAL_DUMPER_VARIABLES_END\n")) break;
|
||||
/* remove ',' or '=' if found */
|
||||
{ char *s=l; while (*s) { if (*s==','||*s=='=') { *s=0; break; } s++; } }
|
||||
if (strncmp(l, x, strlen(x))) continue;
|
||||
if (!(i >= first_var && i <= last_var))
|
||||
err("T_messages.txt is not correct with respect to VCD VARIABLES");
|
||||
name = event_name_from_id(database, i);
|
||||
if (strcmp(l+strlen(x), name+strlen("VCD_VARIABLE_")))
|
||||
err("%s is not correct in T_messages.txt", name);
|
||||
i++;
|
||||
}
|
||||
if (i != last_var + 1) err("VCD VARIABLES wrong in T_messages.txt");
|
||||
while (1) {
|
||||
char *x = " VCD_SIGNAL_DUMPER_FUNCTIONS_";
|
||||
ssize_t r;
|
||||
free(l);
|
||||
l = NULL;
|
||||
lsize = 0;
|
||||
r = getline(&l, &lsize, in);
|
||||
if (r == -1) break;
|
||||
if (!strcmp(l, " VCD_SIGNAL_DUMPER_FUNCTIONS_END\n")) break;
|
||||
/* remove ',' or '=' if found */
|
||||
{ char *s=l; while (*s) { if (*s==','||*s=='=') { *s=0; break; } s++; } }
|
||||
if (strncmp(l, x, strlen(x))) continue;
|
||||
if (!(i >= first_fun && i <= last_fun))
|
||||
err("T_messages.txt is not correct with respect to VCD FUNCTIONS");
|
||||
name = event_name_from_id(database, i);
|
||||
if (strcmp(l+strlen(x), name+strlen("VCD_FUNCTION_")))
|
||||
err("%s is not correct in T_messages.txt", name);
|
||||
i++;
|
||||
}
|
||||
fclose(in);
|
||||
if (i != last_fun + 1) err("VCD FUNCTIONS wrong in T_messages.txt");
|
||||
|
||||
return 0;
|
||||
}
|
||||
+11
-10
@@ -14,21 +14,21 @@ int cmp(const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
/* return 1 if s was not already known, 0 if it was */
|
||||
int new_unique_id(char *s)
|
||||
int new_unique_id(char *s, char *input_file)
|
||||
{
|
||||
if (unique_ids_size)
|
||||
if (bsearch(&s, unique_ids, unique_ids_size, sizeof(char *), cmp) != NULL) {
|
||||
printf("FATAL: ID %s is not unique\n", s);
|
||||
printf("error: ID %s is not unique in %s\n", s, input_file);
|
||||
return 0;
|
||||
}
|
||||
if (unique_ids_size == unique_ids_maxsize) {
|
||||
unique_ids_maxsize += 256;
|
||||
unique_ids = realloc(unique_ids, unique_ids_maxsize * sizeof(char *));
|
||||
if (unique_ids == NULL) { printf("out of memory\n"); abort(); }
|
||||
if (unique_ids == NULL) { printf("erorr: out of memory\n"); abort(); }
|
||||
}
|
||||
unique_ids[unique_ids_size] = strdup(s);
|
||||
if (unique_ids[unique_ids_size] == NULL)
|
||||
{ printf("out of memory\n"); abort(); }
|
||||
{ printf("erorr: out of memory\n"); abort(); }
|
||||
unique_ids_size++;
|
||||
qsort(unique_ids, unique_ids_size, sizeof(char *), cmp);
|
||||
return 1;
|
||||
@@ -43,7 +43,8 @@ void putname(int c)
|
||||
if (bufname_size == bufname_maxsize) {
|
||||
bufname_maxsize += 256;
|
||||
bufname = realloc(bufname, bufname_maxsize);
|
||||
if (bufname == NULL) { printf("memory allocation error\n"); exit(1); }
|
||||
if (bufname == NULL)
|
||||
{ printf("erorr: memory allocation error\n"); exit(1); }
|
||||
}
|
||||
bufname[bufname_size] = c;
|
||||
bufname_size++;
|
||||
@@ -58,7 +59,8 @@ void putvalue(int c)
|
||||
if (bufvalue_size == bufvalue_maxsize) {
|
||||
bufvalue_maxsize += 256;
|
||||
bufvalue = realloc(bufvalue, bufvalue_maxsize);
|
||||
if (bufvalue == NULL) { printf("memory allocation error\n"); exit(1); }
|
||||
if (bufvalue == NULL)
|
||||
{ printf("error: memory allocation error\n"); exit(1); }
|
||||
}
|
||||
bufvalue[bufvalue_size] = c;
|
||||
bufvalue_size++;
|
||||
@@ -119,7 +121,7 @@ int main(int n, char **v)
|
||||
char *in_name;
|
||||
char *out_name;
|
||||
|
||||
if (n != 3) { printf("gimme <source> <dest>\n"); exit(1); }
|
||||
if (n != 3) { printf("error: gimme <source> <dest>\n"); exit(1); }
|
||||
|
||||
n = 0;
|
||||
|
||||
@@ -134,14 +136,13 @@ int main(int n, char **v)
|
||||
while (1) {
|
||||
get_line(in, &name, &value);
|
||||
if (name == NULL) break;
|
||||
printf("name '%s' value '%s'\n", name, value);
|
||||
if (isspace(value[strlen(value)-1])) {
|
||||
printf("bad value '%s' (no space at the end please!)\n", value);
|
||||
printf("error: bad value '%s' (no space at the end please!)\n", value);
|
||||
unlink(out_name);
|
||||
exit(1);
|
||||
}
|
||||
if (!strcmp(name, "ID")) {
|
||||
if (!new_unique_id(value)) { unlink(out_name); exit(1); }
|
||||
if (!new_unique_id(value, in_name)) { unlink(out_name); exit(1); }
|
||||
fprintf(out, "#define T_%s T_ID(%d)\n", value, n);
|
||||
n++;
|
||||
}
|
||||
|
||||
@@ -337,54 +337,34 @@ static void forward(void *_forwarder, char *buf, int size)
|
||||
|
||||
static void wait_message(void)
|
||||
{
|
||||
while (T_local_cache[T_busylist_head].busy == 0) usleep(1000);
|
||||
}
|
||||
|
||||
static void init_shm(char *shm_file)
|
||||
{
|
||||
int i;
|
||||
int s = shm_open(shm_file, O_RDWR | O_CREAT /*| O_SYNC*/, 0666);
|
||||
if (s == -1) { perror(shm_file); abort(); }
|
||||
if (ftruncate(s, T_CACHE_SIZE * sizeof(T_cache_t)))
|
||||
{ perror(shm_file); abort(); }
|
||||
T_local_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, s, 0);
|
||||
if (T_local_cache == MAP_FAILED)
|
||||
{ perror(shm_file); abort(); }
|
||||
close(s);
|
||||
|
||||
/* let's garbage the memory to catch some potential problems
|
||||
* (think multiprocessor sync issues, barriers, etc.)
|
||||
*/
|
||||
memset(T_local_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t));
|
||||
for (i = 0; i < T_CACHE_SIZE; i++) T_local_cache[i].busy = 0;
|
||||
while ((T_local_cache[T_busylist_head].busy & 0x02) == 0) usleep(1000);
|
||||
}
|
||||
|
||||
void T_local_tracer_main(int remote_port, int wait_for_tracer,
|
||||
int local_socket, char *shm_file)
|
||||
int local_socket, void *shm_array)
|
||||
{
|
||||
int s;
|
||||
int port = remote_port;
|
||||
int dont_wait = wait_for_tracer ? 0 : 1;
|
||||
void *f;
|
||||
printf("local tracer starting\n");
|
||||
|
||||
/* write on a socket fails if the other end is closed and we get SIGPIPE */
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR){
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
printf("local tracer received SIGPIPE\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
T_local_cache = shm_array;
|
||||
|
||||
init_shm(shm_file);
|
||||
s = local_socket;
|
||||
printf("local tracer starting step 2\n");
|
||||
|
||||
if (dont_wait) {
|
||||
char t = 2;
|
||||
printf("local tracer in no wait mode \n");
|
||||
if (write(s, &t, 1) != 1) abort();
|
||||
}
|
||||
printf("local tracer starting step 3\n");
|
||||
|
||||
f = forwarder(port, s);
|
||||
printf("local tracer main loop.... \n");
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
wait_message();
|
||||
|
||||
@@ -7,7 +7,7 @@ LIBS=-lm
|
||||
XLIBS=-lX11 -lpng -lXft
|
||||
|
||||
all: record replay extract_config textlog enb ue vcd macpdu2wireshark \
|
||||
extract_input_subframe extract_output_subframe to_vcd extract
|
||||
extract_input_subframe extract_output_subframe to_vcd extract multi
|
||||
|
||||
record: utils.o record.o database.o config.o
|
||||
$(CC) $(CFLAGS) -o record $^ $(LIBS)
|
||||
@@ -57,19 +57,22 @@ macpdu2wireshark: macpdu2wireshark.o database.o utils.o handler.o event.o \
|
||||
config.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
multi: multi.o utils.o database.o config.o
|
||||
$(CC) $(CFLAGS) -o multi $^ $(LIBS)
|
||||
|
||||
.PHONY: all gui/gui.a view/view.a logger/logger.a filter/filter.a
|
||||
|
||||
gui/gui.a:
|
||||
cd gui && make
|
||||
cd gui && $(MAKE)
|
||||
|
||||
view/view.a:
|
||||
cd view && make
|
||||
cd view && $(MAKE)
|
||||
|
||||
logger/logger.a:
|
||||
cd logger && make
|
||||
cd logger && $(MAKE)
|
||||
|
||||
filter/filter.a:
|
||||
cd filter && make
|
||||
cd filter && $(MAKE)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
@@ -77,9 +80,9 @@ filter/filter.a:
|
||||
clean:
|
||||
rm -f *.o core tracer_remote textlog enb ue vcd record replay
|
||||
rm -f extract_config macpdu2wireshark extract_input_subframe
|
||||
rm -f extract_output_subframe to_vcd extract
|
||||
cd gui && make clean
|
||||
cd view && make clean
|
||||
cd logger && make clean
|
||||
cd filter && make clean
|
||||
cd hacks && make clean
|
||||
rm -f extract_output_subframe to_vcd extract multi
|
||||
cd gui && $(MAKE) clean
|
||||
cd view && $(MAKE) clean
|
||||
cd logger && $(MAKE) clean
|
||||
cd filter && $(MAKE) clean
|
||||
cd hacks && $(MAKE) clean
|
||||
|
||||
@@ -60,3 +60,9 @@ void verify_config(void)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void get_local_config(char **txt, int *len)
|
||||
{
|
||||
*txt = local;
|
||||
*len = local_size;
|
||||
}
|
||||
|
||||
@@ -5,5 +5,6 @@ void clear_remote_config(void);
|
||||
void append_received_config_chunk(char *buf, int length);
|
||||
void load_config_file(char *filename);
|
||||
void verify_config(void);
|
||||
void get_local_config(char **txt, int *len);
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
||||
|
||||
@@ -13,6 +13,7 @@ typedef struct {
|
||||
char **arg_type;
|
||||
char **arg_name;
|
||||
int asize;
|
||||
char *vcd_name;
|
||||
int id;
|
||||
} id;
|
||||
|
||||
@@ -138,6 +139,7 @@ id *add_id(database *r, char *idname, int i)
|
||||
r->i[r->isize].arg_type = NULL;
|
||||
r->i[r->isize].arg_name = NULL;
|
||||
r->i[r->isize].asize = 0;
|
||||
r->i[r->isize].vcd_name = NULL;
|
||||
r->i[r->isize].id = i;
|
||||
r->isize++;
|
||||
qsort(r->i, r->isize, sizeof(id), id_cmp);
|
||||
@@ -224,6 +226,12 @@ void add_desc(id *i, char *desc)
|
||||
i->desc = strdup(desc); if (i->desc == NULL) abort();
|
||||
}
|
||||
|
||||
void add_vcd_name(id *i, char *vcd_name)
|
||||
{
|
||||
if (i == NULL) {printf("ERROR: VCD_NAME line before ID line\n");exit(1);}
|
||||
i->vcd_name = strdup(vcd_name); if (i->vcd_name == NULL) abort();
|
||||
}
|
||||
|
||||
char *format_get_next_token(char **cur)
|
||||
{
|
||||
char *start;
|
||||
@@ -320,6 +328,7 @@ void *parse_database(char *filename)
|
||||
if (!strcmp(name, "GROUP")) add_groups(r, last_id, value);
|
||||
if (!strcmp(name, "DESC")) add_desc(last_id, value);
|
||||
if (!strcmp(name, "FORMAT")) add_format(last_id, value);
|
||||
if (!strcmp(name, "VCD_NAME")) add_vcd_name(last_id, value);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
@@ -424,6 +433,12 @@ char *event_name_from_id(void *_database, int id)
|
||||
return d->i[d->id_to_pos[id]].name;
|
||||
}
|
||||
|
||||
char *event_vcd_name_from_id(void *_database, int id)
|
||||
{
|
||||
database *d = _database;
|
||||
return d->i[d->id_to_pos[id]].vcd_name;
|
||||
}
|
||||
|
||||
int event_id_from_name(void *_database, char *name)
|
||||
{
|
||||
database *d = _database;
|
||||
|
||||
@@ -8,6 +8,7 @@ void list_ids(void *database);
|
||||
void list_groups(void *database);
|
||||
void on_off(void *d, char *item, int *a, int onoff);
|
||||
char *event_name_from_id(void *database, int id);
|
||||
char *event_vcd_name_from_id(void *_database, int id);
|
||||
int event_id_from_name(void *database, char *name);
|
||||
int number_of_ids(void *database);
|
||||
int database_get_ids(void *database, char ***ids);
|
||||
|
||||
@@ -878,6 +878,7 @@ int main(int n, char **v)
|
||||
|
||||
restart:
|
||||
clear_remote_config();
|
||||
if (enb_data.socket != -1) close(enb_data.socket);
|
||||
enb_data.socket = connect_to(ip, port);
|
||||
|
||||
/* send the first message - activate selected traces */
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include "database.h"
|
||||
#include "utils.h"
|
||||
#include "../T.h"
|
||||
#include "config.h"
|
||||
|
||||
#define DEFAULT_LOCAL_PORT 2022
|
||||
|
||||
typedef struct {
|
||||
int id; /* increases at each new tracer's connection */
|
||||
int s; /* socket */
|
||||
int *is_on; /* local vision of is_on for this tracer */
|
||||
int poll_id; /* -1: invalid, otherwise index in fds array */
|
||||
} ti_t;
|
||||
|
||||
typedef struct {
|
||||
ti_t *ti; /* data for tracers */
|
||||
int ti_size;
|
||||
int ti_maxsize;
|
||||
} multi_t;
|
||||
|
||||
void set_is_on(int *is_on, int pos, int val)
|
||||
{
|
||||
if (val) is_on[pos]++; else is_on[pos]--;
|
||||
/* TODO: remove check? */
|
||||
if (is_on[pos] < 0) { printf("%s:%d:nonono\n",__FILE__,__LINE__); abort(); }
|
||||
}
|
||||
|
||||
int send_messages_txt(int s, char *T_messages_txt, int T_messages_txt_len)
|
||||
{
|
||||
char buf[T_BUFFER_MAX];
|
||||
char *T_LOCAL_buf = buf;
|
||||
int32_t T_LOCAL_size;
|
||||
unsigned char *src;
|
||||
int src_len;
|
||||
|
||||
/* trace T_message.txt
|
||||
* Send several messages -1 with content followed by message -2.
|
||||
*/
|
||||
src = (unsigned char *)T_messages_txt;
|
||||
src_len = T_messages_txt_len;
|
||||
while (src_len) {
|
||||
int send_size = src_len;
|
||||
if (send_size > T_PAYLOAD_MAXSIZE - sizeof(int))
|
||||
send_size = T_PAYLOAD_MAXSIZE - sizeof(int);
|
||||
/* TODO: be careful, we use internal T stuff, to rewrite? */
|
||||
T_LOCAL_size = 0;
|
||||
T_HEADER(T_ID(-1));
|
||||
T_PUT_buffer(1, ((T_buffer){addr:(src), length:(send_size)}));
|
||||
if (socket_send(s, &T_LOCAL_size, 4) == -1) return -1;
|
||||
if (socket_send(s, buf, T_LOCAL_size) == -1) return -1;
|
||||
src += send_size;
|
||||
src_len -= send_size;
|
||||
}
|
||||
T_LOCAL_size = 0;
|
||||
T_HEADER(T_ID(-2));
|
||||
if (socket_send(s, &T_LOCAL_size, 4) == -1) return -1;
|
||||
return socket_send(s, buf, T_LOCAL_size);
|
||||
}
|
||||
|
||||
void new_tracer(multi_t *m, int s, int is_on_size, char *t, int t_size, int id)
|
||||
{
|
||||
if (send_messages_txt(s, t, t_size) == -1) {
|
||||
printf("error sending T_messages.txt to new tracer %d => remove tracer\n",
|
||||
id);
|
||||
return;
|
||||
}
|
||||
if (m->ti_size == m->ti_maxsize) {
|
||||
m->ti_maxsize += 64;
|
||||
m->ti = realloc(m->ti, m->ti_maxsize * sizeof(ti_t));
|
||||
if (m->ti == NULL) abort();
|
||||
}
|
||||
m->ti[m->ti_size].id = id;
|
||||
m->ti[m->ti_size].s = s;
|
||||
m->ti[m->ti_size].is_on = calloc(is_on_size, sizeof(int));
|
||||
if (m->ti[m->ti_size].is_on == NULL) abort();
|
||||
m->ti[m->ti_size].poll_id = -1;
|
||||
m->ti_size++;
|
||||
}
|
||||
|
||||
void remove_tracer(multi_t *m, int t)
|
||||
{
|
||||
free(m->ti[t].is_on);
|
||||
shutdown(m->ti[t].s, SHUT_RDWR);
|
||||
close(m->ti[t].s);
|
||||
m->ti_size--;
|
||||
memmove(&m->ti[t], &m->ti[t+1], (m->ti_size - t) * sizeof(ti_t));
|
||||
}
|
||||
|
||||
int send_is_on(int socket, int number_of_events, int *is_on)
|
||||
{
|
||||
int i;
|
||||
char mt = 1;
|
||||
if (socket_send(socket, &mt, 1) == -1 ||
|
||||
socket_send(socket, &number_of_events, sizeof(int)) == -1) return -1;
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
int v = is_on[i] ? 1 : 0;
|
||||
if (socket_send(socket, &v, sizeof(int)) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_tracee(int s, OBUF *ebuf, int *_type, int32_t *_length)
|
||||
{
|
||||
int type;
|
||||
int32_t length;
|
||||
char *v;
|
||||
int vpos = 0;
|
||||
|
||||
if (fullread(s, &length, 4) == -1) return -1;
|
||||
if (ebuf->omaxsize < length) {
|
||||
ebuf->omaxsize = (length + 65535) & ~65535;
|
||||
ebuf->obuf = realloc(ebuf->obuf, ebuf->omaxsize);
|
||||
if (ebuf->obuf == NULL) { printf("out of memory\n"); exit(1); }
|
||||
}
|
||||
v = ebuf->obuf;
|
||||
memcpy(v+vpos, &length, 4);
|
||||
vpos += 4;
|
||||
#ifdef T_SEND_TIME
|
||||
if (fullread(s,v+vpos,sizeof(struct timespec))==-1) return -1;
|
||||
vpos += sizeof(struct timespec);
|
||||
length -= sizeof(struct timespec);
|
||||
#endif
|
||||
if (fullread(s, &type, sizeof(int)) == -1) return -1;
|
||||
memcpy(v+vpos, &type, sizeof(int));
|
||||
vpos += sizeof(int);
|
||||
length -= sizeof(int);
|
||||
if (fullread(s, v+vpos, length) == -1) return -1;
|
||||
vpos += length;
|
||||
|
||||
ebuf->osize = vpos;
|
||||
|
||||
*_type = type;
|
||||
*_length = length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void forward_event(multi_t *m, int number_of_events, OBUF *ebuf, int type)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (type < 0 || type >= number_of_events)
|
||||
{ printf("error: bad type of event to forward %d\n", type); abort(); }
|
||||
|
||||
for (i = 0; i < m->ti_size; i++) {
|
||||
if (!m->ti[i].is_on[type]) continue;
|
||||
if (socket_send(m->ti[i].s, ebuf->obuf, ebuf->osize) == -1)
|
||||
printf("warning: error forwarding event to tracer %d\n", m->ti[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
int connect_to_tracee(char *ip, int port, int number_of_events, int *is_on)
|
||||
{
|
||||
int s;
|
||||
|
||||
printf("connecting to %s:%d\n", ip, port);
|
||||
|
||||
s = try_connect_to(ip, port);
|
||||
if (s == -1) return -1;
|
||||
|
||||
if (send_is_on(s, number_of_events, is_on) == -1) {
|
||||
shutdown(s, SHUT_RDWR);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf(
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -ip <host> connect to given IP address (default %s)\n"
|
||||
" -p <port> connect to given port (default %d)\n"
|
||||
" -lp <port> listen on local port (default %d)\n",
|
||||
DEFAULT_REMOTE_IP,
|
||||
DEFAULT_REMOTE_PORT,
|
||||
DEFAULT_LOCAL_PORT
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
char *ip = DEFAULT_REMOTE_IP;
|
||||
int port = DEFAULT_REMOTE_PORT;
|
||||
int local_port = DEFAULT_LOCAL_PORT;
|
||||
int *is_on;
|
||||
int number_of_events;
|
||||
int i, j;
|
||||
char *T_messages_txt;
|
||||
int T_messages_txt_len;
|
||||
int l; /* listen socket for tracers' connections */
|
||||
int s = -1; /* socket connected to tracee. -1 if not connected */
|
||||
multi_t m;
|
||||
int is_on_changed;
|
||||
int current_nfd;
|
||||
struct pollfd *fds = NULL;
|
||||
int next_id = 0;
|
||||
|
||||
memset(&m, 0, sizeof(m));
|
||||
|
||||
/* write on a socket fails if the other end is closed and we get SIGPIPE */
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
|
||||
if (!strcmp(v[i], "-d"))
|
||||
{ if (i > n-2) usage(); database_filename = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-p"))
|
||||
{ if (i > n-2) usage(); port = atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-lp"))
|
||||
{ if (i > n-2) usage(); local_port = atoi(v[++i]); continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
if (database_filename == NULL) {
|
||||
printf("ERROR: provide a database file (-d)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
database = parse_database(database_filename);
|
||||
|
||||
load_config_file(database_filename);
|
||||
get_local_config(&T_messages_txt, &T_messages_txt_len);
|
||||
|
||||
number_of_events = number_of_ids(database);
|
||||
is_on = calloc(number_of_events, sizeof(int));
|
||||
if (is_on == NULL) abort();
|
||||
|
||||
/* create listener socket */
|
||||
l = create_listen_socket("0.0.0.0", local_port);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
current_nfd = 0;
|
||||
|
||||
while (1) {
|
||||
int nfd;
|
||||
int timeout;
|
||||
|
||||
if (s == -1) s = connect_to_tracee(ip, port, number_of_events, is_on);
|
||||
|
||||
/* poll on s (if there), l, and all tracers' sockets */
|
||||
nfd = 1 + (s != -1) + m.ti_size;
|
||||
if (nfd != current_nfd) {
|
||||
current_nfd = nfd;
|
||||
free(fds);
|
||||
fds = calloc(nfd, sizeof(struct pollfd));
|
||||
if (fds == NULL) { perror("calloc"); exit(1); }
|
||||
}
|
||||
i = 0;
|
||||
fds[i].fd = l;
|
||||
fds[i].events = POLLIN;
|
||||
i++;
|
||||
if (s != -1) {
|
||||
fds[i].fd = s;
|
||||
fds[i].events = POLLIN;
|
||||
i++;
|
||||
}
|
||||
for (j = 0; j < m.ti_size; j++) {
|
||||
m.ti[j].poll_id = i;
|
||||
fds[i].fd = m.ti[j].s;
|
||||
fds[i].events = POLLIN;
|
||||
i++;
|
||||
}
|
||||
if (s == -1) timeout = 1000; else timeout = -1;
|
||||
if (poll(fds, nfd, timeout) == -1) { perror("poll"); exit(1); }
|
||||
|
||||
if (fds[0].revents & ~POLLIN) {
|
||||
printf("TODO: error on listen socket?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* new tracer connecting? */
|
||||
if (fds[0].revents & POLLIN) {
|
||||
int t;
|
||||
printf("tracer %d connecting\n", next_id);
|
||||
t = socket_accept(l);
|
||||
if (t == -1) perror("accept");
|
||||
else new_tracer(&m, t, number_of_events,
|
||||
T_messages_txt, T_messages_txt_len, next_id);
|
||||
next_id++;
|
||||
}
|
||||
|
||||
if (s != -1 && fds[1].revents & ~POLLIN) {
|
||||
printf("TODO: error on tracee socket?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* data from tracee */
|
||||
if (s != -1 && fds[1].revents & POLLIN) {
|
||||
int type;
|
||||
int32_t length;
|
||||
if (read_tracee(s, &ebuf, &type, &length) == -1) {
|
||||
clear_remote_config();
|
||||
shutdown(s, SHUT_RDWR);
|
||||
close(s);
|
||||
s = -1;
|
||||
} else {
|
||||
if (type == -1)
|
||||
append_received_config_chunk(ebuf.obuf+ebuf.osize-length, length);
|
||||
else if (type == -2) verify_config();
|
||||
else forward_event(&m, number_of_events, &ebuf, type);
|
||||
}
|
||||
}
|
||||
|
||||
/* status of each tracer */
|
||||
is_on_changed = 0;
|
||||
for (j = 0; j < m.ti_size; j++) {
|
||||
int l;
|
||||
int s;
|
||||
int *t_is_on;
|
||||
if (m.ti[j].poll_id == -1) continue;
|
||||
i = m.ti[j].poll_id;
|
||||
s = m.ti[j].s;
|
||||
t_is_on = m.ti[j].is_on;
|
||||
if (fds[i].revents & (POLLHUP | POLLERR)) goto tracer_error;
|
||||
/* error? */
|
||||
if (fds[i].revents & ~POLLIN) {
|
||||
printf("TODO: error with tracer?\n");
|
||||
exit(1);
|
||||
}
|
||||
/* data in */
|
||||
if (fds[i].revents & POLLIN) {
|
||||
char t;
|
||||
int len;
|
||||
int v;
|
||||
if (fullread(s, &t, 1) != 1) goto tracer_error;
|
||||
switch (t) {
|
||||
case 0:
|
||||
is_on_changed = 1;
|
||||
if (fullread(s, &len, sizeof(int)) == -1) goto tracer_error;
|
||||
for (l = 0; l < len; l++) {
|
||||
if (fullread(s, &v, sizeof(int)) == -1) goto tracer_error;
|
||||
if (v < 0 || v >= number_of_events) goto tracer_error;
|
||||
t_is_on[v] = 1 - t_is_on[v];
|
||||
set_is_on(is_on, v, t_is_on[v]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
is_on_changed = 1;
|
||||
if (fullread(s, &len, sizeof(int)) == -1) goto tracer_error;
|
||||
if (len < 0 || len > number_of_events) goto tracer_error;
|
||||
for (l = 0; l < len; l++) {
|
||||
if (fullread(s, &v, sizeof(int)) == -1) goto tracer_error;
|
||||
if (v < 0 || v > 1) goto tracer_error;
|
||||
if (t_is_on[l] != v) set_is_on(is_on, l, v);
|
||||
t_is_on[l] = v;
|
||||
}
|
||||
break;
|
||||
case 2: break;
|
||||
default: printf("error: unhandled message type %d\n", t); //abort();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
tracer_error:
|
||||
printf("remove tracer %d\n", m.ti[j].id);
|
||||
for (l = 0; l < number_of_events; l++)
|
||||
if (m.ti[j].is_on[l]) { is_on_changed = 1; set_is_on(is_on, l, 0); }
|
||||
remove_tracer(&m, j);
|
||||
j--;
|
||||
}
|
||||
if (is_on_changed && s != -1)
|
||||
if (send_is_on(s, number_of_events, is_on) == -1) {
|
||||
clear_remote_config();
|
||||
shutdown(s, SHUT_RDWR);
|
||||
close(s);
|
||||
s = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -12,7 +12,14 @@
|
||||
#include "logger/logger.h"
|
||||
#include "view/view.h"
|
||||
|
||||
enum var_type {
|
||||
DEFAULT,
|
||||
VCD_FUNCTION,
|
||||
VCD_VARIABLE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum var_type type;
|
||||
char *event;
|
||||
char *arg;
|
||||
char *vcd_name;
|
||||
@@ -44,16 +51,39 @@ void vcd_write_header(vcd_vars *v, int n)
|
||||
"$version\n"
|
||||
" to_vcd\n"
|
||||
"$end\n"
|
||||
"$timescale 1ns $end\n"
|
||||
"$timescale 1ns $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$scope module logic $end\n") <= 0) abort();
|
||||
for (i = 0; i < n; i++)
|
||||
if (v[i].type == DEFAULT)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$scope module functions $end\n") <= 0) abort();
|
||||
for (i = 0; i < n; i++)
|
||||
if (v[i].type == VCD_FUNCTION)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$scope module variables $end\n") <= 0) abort();
|
||||
for (i = 0; i < n; i++)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (v[i].type == VCD_VARIABLE)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n"
|
||||
"$enddefinitions $end\n"
|
||||
"$dumpvars\n") <= 0) abort();
|
||||
|
||||
@@ -194,12 +224,13 @@ void force_stop(int x)
|
||||
}
|
||||
|
||||
vcd_vars *add_var(vcd_vars *vars, int nvars,
|
||||
char *event, char *arg, char *vcd_name, int is_boolean)
|
||||
char *event, char *arg, char *vcd_name, int is_boolean, enum var_type t)
|
||||
{
|
||||
if (nvars % 64 == 0) {
|
||||
vars = realloc(vars, (nvars+64) * sizeof(vcd_vars));
|
||||
if (vars == NULL) abort();
|
||||
}
|
||||
vars[nvars].type = t;
|
||||
vars[nvars].event = event;
|
||||
vars[nvars].arg = arg;
|
||||
vars[nvars].vcd_name = vcd_name;
|
||||
@@ -240,7 +271,7 @@ int main(int n, char **v)
|
||||
char *event = v[++i];
|
||||
char *arg = v[++i];
|
||||
char *vcd_name = v[++i];
|
||||
vars = add_var(vars, nvars, event, arg, vcd_name, 1);
|
||||
vars = add_var(vars, nvars, event, arg, vcd_name, 1, DEFAULT);
|
||||
nvars++;
|
||||
continue;
|
||||
}
|
||||
@@ -248,7 +279,7 @@ int main(int n, char **v)
|
||||
char *event = v[++i];
|
||||
char *arg = v[++i];
|
||||
char *vcd_name = v[++i];
|
||||
vars = add_var(vars, nvars, event, arg, vcd_name, 0);
|
||||
vars = add_var(vars, nvars, event, arg, vcd_name, 0, DEFAULT);
|
||||
nvars++;
|
||||
continue;
|
||||
}
|
||||
@@ -283,20 +314,30 @@ int main(int n, char **v)
|
||||
/* activate all VCD traces */
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
int is_boolean;
|
||||
enum var_type type;
|
||||
int prefix_length;
|
||||
char *name = event_name_from_id(database, i);
|
||||
char *vcd_name;
|
||||
char *var_prefix = "VCD_VARIABLE_";
|
||||
char *fun_prefix = "VCD_FUNCTION_";
|
||||
if (!strncmp(name, var_prefix, strlen(var_prefix))) {
|
||||
prefix_length = strlen(var_prefix);
|
||||
is_boolean = 0;
|
||||
type = VCD_VARIABLE;
|
||||
} else if (!strncmp(name, fun_prefix, strlen(fun_prefix))) {
|
||||
prefix_length = strlen(fun_prefix);
|
||||
is_boolean = 1;
|
||||
type = VCD_FUNCTION;
|
||||
} else
|
||||
continue;
|
||||
vcd_name = event_vcd_name_from_id(database, i);
|
||||
if (vcd_name == NULL) {
|
||||
vcd_name = name+prefix_length;
|
||||
printf("WARNING: ID %s does not define VCD_NAME in the file %s, using %s\n",
|
||||
name, database_filename, vcd_name);
|
||||
}
|
||||
vars = add_var(vars, nvars,
|
||||
name, "value", name+prefix_length, is_boolean);
|
||||
name, "value", vcd_name, is_boolean, type);
|
||||
nvars++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,6 +857,7 @@ int main(int n, char **v)
|
||||
|
||||
restart:
|
||||
clear_remote_config();
|
||||
if (ue_data.socket != -1) close(ue_data.socket);
|
||||
ue_data.socket = connect_to(ip, port);
|
||||
|
||||
/* send the first message - activate selected traces */
|
||||
|
||||
@@ -79,6 +79,36 @@ list *list_append(list *l, void *data)
|
||||
/* socket */
|
||||
/****************************************************************************/
|
||||
|
||||
int create_listen_socket(char *addr, int port)
|
||||
{
|
||||
struct sockaddr_in a;
|
||||
int s;
|
||||
int v;
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
v = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int)))
|
||||
{ perror("setsockopt"); exit(1); }
|
||||
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = htons(port);
|
||||
a.sin_addr.s_addr = inet_addr(addr);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
|
||||
if (listen(s, 5)) { perror("listen"); exit(1); }
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int socket_accept(int s)
|
||||
{
|
||||
struct sockaddr_in a;
|
||||
socklen_t alen;
|
||||
alen = sizeof(a);
|
||||
return accept(s, (struct sockaddr *)&a, &alen);
|
||||
}
|
||||
|
||||
int socket_send(int socket, void *buffer, int size)
|
||||
{
|
||||
char *x = buffer;
|
||||
@@ -94,26 +124,13 @@ int socket_send(int socket, void *buffer, int size)
|
||||
|
||||
int get_connection(char *addr, int port)
|
||||
{
|
||||
struct sockaddr_in a;
|
||||
socklen_t alen;
|
||||
int s, t;
|
||||
|
||||
printf("waiting for connection on %s:%d\n", addr, port);
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
t = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int)))
|
||||
{ perror("setsockopt"); exit(1); }
|
||||
s = create_listen_socket(addr, port);
|
||||
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = htons(port);
|
||||
a.sin_addr.s_addr = inet_addr(addr);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
|
||||
if (listen(s, 5)) { perror("bind"); exit(1); }
|
||||
alen = sizeof(a);
|
||||
t = accept(s, (struct sockaddr *)&a, &alen);
|
||||
t = socket_accept(s);
|
||||
if (t == -1) { perror("accept"); exit(1); }
|
||||
close(s);
|
||||
|
||||
@@ -137,14 +154,11 @@ int fullread(int fd, void *_buf, int count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connect_to(char *addr, int port)
|
||||
int try_connect_to(char *addr, int port)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_in a;
|
||||
|
||||
printf("connecting to %s:%d\n", addr, port);
|
||||
|
||||
again:
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
|
||||
@@ -155,6 +169,21 @@ again:
|
||||
if (connect(s, (struct sockaddr *)&a, sizeof(a)) == -1) {
|
||||
perror("connect");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int connect_to(char *addr, int port)
|
||||
{
|
||||
int s;
|
||||
|
||||
printf("connecting to %s:%d\n", addr, port);
|
||||
|
||||
again:
|
||||
s = try_connect_to(addr, port);
|
||||
if (s == -1) {
|
||||
printf("trying again in 1s\n");
|
||||
sleep(1);
|
||||
goto again;
|
||||
|
||||
@@ -24,11 +24,14 @@ list *list_append(list *l, void *data);
|
||||
#define DEFAULT_REMOTE_IP "127.0.0.1"
|
||||
#define DEFAULT_REMOTE_PORT 2021
|
||||
|
||||
int create_listen_socket(char *addr, int port);
|
||||
int socket_accept(int s);
|
||||
/* socket_send: return 0 if okay, -1 on error */
|
||||
int socket_send(int socket, void *buffer, int size);
|
||||
int get_connection(char *addr, int port);
|
||||
/* fullread: return length read if okay (that is: 'count'), -1 on error */
|
||||
int fullread(int fd, void *_buf, int count);
|
||||
int try_connect_to(char *addr, int port);
|
||||
int connect_to(char *addr, int port);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -745,7 +745,7 @@ void itti_exit_task(void)
|
||||
|
||||
#if defined(OAI_EMU) || defined(RTAI)
|
||||
if (task_id > TASK_UNKNOWN) {
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_RECV_MSG,
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_ITTI_RECV_MSG,
|
||||
__sync_and_and_fetch (&itti_desc.vcd_receive_msg, ~(1L << task_id)));
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user