blob: b0de94f5a8b61898be6d1e50b4cfd2b8a2492ea8 [file] [log] [blame]
/*******************************************************************************
* 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, &reg_ctx, &reg_frame, &reg);
}
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 */