| /******************************************************************************* |
| * 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 |
| *******************************************************************************/ |
| |
| |
| #include <config.h> |
| |
| #if SERVICE_Symbols |
| |
| #include <framework/channel.h> |
| #include <framework/json.h> |
| #include <framework/myalloc.h> |
| #include <framework/exceptions.h> |
| #include <framework/cache.h> |
| #include <services/stacktrace.h> |
| #include <services/symbols.h> |
| |
| static const char * SYMBOLS = "Symbols"; |
| |
| typedef struct CommandGetContextArgs { |
| char token[256]; |
| char id[256]; |
| } CommandGetContextArgs; |
| |
| static void command_get_context_cache_client(void * x) { |
| CommandGetContextArgs * args = (CommandGetContextArgs *)x; |
| Channel * c = cache_channel(); |
| int err = 0; |
| Symbol * sym = NULL; |
| char * owner = NULL; |
| char * name = NULL; |
| int update_policy = 0; |
| int sym_class = SYM_CLASS_UNKNOWN; |
| int type_class = TYPE_CLASS_UNKNOWN; |
| Symbol * type = NULL; |
| Symbol * base = NULL; |
| Symbol * index = NULL; |
| int has_size = 0; |
| int has_length = 0; |
| int has_lower_bound = 0; |
| int has_offset = 0; |
| int has_address = 0; |
| int big_endian = 0; |
| ContextAddress size = 0; |
| ContextAddress length = 0; |
| int64_t lower_bound = 0; |
| ContextAddress offset = 0; |
| ContextAddress address = 0; |
| RegisterDefinition * reg = NULL; |
| Context * reg_ctx = NULL; |
| int reg_frame = 0; |
| SYM_FLAGS flags = 0; |
| void * value = NULL; |
| size_t value_size = 0; |
| |
| if (id2symbol(args->id, &sym) < 0) err = errno; |
| |
| if (err == 0) { |
| get_symbol_class(sym, &sym_class); |
| get_symbol_update_policy(sym, &owner, &update_policy); |
| get_symbol_name(sym, &name); |
| get_symbol_type_class(sym, &type_class); |
| get_symbol_type(sym, &type); |
| get_symbol_base_type(sym, &base); |
| get_symbol_index_type(sym, &index); |
| has_size = get_symbol_size(sym, &size) == 0; |
| has_length = get_symbol_length(sym, &length) == 0; |
| if (has_length) { |
| has_lower_bound = get_symbol_lower_bound(sym, &lower_bound) == 0; |
| } |
| if (sym_class == SYM_CLASS_REFERENCE) { |
| has_offset = get_symbol_offset(sym, &offset) == 0; |
| } |
| if (sym_class == SYM_CLASS_REFERENCE || sym_class == SYM_CLASS_FUNCTION) { |
| has_address = get_symbol_address(sym, &address) == 0; |
| get_symbol_register(sym, ®_ctx, ®_frame, ®); |
| } |
| if (sym_class == SYM_CLASS_VALUE) { |
| get_symbol_value(sym, &value, &value_size, &big_endian); |
| } |
| get_symbol_flags(sym, &flags); |
| } |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| if (err == 0) { |
| |
| write_stream(&c->out, '{'); |
| |
| json_write_string(&c->out, "ID"); |
| write_stream(&c->out, ':'); |
| json_write_string(&c->out, args->id); |
| write_stream(&c->out, ','); |
| |
| if (owner != NULL) { |
| json_write_string(&c->out, "OwnerID"); |
| write_stream(&c->out, ':'); |
| json_write_string(&c->out, owner); |
| write_stream(&c->out, ','); |
| |
| json_write_string(&c->out, "UpdatePolicy"); |
| write_stream(&c->out, ':'); |
| json_write_long(&c->out, update_policy); |
| write_stream(&c->out, ','); |
| } |
| |
| if (name != NULL) { |
| json_write_string(&c->out, "Name"); |
| write_stream(&c->out, ':'); |
| json_write_string(&c->out, name); |
| write_stream(&c->out, ','); |
| } |
| |
| if (type_class != TYPE_CLASS_UNKNOWN) { |
| json_write_string(&c->out, "TypeClass"); |
| write_stream(&c->out, ':'); |
| json_write_long(&c->out, type_class); |
| write_stream(&c->out, ','); |
| } |
| |
| if (type != NULL) { |
| json_write_string(&c->out, "TypeID"); |
| write_stream(&c->out, ':'); |
| json_write_string(&c->out, symbol2id(type)); |
| write_stream(&c->out, ','); |
| } |
| |
| if (base != NULL) { |
| json_write_string(&c->out, "BaseTypeID"); |
| write_stream(&c->out, ':'); |
| json_write_string(&c->out, symbol2id(base)); |
| write_stream(&c->out, ','); |
| } |
| |
| if (index != NULL) { |
| json_write_string(&c->out, "IndexTypeID"); |
| write_stream(&c->out, ':'); |
| json_write_string(&c->out, symbol2id(index)); |
| write_stream(&c->out, ','); |
| } |
| |
| if (has_size) { |
| json_write_string(&c->out, "Size"); |
| write_stream(&c->out, ':'); |
| json_write_uint64(&c->out, size); |
| write_stream(&c->out, ','); |
| } |
| |
| if (has_length) { |
| json_write_string(&c->out, "Length"); |
| write_stream(&c->out, ':'); |
| json_write_uint64(&c->out, length); |
| write_stream(&c->out, ','); |
| |
| if (has_lower_bound) { |
| json_write_string(&c->out, "LowerBound"); |
| write_stream(&c->out, ':'); |
| json_write_int64(&c->out, lower_bound); |
| write_stream(&c->out, ','); |
| |
| json_write_string(&c->out, "UpperBound"); |
| write_stream(&c->out, ':'); |
| json_write_int64(&c->out, lower_bound + (int64_t)length - 1); |
| write_stream(&c->out, ','); |
| } |
| } |
| |
| if (has_offset) { |
| json_write_string(&c->out, "Offset"); |
| write_stream(&c->out, ':'); |
| json_write_uint64(&c->out, offset); |
| write_stream(&c->out, ','); |
| } |
| |
| if (has_address) { |
| json_write_string(&c->out, "Address"); |
| write_stream(&c->out, ':'); |
| json_write_uint64(&c->out, address); |
| write_stream(&c->out, ','); |
| } |
| |
| if (reg != NULL) { |
| json_write_string(&c->out, "Register"); |
| write_stream(&c->out, ':'); |
| json_write_string(&c->out, register2id(reg_ctx, reg_frame, reg)); |
| write_stream(&c->out, ','); |
| } |
| |
| if (flags) { |
| json_write_string(&c->out, "Flags"); |
| write_stream(&c->out, ':'); |
| json_write_long(&c->out, flags); |
| write_stream(&c->out, ','); |
| } |
| |
| if (value != NULL) { |
| json_write_string(&c->out, "Value"); |
| write_stream(&c->out, ':'); |
| json_write_binary(&c->out, value, value_size); |
| write_stream(&c->out, ','); |
| |
| if (big_endian) { |
| json_write_string(&c->out, "BigEndian"); |
| write_stream(&c->out, ':'); |
| json_write_boolean(&c->out, 1); |
| write_stream(&c->out, ','); |
| } |
| } |
| |
| json_write_string(&c->out, "Class"); |
| write_stream(&c->out, ':'); |
| json_write_long(&c->out, sym_class); |
| |
| write_stream(&c->out, '}'); |
| write_stream(&c->out, 0); |
| } |
| else { |
| write_stringz(&c->out, "null"); |
| } |
| |
| write_stream(&c->out, MARKER_EOM); |
| } |
| |
| static void command_get_context(char * token, Channel * c) { |
| CommandGetContextArgs args; |
| |
| json_read_string(&c->inp, args.id, sizeof(args.id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_get_context_cache_client, c, &args, sizeof(args)); |
| } |
| |
| typedef struct CommandGetChildrenArgs { |
| char token[256]; |
| char id[256]; |
| } CommandGetChildrenArgs; |
| |
| static void command_get_children_cache_client(void * x) { |
| CommandGetChildrenArgs * args = (CommandGetChildrenArgs *)x; |
| Channel * c = cache_channel(); |
| int err = 0; |
| Symbol * sym = NULL; |
| Symbol ** list = NULL; |
| int cnt = 0; |
| |
| if (id2symbol(args->id, &sym) < 0) err = errno; |
| if (err == 0 && get_symbol_children(sym, &list, &cnt) < 0) err = errno; |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| if (err == 0) { |
| int i; |
| write_stream(&c->out, '['); |
| for (i = 0; i < cnt; i++) { |
| if (i > 0) write_stream(&c->out, ','); |
| json_write_string(&c->out, symbol2id(list[i])); |
| } |
| write_stream(&c->out, ']'); |
| write_stream(&c->out, 0); |
| } |
| else { |
| write_stringz(&c->out, "null"); |
| } |
| |
| write_stream(&c->out, MARKER_EOM); |
| } |
| |
| static void command_get_children(char * token, Channel * c) { |
| CommandGetChildrenArgs args; |
| |
| json_read_string(&c->inp, args.id, sizeof(args.id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_get_children_cache_client, c, &args, sizeof(args)); |
| } |
| |
| typedef struct CommandFindByNameArgs { |
| char token[256]; |
| char id[256]; |
| ContextAddress ip; |
| char * name; |
| } CommandFindByNameArgs; |
| |
| static void command_find_by_name_cache_client(void * x) { |
| CommandFindByNameArgs * args = (CommandFindByNameArgs *)x; |
| Channel * c = cache_channel(); |
| Context * ctx = NULL; |
| int frame = STACK_NO_FRAME; |
| Symbol * sym = NULL; |
| int err = 0; |
| |
| if (id2frame(args->id, &ctx, &frame) < 0) ctx = id2ctx(args->id); |
| if (ctx == NULL) err = set_errno(ERR_INV_CONTEXT, args->id); |
| else if (ctx->exited) err = ERR_ALREADY_EXITED; |
| |
| if (err == 0 && find_symbol_by_name(ctx, frame, args->ip, args->name, &sym) < 0) err = errno; |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| if (err == 0) { |
| json_write_string(&c->out, symbol2id(sym)); |
| write_stream(&c->out, 0); |
| } |
| else { |
| write_stringz(&c->out, "null"); |
| } |
| |
| write_stream(&c->out, MARKER_EOM); |
| loc_free(args->name); |
| } |
| |
| static void command_find_by_name(char * token, Channel * c) { |
| CommandFindByNameArgs args; |
| |
| args.ip = 0; |
| json_read_string(&c->inp, args.id, sizeof(args.id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (peek_stream(&c->inp) != '"' && peek_stream(&c->inp) != 'n') { |
| args.ip = (ContextAddress)json_read_uint64(&c->inp); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| } |
| args.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); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_find_by_name_cache_client, c, &args, sizeof(args)); |
| } |
| |
| typedef struct CommandFindByAddrArgs { |
| char token[256]; |
| char id[256]; |
| ContextAddress addr; |
| } CommandFindByAddrArgs; |
| |
| static void command_find_by_addr_cache_client(void * x) { |
| CommandFindByAddrArgs * args = (CommandFindByAddrArgs *)x; |
| Channel * c = cache_channel(); |
| Context * ctx = NULL; |
| int frame = STACK_NO_FRAME; |
| Symbol * sym = NULL; |
| int err = 0; |
| |
| if (id2frame(args->id, &ctx, &frame) < 0) ctx = id2ctx(args->id); |
| if (ctx == NULL) err = set_errno(ERR_INV_CONTEXT, args->id); |
| else if (ctx->exited) err = ERR_ALREADY_EXITED; |
| |
| if (err == 0 && find_symbol_by_addr(ctx, frame, args->addr, &sym) < 0) err = errno; |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| if (err == 0) { |
| json_write_string(&c->out, symbol2id(sym)); |
| write_stream(&c->out, 0); |
| } |
| else { |
| write_stringz(&c->out, "null"); |
| } |
| |
| write_stream(&c->out, MARKER_EOM); |
| } |
| |
| static void command_find_by_addr(char * token, Channel * c) { |
| CommandFindByAddrArgs args; |
| |
| json_read_string(&c->inp, args.id, sizeof(args.id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| args.addr = (ContextAddress)json_read_uint64(&c->inp); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_find_by_addr_cache_client, c, &args, sizeof(args)); |
| } |
| |
| typedef struct CommandFindInScopeArgs { |
| char token[256]; |
| char frame_id[256]; |
| char scope_id[256]; |
| ContextAddress ip; |
| char * name; |
| } CommandFindInScopeArgs; |
| |
| static void command_find_in_scope_cache_client(void * x) { |
| CommandFindInScopeArgs * args = (CommandFindInScopeArgs *)x; |
| Channel * c = cache_channel(); |
| Context * ctx = NULL; |
| int frame = STACK_NO_FRAME; |
| Symbol * scope = NULL; |
| Symbol * sym = NULL; |
| int err = 0; |
| |
| if (id2frame(args->frame_id, &ctx, &frame) < 0) ctx = id2ctx(args->frame_id); |
| if (ctx == NULL) err = set_errno(ERR_INV_CONTEXT, args->frame_id); |
| else if (ctx->exited) err = ERR_ALREADY_EXITED; |
| |
| if (err == 0 && args->scope_id[0] && id2symbol(args->scope_id, &scope) < 0) err = errno; |
| if (err == 0 && find_symbol_in_scope(ctx, frame, args->ip, scope, args->name, &sym) < 0) err = errno; |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| if (err == 0) { |
| json_write_string(&c->out, symbol2id(sym)); |
| write_stream(&c->out, 0); |
| } |
| else { |
| write_stringz(&c->out, "null"); |
| } |
| |
| write_stream(&c->out, MARKER_EOM); |
| loc_free(args->name); |
| } |
| |
| static void command_find_in_scope(char * token, Channel * c) { |
| CommandFindInScopeArgs args; |
| |
| json_read_string(&c->inp, args.frame_id, sizeof(args.frame_id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| args.ip = (ContextAddress)json_read_uint64(&c->inp); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| json_read_string(&c->inp, args.scope_id, sizeof(args.scope_id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| args.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); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_find_in_scope_cache_client, c, &args, sizeof(args)); |
| } |
| |
| typedef struct CommandListArgs { |
| char token[256]; |
| char id[256]; |
| } CommandListArgs; |
| |
| static Symbol ** list_buf = NULL; |
| static unsigned list_cnt = 0; |
| static unsigned list_max = 0; |
| |
| static void list_callback(void * x, Symbol * sym) { |
| if (list_cnt >= list_max) { |
| list_max = list_max == 0 ? 32 : list_max * 2; |
| list_buf = (Symbol **)loc_realloc(list_buf, sizeof(Symbol *) * list_max); |
| } |
| list_buf[list_cnt++] = sym; |
| } |
| |
| static void command_list_cache_client(void * x) { |
| CommandListArgs * args = (CommandListArgs *)x; |
| Channel * c = cache_channel(); |
| Context * ctx = NULL; |
| int frame = STACK_NO_FRAME; |
| int err = 0; |
| |
| list_cnt = 0; |
| |
| if (id2frame(args->id, &ctx, &frame) < 0) ctx = id2ctx(args->id); |
| if (ctx == NULL) err = set_errno(ERR_INV_CONTEXT, args->id); |
| else if (ctx->exited) err = ERR_ALREADY_EXITED; |
| |
| if (err == 0 && enumerate_symbols(ctx, frame, list_callback, NULL) < 0) err = errno; |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| if (err == 0) { |
| unsigned i = 0; |
| write_stream(&c->out, '['); |
| for (i = 0; i < list_cnt; i++) { |
| if (i > 0) write_stream(&c->out, ','); |
| json_write_string(&c->out, symbol2id(list_buf[i])); |
| } |
| write_stream(&c->out, ']'); |
| write_stream(&c->out, 0); |
| } |
| else { |
| write_stringz(&c->out, "null"); |
| } |
| |
| write_stream(&c->out, MARKER_EOM); |
| } |
| |
| static void command_list(char * token, Channel * c) { |
| CommandListArgs args; |
| |
| json_read_string(&c->inp, args.id, sizeof(args.id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_list_cache_client, c, &args, sizeof(args)); |
| } |
| |
| typedef struct CommandGetArrayTypeArgs { |
| char token[256]; |
| char id[256]; |
| uint64_t length; |
| } CommandGetArrayTypeArgs; |
| |
| static void command_get_array_type_cache_client(void * x) { |
| CommandGetArrayTypeArgs * args = (CommandGetArrayTypeArgs *)x; |
| Channel * c = cache_channel(); |
| Symbol * sym = NULL; |
| Symbol * arr = NULL; |
| int err = 0; |
| |
| if (id2symbol(args->id, &sym) < 0) err = errno; |
| if (err == 0 && get_array_symbol(sym, (ContextAddress)args->length, &arr) < 0) err = errno; |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| if (err == 0) { |
| json_write_string(&c->out, symbol2id(arr)); |
| write_stream(&c->out, 0); |
| } |
| else { |
| write_stringz(&c->out, "null"); |
| } |
| |
| write_stream(&c->out, MARKER_EOM); |
| } |
| |
| static void command_get_array_type(char * token, Channel * c) { |
| CommandGetArrayTypeArgs args; |
| |
| json_read_string(&c->inp, args.id, sizeof(args.id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| args.length = json_read_uint64(&c->inp); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_get_array_type_cache_client, c, &args, sizeof(args)); |
| } |
| |
| typedef struct CommandFindFrameInfo { |
| char token[256]; |
| char id[256]; |
| ContextAddress addr; |
| } CommandFindFrameInfo; |
| |
| static void write_commands(OutputStream * out, Context * ctx, StackTracingCommandSequence * seq) { |
| if (seq != NULL) { |
| int i; |
| write_stream(out, '['); |
| for (i = 0; i < seq->cmds_cnt; i++) { |
| StackTracingCommand * cmd = seq->cmds + i; |
| if (i > 0) write_stream(out, ','); |
| json_write_long(out, cmd->cmd); |
| switch (cmd->cmd) { |
| case SFT_CMD_NUMBER: |
| write_stream(out, ','); |
| json_write_int64(out, cmd->num); |
| break; |
| case SFT_CMD_REGISTER: |
| write_stream(out, ','); |
| json_write_string(out, register2id(ctx, STACK_NO_FRAME, cmd->reg)); |
| break; |
| case SFT_CMD_DEREF: |
| write_stream(out, ','); |
| json_write_ulong(out, cmd->size); |
| write_stream(out, ','); |
| json_write_boolean(out, cmd->big_endian); |
| break; |
| } |
| } |
| write_stream(out, ']'); |
| } |
| else { |
| write_string(out, "null"); |
| } |
| } |
| |
| static void command_find_frame_info_cache_client(void * x) { |
| CommandFindFrameInfo * args = (CommandFindFrameInfo *)x; |
| Channel * c = cache_channel(); |
| Context * ctx = NULL; |
| StackTracingInfo * info = NULL; |
| int err = 0; |
| |
| ctx = id2ctx(args->id); |
| if (ctx == NULL) err = ERR_INV_CONTEXT; |
| else if (get_stack_tracing_info(ctx, args->addr, &info) < 0) err = errno; |
| |
| cache_exit(); |
| |
| write_stringz(&c->out, "R"); |
| write_stringz(&c->out, args->token); |
| write_errno(&c->out, err); |
| |
| json_write_uint64(&c->out, info ? info->addr : 0); |
| write_stream(&c->out, 0); |
| json_write_uint64(&c->out, info ? info->size : 0); |
| write_stream(&c->out, 0); |
| |
| write_commands(&c->out, ctx, info ? info->fp : NULL); |
| write_stream(&c->out, 0); |
| |
| if (info != NULL && info->regs != NULL) { |
| int i; |
| write_stream(&c->out, '{'); |
| for (i = 0; i < info->reg_cnt; i++) { |
| if (i > 0) write_stream(&c->out, ','); |
| json_write_string(&c->out, register2id(ctx, STACK_NO_FRAME, info->regs[i]->reg)); |
| write_stream(&c->out, ':'); |
| write_commands(&c->out, ctx, info->regs[i]); |
| } |
| write_stream(&c->out, '}'); |
| } |
| else { |
| write_string(&c->out, "null"); |
| } |
| write_stream(&c->out, 0); |
| |
| write_stream(&c->out, MARKER_EOM); |
| } |
| |
| static void command_find_frame_info(char * token, Channel * c) { |
| CommandFindFrameInfo args; |
| |
| json_read_string(&c->inp, args.id, sizeof(args.id)); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| args.addr = (ContextAddress)json_read_uint64(&c->inp); |
| if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| strlcpy(args.token, token, sizeof(args.token)); |
| cache_enter(command_find_frame_info_cache_client, c, &args, sizeof(args)); |
| } |
| |
| void ini_symbols_service(Protocol * proto) { |
| static int ini_done = 0; |
| if (!ini_done) { |
| ini_symbols_lib(); |
| ini_done = 1; |
| } |
| add_command_handler(proto, SYMBOLS, "getContext", command_get_context); |
| add_command_handler(proto, SYMBOLS, "getChildren", command_get_children); |
| add_command_handler(proto, SYMBOLS, "find", command_find_by_name); |
| add_command_handler(proto, SYMBOLS, "findByAddr", command_find_by_addr); |
| add_command_handler(proto, SYMBOLS, "findInScope", command_find_in_scope); |
| add_command_handler(proto, SYMBOLS, "list", command_list); |
| add_command_handler(proto, SYMBOLS, "getArrayType", command_get_array_type); |
| add_command_handler(proto, SYMBOLS, "findFrameInfo", command_find_frame_info); |
| } |
| |
| #endif /* SERVICE_Symbols */ |