/******************************************************************************* * 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 *******************************************************************************/ /* * Diagnostics service. * This service is used for framework and agents testing. */ #include #include #include #include #include #include #include #include #include #include #include #if ENABLE_Symbols # include #endif #if SERVICE_Streams # include #endif #if ENABLE_RCBP_TEST # include
# include #endif #include static const char * DIAGNOSTICS = "Diagnostics"; #if ENABLE_RCBP_TEST typedef struct ContextExtensionDiag { int test_process; Channel * channel; } ContextExtensionDiag; static size_t context_extension_offset = 0; #define EXT(ctx) ((ContextExtensionDiag *)((char *)(ctx) + context_extension_offset)) int is_test_process(Context * ctx) { #if defined(_WRS_KERNEL) return 1; #else return EXT(context_get_group(ctx, CONTEXT_GROUP_PROCESS))->test_process; #endif } static void channel_close_listener(Channel * c) { LINK * l = context_root.next; while (l != &context_root) { Context * ctx = ctxl2ctxp(l); l = l->next; if (EXT(ctx)->channel == c || (ctx->creator != NULL && EXT(ctx->creator)->channel == c)) { terminate_debug_context(ctx); } } l = context_root.next; while (l != &context_root) { Context * ctx = ctxl2ctxp(l); if (EXT(ctx)->channel == c) EXT(ctx)->channel = NULL; l = l->next; } } #endif /* ENABLE_RCBP_TEST */ typedef struct RunTestDoneArgs RunTestDoneArgs; struct RunTestDoneArgs { Channel * c; Context * ctx; char token[256]; }; static void command_echo(char * token, Channel * c) { char str[0x1000]; int len = json_read_string(&c->inp, str, sizeof(str)); if (len >= (int)sizeof(str)) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); write_stringz(&c->out, "R"); write_stringz(&c->out, token); json_write_string_len(&c->out, str, len); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); } static void command_echo_fp(char * token, Channel * c) { double x = json_read_double(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); write_stringz(&c->out, "R"); write_stringz(&c->out, token); json_write_double(&c->out, x); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); } static void command_echo_err(char * token, Channel * c) { int no = read_errno(&c->inp); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, no); json_write_string(&c->out, errno_to_str(no)); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); } static void command_get_test_list(char * token, Channel * c) { const char * arr = "[]"; if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, 0); #if ENABLE_RCBP_TEST arr = "[\"RCBP1\"]"; #endif write_stringz(&c->out, arr); write_stream(&c->out, MARKER_EOM); } #if ENABLE_RCBP_TEST static void run_test_done(int error, Context * ctx, void * arg) { RunTestDoneArgs * data = (RunTestDoneArgs *)arg; Channel * c = data->c; if (ctx != NULL) { EXT(context_get_group(ctx, CONTEXT_GROUP_PROCESS))->test_process = 1; EXT(ctx)->channel = c; } if (!is_channel_closed(c)) { write_stringz(&c->out, "R"); write_stringz(&c->out, data->token); write_errno(&c->out, error); json_write_string(&c->out, ctx ? ctx->id : NULL); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); } else if (ctx != NULL) { terminate_debug_context(ctx); } channel_unlock(c); loc_free(data); } #endif static void command_run_test(char * token, Channel * c) { int err = 0; char id[256]; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); if (strcmp(id, "RCBP1") == 0) { #if ENABLE_RCBP_TEST RunTestDoneArgs * data = (RunTestDoneArgs *)loc_alloc_zero(sizeof(RunTestDoneArgs)); data->c = c; strcpy(data->token, token); if (run_test_process(run_test_done, data) == 0) { channel_lock(c); return; } err = errno; loc_free(data); #else err = EINVAL; #endif } else { err = EINVAL; } write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); json_write_string(&c->out, NULL); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); } static void command_cancel_test(char * token, Channel * c) { char id[256]; int err = 0; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); #if ENABLE_RCBP_TEST if (terminate_debug_context(id2ctx(id)) != 0) err = errno; #else err = ERR_UNSUPPORTED; #endif write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); } static void write_symbol(Channel * c, ContextAddress address) { if (address == 0) { write_stringz(&c->out, "null"); } else { write_stream(&c->out, '{'); json_write_string(&c->out, "Abs"); write_stream(&c->out, ':'); json_write_boolean(&c->out, 1); write_stream(&c->out, ','); json_write_string(&c->out, "Value"); write_stream(&c->out, ':'); json_write_uint64(&c->out, address); write_stream(&c->out, '}'); write_stream(&c->out, 0); } } #if ENABLE_Symbols typedef struct GetSymbolArgs { char token[256]; Context * ctx; char * name; } GetSymbolArgs; static void get_symbol_cache_client(void * x) { GetSymbolArgs * args = (GetSymbolArgs *)x; Channel * c = cache_channel(); Context * ctx = args->ctx; Symbol * sym = NULL; ContextAddress addr = 0; int error = 0; if (ctx->exited) { error = ERR_ALREADY_EXITED; } else if (find_symbol_by_name(ctx, STACK_NO_FRAME, 0, args->name, &sym) < 0) { error = errno; } else if (get_symbol_address(sym, &addr) < 0) { error = errno; } cache_exit(); write_stringz(&c->out, "R"); write_stringz(&c->out, args->token); write_errno(&c->out, error); write_symbol(c, addr); write_stream(&c->out, MARKER_EOM); context_unlock(ctx); loc_free(args->name); } #endif /* ENABLE_Symbols */ static void command_get_symbol(char * token, Channel * c) { char id[256]; char * name = NULL; int error = 0; ContextAddress addr = 0; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); name = json_read_alloc_string(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); #if ENABLE_DebugContext { Context *ctx = id2ctx(id); if (ctx == NULL) { error = ERR_INV_CONTEXT; } else if (ctx->exited) { error = ERR_ALREADY_EXITED; } else { #if ENABLE_Symbols GetSymbolArgs args; strlcpy(args.token, token, sizeof(args.token)); context_lock(ctx); args.ctx = ctx; args.name = name; cache_enter(get_symbol_cache_client, c, &args, sizeof(args)); return; #elif ENABLE_RCBP_TEST void * ptr = NULL; int cls = 0; if (find_test_symbol(ctx, name, &ptr, &cls) < 0) error = errno; addr = (ContextAddress)ptr; #else error = ERR_UNSUPPORTED; #endif } } #else error = ERR_UNSUPPORTED; #endif write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, error); write_symbol(c, addr); write_stream(&c->out, MARKER_EOM); loc_free(name); } #if SERVICE_Streams typedef struct StreamsTest { VirtualStream * inp; VirtualStream * out; char buf[111]; size_t buf_pos; size_t buf_len; int inp_eos; int out_eos; } StreamsTest; static void streams_test_callback(VirtualStream * stream, int event_code, void * args) { StreamsTest * st = (StreamsTest *)args; switch (event_code) { case VS_EVENT_SPACE_AVAILABLE: if (stream != st->out) return; break; case VS_EVENT_DATA_AVAILABLE: if (stream != st->inp) return; break; } if (st->buf_pos == st->buf_len && !st->inp_eos) { st->buf_pos = st->buf_len = 0; virtual_stream_get_data(st->inp, st->buf, sizeof(st->buf), &st->buf_len, &st->inp_eos); } if (st->buf_len > st->buf_pos || st->inp_eos != st->out_eos) { size_t done = 0; virtual_stream_add_data(st->out, st->buf + st->buf_pos, st->buf_len - st->buf_pos, &done, st->inp_eos); st->buf_pos += done; if (st->buf_pos == st->buf_len && st->inp_eos) st->out_eos = 1; } if (st->inp_eos && st->out_eos) loc_free(st); } #endif /* SERVICE_Streams */ static void command_create_test_streams(char * token, Channel * c) { char id_inp[256]; char id_out[256]; long buf_size0; long buf_size1; int err = 0; buf_size0 = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); buf_size1 = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); #if SERVICE_Streams if (buf_size0 <= 0 || buf_size1 <= 0) err = ERR_INV_NUMBER; if (!err) { StreamsTest * st = (StreamsTest *)loc_alloc_zero(sizeof(StreamsTest)); virtual_stream_create(DIAGNOSTICS, NULL, (unsigned)buf_size0, VS_ENABLE_REMOTE_WRITE, streams_test_callback, st, &st->inp); virtual_stream_create(DIAGNOSTICS, NULL, (unsigned)buf_size1, VS_ENABLE_REMOTE_READ, streams_test_callback, st, &st->out); virtual_stream_get_id(st->inp, id_inp, sizeof(id_inp)); virtual_stream_get_id(st->out, id_out, sizeof(id_out)); } #else err = ERR_UNSUPPORTED; #endif write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); if (err) { write_stringz(&c->out, "null"); write_stringz(&c->out, "null"); } else { json_write_string(&c->out, id_inp); write_stream(&c->out, 0); json_write_string(&c->out, id_out); write_stream(&c->out, 0); } write_stream(&c->out, MARKER_EOM); } static void command_dispose_test_stream(char * token, Channel * c) { char id[256]; int err = 0; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); #if SERVICE_Streams if (!err) { VirtualStream * stream = virtual_stream_find(id); if (stream == NULL) err = errno; else virtual_stream_delete(stream); } #else err = ERR_UNSUPPORTED; #endif write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); } void ini_diagnostics_service(Protocol * proto) { add_command_handler(proto, DIAGNOSTICS, "echo", command_echo); add_command_handler(proto, DIAGNOSTICS, "echoFP", command_echo_fp); add_command_handler(proto, DIAGNOSTICS, "echoERR", command_echo_err); add_command_handler(proto, DIAGNOSTICS, "getTestList", command_get_test_list); add_command_handler(proto, DIAGNOSTICS, "runTest", command_run_test); add_command_handler(proto, DIAGNOSTICS, "cancelTest", command_cancel_test); add_command_handler(proto, DIAGNOSTICS, "getSymbol", command_get_symbol); add_command_handler(proto, DIAGNOSTICS, "createTestStreams", command_create_test_streams); add_command_handler(proto, DIAGNOSTICS, "disposeTestStream", command_dispose_test_stream); #if ENABLE_RCBP_TEST context_extension_offset = context_extension(sizeof(ContextExtensionDiag)); add_channel_close_listener(channel_close_listener); #endif }