/******************************************************************************* * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * Wind River Systems - initial API and implementation *******************************************************************************/ /* * Agent self-testing service. */ #include #if ENABLE_RCBP_TEST #include #include #include #include #include #include #include #include #include #include #if defined(_WIN32) # include #endif #ifdef __cplusplus bool tcf_cpp_test_bool = false; class tcf_cpp_test_class { public: static int s_int; class tcf_cpp_test_class_nested; }; class tcf_cpp_test_class_extension : tcf_cpp_test_class { public: int f_int; }; class tcf_cpp_test_class::tcf_cpp_test_class_nested { public: static int s_int; int f_int; }; int tcf_cpp_test_class::s_int = 1; int tcf_cpp_test_class::tcf_cpp_test_class_nested::s_int = 2; tcf_cpp_test_class_extension * tcf_cpp_text_ce = (tcf_cpp_test_class_extension *)3; extern "C" { #endif /* __cplusplus */ typedef enum test_enum { enum_val1 = 1, enum_val2 = 2, enum_val3 = 3 } test_enum; typedef union test_union { int x; float y; } test_union; typedef struct test_struct { test_enum f_enum; int f_int; struct test_struct * f_struct; float f_float; double f_double; test_union f_union; } test_struct; typedef int test_array[10001]; extern void tcf_test_func3(void); extern int tcf_test_func2(void); extern void tcf_test_func1(void); extern void tcf_test_func0(enum test_enum); /* Main purpose of this declaration is to pull basic types info into DWARF */ char tcf_test_char = 0; short tcf_test_short = 0; long tcf_test_long = 0; void tcf_test_func3(void) { tcf_test_char++; usleep(1000); } int tcf_test_func2(void) { int func2_local1 = 1; int func2_local2 = 2; test_struct func2_local3 = { enum_val3, 153, NULL, 3.14f, 2.71 }; int * func2_local4 = NULL; func2_local3.f_struct = &func2_local3; tcf_test_short++; errno = tcf_test_short; func2_local4 = &errno; tcf_test_func3(); func2_local1++; func2_local2 = func2_local1; return func2_local2 + *func2_local4; } void tcf_test_func1(void) { tcf_test_long++; tcf_test_func2(); } void tcf_test_func0(test_enum e) { tcf_test_func1(); } static char array[0x1000]; char * tcf_test_array = array; #ifdef __cplusplus } #endif static void * test_sub(void * x) { volatile int * test_done = (int *)x; while (!*test_done) { tcf_test_func0(enum_val3); } return NULL; } void test_proc(void) { int i; pthread_t thread[4]; int test_done = 0; tcf_test_func0(enum_val1); for (i = 0; i < 4; i++) { thread[i] = 0; } for (i = 0; i < 4; i++) { if (pthread_create(thread + i, &pthread_create_attr, test_sub, &test_done) != 0) { perror("pthread_create"); break; } } for (i = 0; i < 9; i++) { tcf_test_func0(enum_val2); } test_done = 1; for (i = 0; i < 4; i++) { if (thread[i]) pthread_join(thread[i], NULL); } } int find_test_symbol(Context * ctx, const char * name, void ** addr, int * sym_class) { /* This code allows to run TCF diagnostic tests when symbols info is not available */ if (is_test_process(ctx) && strncmp(name, "tcf_test_", 9) == 0) { *addr = NULL; if (strcmp(name, "tcf_test_array") == 0) { *sym_class = SYM_CLASS_REFERENCE; *addr = &tcf_test_array; } else if (strcmp(name, "tcf_test_char") == 0) { *sym_class = SYM_CLASS_REFERENCE; *addr = &tcf_test_char; } else { *sym_class = SYM_CLASS_FUNCTION; if (strcmp(name, "tcf_test_func0") == 0) *addr = (void *)&tcf_test_func0; else if (strcmp(name, "tcf_test_func1") == 0) *addr = (void *)&tcf_test_func1; else if (strcmp(name, "tcf_test_func2") == 0) *addr = (void *)&tcf_test_func2; else if (strcmp(name, "tcf_test_func3") == 0) *addr = (void *)&tcf_test_func3; } if (*addr != NULL) return 0; } errno = ERR_SYM_NOT_FOUND; return -1; } #if defined(_WIN32) typedef struct ContextAttachArgs { ContextAttachCallBack * done; void * data; HANDLE thread; HANDLE process; } ContextAttachArgs; static void done_context_attach(int error, Context * ctx, void * data) { ContextAttachArgs * args = (ContextAttachArgs *)data; args->done(error, ctx, args->data); assert(error || args->process != get_context_handle(ctx)); CloseHandle(args->thread); CloseHandle(args->process); loc_free(args); } #endif /* defined(_WIN32) */ int run_test_process(ContextAttachCallBack * done, void * data) { #if defined(_WIN32) char fnm[FILE_PATH_SIZE]; char cmd[FILE_PATH_SIZE]; int res = 0; STARTUPINFO si; PROCESS_INFORMATION prs; ContextAttachArgs * args; memset(&si, 0, sizeof(si)); memset(&prs, 0, sizeof(prs)); memset(fnm, 0, sizeof(fnm)); if (GetModuleFileName(NULL, fnm, sizeof(fnm)) == 0) { set_win32_errno(GetLastError()); return -1; } si.cb = sizeof(si); strcpy(cmd, "agent.exe -t"); if (CreateProcess(fnm, cmd, NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW, NULL, NULL, &si, &prs) == 0) { set_win32_errno(GetLastError()); return -1; } args = (ContextAttachArgs *)loc_alloc(sizeof(ContextAttachArgs)); args->done = done; args->data = data; args->thread = prs.hThread; args->process = prs.hProcess; res = context_attach(prs.dwProcessId, done_context_attach, args, 0); if (res != 0) loc_free(args); return res; #elif defined(_WRS_KERNEL) int tid = taskCreate("tTcf", 100, 0, 0x4000, (FUNCPTR)test_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (tid == 0) return -1; taskStop(tid); taskActivate(tid); assert(taskIsStopped(tid)); return context_attach(tid, done, data, 0); #else /* Create child process to debug */ int pid = fork(); if (pid < 0) return -1; if (pid == 0) { int fd; if (context_attach_self() < 0) exit(1); fd = sysconf(_SC_OPEN_MAX); while (fd-- > 2) close(fd); if (tkill(getpid(), SIGSTOP) < 0) exit(1); test_proc(); exit(0); } return context_attach(pid, done, data, CONTEXT_ATTACH_SELF); #endif } #endif /* ENABLE_RCBP_TEST */