Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/memoryservice.c')
-rw-r--r--agent/tcf/services/memoryservice.c700
1 files changed, 700 insertions, 0 deletions
diff --git a/agent/tcf/services/memoryservice.c b/agent/tcf/services/memoryservice.c
new file mode 100644
index 00000000..b1847d16
--- /dev/null
+++ b/agent/tcf/services/memoryservice.c
@@ -0,0 +1,700 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 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
+ *******************************************************************************/
+
+/*
+ * TCF Memory - memory access service.
+ */
+
+#include <config.h>
+
+#if SERVICE_Memory
+
+#include <assert.h>
+#include <framework/protocol.h>
+#include <framework/context.h>
+#include <framework/json.h>
+#include <framework/exceptions.h>
+#include <framework/myalloc.h>
+#include <framework/channel.h>
+#include <framework/trace.h>
+#include <services/memoryservice.h>
+#include <services/runctrl.h>
+
+static const char * MEMORY = "Memory";
+
+static TCFBroadcastGroup * broadcast_group = NULL;
+
+#define BYTE_VALID 0x00
+#define BYTE_UNKNOWN 0x01
+#define BYTE_INVALID 0x02
+#define BYTE_CANNOT_READ 0x04
+#define BYTE_CANNOT_WRITE 0x08
+
+#define CMD_GET 1
+#define CMD_SET 2
+#define CMD_FILL 3
+
+#define BUF_SIZE (128 * MEM_USAGE_FACTOR)
+
+typedef struct MemoryCommandArgs {
+ Channel * c;
+ char token[256];
+ ContextAddress addr;
+ unsigned long size;
+ int word_size;
+ int mode;
+ Context * ctx;
+} MemoryCommandArgs;
+
+static void write_context(OutputStream * out, Context * ctx) {
+ assert(!ctx->exited);
+
+ write_stream(out, '{');
+
+ json_write_string(out, "ID");
+ write_stream(out, ':');
+ json_write_string(out, ctx->id);
+
+ if (ctx->parent != NULL) {
+ write_stream(out, ',');
+ json_write_string(out, "ParentID");
+ write_stream(out, ':');
+ json_write_string(out, ctx->parent->id);
+ }
+
+ write_stream(out, ',');
+ json_write_string(out, "ProcessID");
+ write_stream(out, ':');
+ json_write_string(out, context_get_group(ctx, CONTEXT_GROUP_PROCESS)->id);
+
+ if (ctx->name != NULL) {
+ write_stream(out, ',');
+ json_write_string(out, "Name");
+ write_stream(out, ':');
+ json_write_string(out, ctx->name);
+ }
+
+ write_stream(out, ',');
+ json_write_string(out, "BigEndian");
+ write_stream(out, ':');
+ json_write_boolean(out, ctx->big_endian);
+
+ if (ctx->mem_access) {
+ int cnt = 0;
+
+ write_stream(out, ',');
+ json_write_string(out, "AddressSize");
+ write_stream(out, ':');
+ json_write_ulong(out, context_word_size(ctx));
+
+ write_stream(out, ',');
+ json_write_string(out, "AccessTypes");
+ write_stream(out, ':');
+ write_stream(out, '[');
+ if (ctx->mem_access & MEM_ACCESS_INSTRUCTION) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "instruction");
+ }
+ if (ctx->mem_access & MEM_ACCESS_DATA) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "data");
+ }
+ if (ctx->mem_access & MEM_ACCESS_IO) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "io");
+ }
+ if (ctx->mem_access & MEM_ACCESS_USER) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "user");
+ }
+ if (ctx->mem_access & MEM_ACCESS_SUPERVISOR) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "supervisor");
+ }
+ if (ctx->mem_access & MEM_ACCESS_HYPERVISOR) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "hypervisor");
+ }
+ if (ctx->mem_access & MEM_ACCESS_VIRTUAL) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "virtual");
+ }
+ if (ctx->mem_access & MEM_ACCESS_PHYSICAL) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "physical");
+ }
+ if (ctx->mem_access & MEM_ACCESS_CACHE) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "cache");
+ }
+ if (ctx->mem_access & MEM_ACCESS_TLB) {
+ if (cnt++) write_stream(out, ',');
+ json_write_string(out, "tlb");
+ }
+ write_stream(out, ']');
+ }
+
+ write_stream(out, '}');
+}
+
+static void write_ranges(OutputStream * out, ContextAddress addr, int offs, int status, MemoryErrorInfo * err_info) {
+ int cnt = 0;
+ size_t size_valid = 0;
+ size_t size_error = 0;
+
+ if (err_info->error) {
+ size_valid = err_info->size_valid + offs;
+ size_error = err_info->size_error;
+ }
+ else {
+ size_valid = offs;
+ }
+
+ write_stream(out, '[');
+ if (size_valid > 0) {
+ write_stream(out, '{');
+
+ json_write_string(out, "addr");
+ write_stream(out, ':');
+ json_write_uint64(out, addr);
+ write_stream(out, ',');
+
+ json_write_string(out, "size");
+ write_stream(out, ':');
+ json_write_ulong(out, size_valid);
+ write_stream(out, ',');
+
+ json_write_string(out, "stat");
+ write_stream(out, ':');
+ json_write_ulong(out, 0);
+
+ write_stream(out, '}');
+ cnt++;
+ }
+ if (size_error > 0) {
+ if (cnt > 0) write_stream(out, ',');
+ write_stream(out, '{');
+
+ json_write_string(out, "addr");
+ write_stream(out, ':');
+ json_write_uint64(out, addr + size_valid);
+ write_stream(out, ',');
+
+ json_write_string(out, "size");
+ write_stream(out, ':');
+ json_write_ulong(out, size_error);
+ write_stream(out, ',');
+
+ json_write_string(out, "stat");
+ write_stream(out, ':');
+ json_write_ulong(out, BYTE_INVALID | status);
+ write_stream(out, ',');
+
+ json_write_string(out, "msg");
+ write_stream(out, ':');
+ write_error_object(out, err_info->error);
+
+ write_stream(out, '}');
+ }
+ write_stream(out, ']');
+ write_stream(out, 0);
+}
+
+static void command_get_context(char * token, Channel * c) {
+ int err = 0;
+ char id[256];
+ Context * ctx = NULL;
+
+ 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);
+
+ ctx = id2ctx(id);
+
+ if (ctx == NULL || ctx->mem_access == 0) err = ERR_INV_CONTEXT;
+ else if (ctx->exited) err = ERR_ALREADY_EXITED;
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+ write_errno(&c->out, err);
+ if (err == 0) {
+ write_context(&c->out, ctx);
+ }
+ else {
+ write_string(&c->out, "null");
+ }
+ write_stream(&c->out, 0);
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, Channel * c) {
+ 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);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ write_errno(&c->out, 0);
+
+ write_stream(&c->out, '[');
+ if (id[0] == 0) {
+ LINK * qp;
+ int cnt = 0;
+ for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+ Context * ctx = ctxl2ctxp(qp);
+ if (ctx->parent != NULL) continue;
+ if (ctx->exited) continue;
+ if (ctx->mem_access == 0 && list_is_empty(&ctx->children)) continue;
+ if (cnt > 0) write_stream(&c->out, ',');
+ json_write_string(&c->out, ctx->id);
+ cnt++;
+ }
+ }
+ else {
+ Context * parent = id2ctx(id);
+ if (parent != NULL) {
+ LINK * l;
+ int cnt = 0;
+ for (l = parent->children.next; l != &parent->children; l = l->next) {
+ Context * ctx = cldl2ctxp(l);
+ assert(ctx->parent == parent);
+ if (ctx->exited) continue;
+ if (ctx->mem_access == 0 && list_is_empty(&ctx->children)) continue;
+ if (cnt > 0) write_stream(&c->out, ',');
+ json_write_string(&c->out, ctx->id);
+ cnt++;
+ }
+ }
+ }
+ write_stream(&c->out, ']');
+ write_stream(&c->out, 0);
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static MemoryCommandArgs * read_command_args(char * token, Channel * c, int cmd) {
+ int err = 0;
+ char id[256];
+ MemoryCommandArgs buf;
+ memset(&buf, 0, sizeof(buf));
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ buf.addr = json_read_ulong(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ buf.word_size = (int)json_read_long(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ buf.size = (int)json_read_long(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ buf.mode = (int)json_read_long(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (cmd == CMD_GET && read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ buf.ctx = id2ctx(id);
+ if (buf.ctx == NULL) err = ERR_INV_CONTEXT;
+ else if (buf.ctx->exited) err = ERR_ALREADY_EXITED;
+ else if (buf.ctx->mem_access == 0) err = ERR_INV_CONTEXT;
+
+ if (err != 0) {
+ if (cmd != CMD_GET) {
+ int ch;
+ while ((ch = read_stream(&c->inp)) != 0) {
+ if (ch < 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);
+ if (cmd == CMD_GET) write_stringz(&c->out, "null");
+ write_errno(&c->out, err);
+ write_stringz(&c->out, "null");
+ write_stream(&c->out, MARKER_EOM);
+ return NULL;
+ }
+ else {
+ MemoryCommandArgs * args = (MemoryCommandArgs *)loc_alloc(sizeof(MemoryCommandArgs));
+ *args = buf;
+ args->c = c;
+ strlcpy(args->token, token, sizeof(args->token));
+ channel_lock(c);
+ context_lock(buf.ctx);
+ return args;
+ }
+}
+
+void send_event_memory_changed(Context * ctx, ContextAddress addr, unsigned long size) {
+ OutputStream * out = &broadcast_group->out;
+
+ write_stringz(out, "E");
+ write_stringz(out, MEMORY);
+ write_stringz(out, "memoryChanged");
+
+ json_write_string(out, ctx->id);
+ write_stream(out, 0);
+
+ /* <array of addres ranges> */
+ write_stream(out, '[');
+ write_stream(out, '{');
+
+ json_write_string(out, "addr");
+ write_stream(out, ':');
+ json_write_uint64(out, addr);
+
+ write_stream(out, ',');
+
+ json_write_string(out, "size");
+ write_stream(out, ':');
+ json_write_ulong(out, size);
+
+ write_stream(out, '}');
+ write_stream(out, ']');
+ write_stream(out, 0);
+
+ write_stream(out, MARKER_EOM);
+}
+
+static void safe_memory_set(void * parm) {
+ MemoryCommandArgs * args = (MemoryCommandArgs *)parm;
+ Channel * c = args->c;
+ Context * ctx = args->ctx;
+
+ if (!is_channel_closed(c)) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ InputStream * inp = &c->inp;
+ OutputStream * out = &c->out;
+ char * token = args->token;
+ ContextAddress addr0 = args->addr;
+ ContextAddress addr = args->addr;
+ unsigned long size = 0;
+ char buf[BUF_SIZE];
+ int err = 0;
+ MemoryErrorInfo err_info;
+ JsonReadBinaryState state;
+
+ memset(&err_info, 0, sizeof(err_info));
+ if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED;
+
+ json_read_binary_start(&state, inp);
+ for (;;) {
+ int rd = json_read_binary_data(&state, buf, sizeof(buf));
+ if (rd == 0) break;
+ if (err == 0) {
+ /* TODO: word size, mode */
+ if (context_write_mem(ctx, addr, buf, rd) < 0) {
+ err = errno;
+#if ENABLE_ExtendedMemoryErrorReports
+ context_get_mem_error_info(&err_info);
+#endif
+ }
+ else {
+ addr += rd;
+ }
+ }
+ size += rd;
+ }
+ json_read_binary_end(&state);
+ if (read_stream(inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ send_event_memory_changed(ctx, addr0, size);
+
+ write_stringz(out, "R");
+ write_stringz(out, token);
+ write_errno(out, err);
+ if (err == 0) {
+ write_stringz(out, "null");
+ }
+ else {
+ write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_WRITE, &err_info);
+ }
+ write_stream(out, MARKER_EOM);
+ clear_trap(&trap);
+ }
+ else {
+ trace(LOG_ALWAYS, "Exception in message handler: %d %s",
+ trap.error, errno_to_str(trap.error));
+ channel_close(c);
+ }
+ }
+ channel_unlock(c);
+ context_unlock(ctx);
+ loc_free(args);
+}
+
+static void command_set(char * token, Channel * c) {
+ MemoryCommandArgs * args = read_command_args(token, c, CMD_SET);
+ if (args != NULL) post_safe_event(args->ctx, safe_memory_set, args);
+}
+
+static void safe_memory_get(void * parm) {
+ MemoryCommandArgs * args = (MemoryCommandArgs *)parm;
+ Channel * c = args->c;
+ Context * ctx = args->ctx;
+
+ if (!is_channel_closed(c)) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ OutputStream * out = &args->c->out;
+ char * token = args->token;
+ ContextAddress addr0 = args->addr;
+ ContextAddress addr = args->addr;
+ unsigned long size = args->size;
+ unsigned long pos = 0;
+ char buf[BUF_SIZE];
+ int err = 0;
+ MemoryErrorInfo err_info;
+ JsonWriteBinaryState state;
+
+ if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED;
+
+ write_stringz(out, "R");
+ write_stringz(out, token);
+
+ json_write_binary_start(&state, out, size);
+ while (pos < size) {
+ int rd = size - pos;
+ if (rd > BUF_SIZE) rd = BUF_SIZE;
+ /* TODO: word size, mode */
+ memset(buf, 0, rd);
+ if (err == 0) {
+ if (context_read_mem(ctx, addr, buf, rd) < 0) {
+ err = errno;
+#if ENABLE_ExtendedMemoryErrorReports
+ context_get_mem_error_info(&err_info);
+#endif
+ }
+ else {
+ addr += rd;
+ }
+ }
+ json_write_binary_data(&state, buf, rd);
+ pos += rd;
+ }
+ json_write_binary_end(&state);
+ write_stream(out, 0);
+
+ write_errno(out, err);
+ if (err == 0) {
+ write_stringz(out, "null");
+ }
+ else {
+ write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_READ, &err_info);
+ }
+ write_stream(out, MARKER_EOM);
+ clear_trap(&trap);
+ }
+ else {
+ trace(LOG_ALWAYS, "Exception in message handler: %d %s",
+ trap.error, errno_to_str(trap.error));
+ channel_close(c);
+ }
+ }
+ channel_unlock(c);
+ context_unlock(ctx);
+ loc_free(args);
+}
+
+static void command_get(char * token, Channel * c) {
+ MemoryCommandArgs * args = read_command_args(token, c, CMD_GET);
+ if (args != NULL) post_safe_event(args->ctx, safe_memory_get, args);
+}
+
+static void safe_memory_fill(void * parm) {
+ MemoryCommandArgs * args = (MemoryCommandArgs *)parm;
+ Channel * c = args->c;
+ Context * ctx = args->ctx;
+
+ if (!is_channel_closed(c)) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ InputStream * inp = &c->inp;
+ OutputStream * out = &c->out;
+ char * token = args->token;
+ ContextAddress addr0 = args->addr;
+ ContextAddress addr = args->addr;
+ unsigned long size = args->size;
+ MemoryErrorInfo err_info;
+ char buf[0x1000];
+ int buf_pos = 0;
+ int err = 0;
+
+ if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED;
+
+ if (read_stream(inp) != '[') exception(ERR_JSON_SYNTAX);
+ if (peek_stream(inp) == ']') {
+ read_stream(inp);
+ }
+ else {
+ for (;;) {
+ int ch;
+ if (err == 0) {
+ if (buf_pos >= (int)sizeof(buf)) err = ERR_BUFFER_OVERFLOW;
+ else buf[buf_pos++] = (char)json_read_ulong(inp);
+ }
+ else {
+ json_read_ulong(inp);
+ }
+ ch = read_stream(inp);
+ if (ch == ',') continue;
+ if (ch == ']') break;
+ exception(ERR_JSON_SYNTAX);
+ }
+ }
+ if (read_stream(inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ while (err == 0 && buf_pos < (int)size && buf_pos <= (int)(sizeof(buf) / 2)) {
+ if (buf_pos == 0) {
+ buf[buf_pos++] = 0;
+ }
+ else {
+ memcpy(buf + buf_pos, buf, buf_pos);
+ buf_pos *= 2;
+ }
+ }
+
+ while (err == 0 && addr < addr0 + size) {
+ char tmp[sizeof(buf)];
+ int wr = (int)(addr0 + size - addr);
+ if (wr > buf_pos) wr = buf_pos;
+ /* TODO: word size, mode */
+ memcpy(tmp, buf, wr);
+ if (context_write_mem(ctx, addr, tmp, wr) < 0) {
+ err = errno;
+#if ENABLE_ExtendedMemoryErrorReports
+ context_get_mem_error_info(&err_info);
+#endif
+ }
+ else {
+ addr += wr;
+ }
+ }
+
+ send_event_memory_changed(ctx, addr0, size);
+
+ write_stringz(out, "R");
+ write_stringz(out, token);
+ write_errno(out, err);
+ if (err == 0) {
+ write_stringz(out, "null");
+ }
+ else {
+ write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_WRITE, &err_info);
+ }
+ write_stream(out, MARKER_EOM);
+ clear_trap(&trap);
+ }
+ else {
+ trace(LOG_ALWAYS, "Exception in message handler: %d %s",
+ trap.error, errno_to_str(trap.error));
+ channel_close(c);
+ }
+ }
+ channel_unlock(c);
+ context_unlock(ctx);
+ loc_free(args);
+}
+
+static void command_fill(char * token, Channel * c) {
+ MemoryCommandArgs * args = read_command_args(token, c, CMD_FILL);
+ if (args != NULL) post_safe_event(args->ctx, safe_memory_fill, args);
+}
+
+static void send_event_context_added(Context * ctx) {
+ OutputStream * out = &broadcast_group->out;
+
+ write_stringz(out, "E");
+ write_stringz(out, MEMORY);
+ write_stringz(out, "contextAdded");
+
+ /* <array of context data> */
+ write_stream(out, '[');
+ write_context(out, ctx);
+ write_stream(out, ']');
+ write_stream(out, 0);
+
+ write_stream(out, MARKER_EOM);
+}
+
+static void send_event_context_changed(Context * ctx) {
+ OutputStream * out = &broadcast_group->out;
+
+ write_stringz(out, "E");
+ write_stringz(out, MEMORY);
+ write_stringz(out, "contextChanged");
+
+ /* <array of context data> */
+ write_stream(out, '[');
+ write_context(out, ctx);
+ write_stream(out, ']');
+ write_stream(out, 0);
+
+ write_stream(out, MARKER_EOM);
+}
+
+static void send_event_context_removed(Context * ctx) {
+ OutputStream * out = &broadcast_group->out;
+
+ write_stringz(out, "E");
+ write_stringz(out, MEMORY);
+ write_stringz(out, "contextRemoved");
+
+ /* <array of context IDs> */
+ write_stream(out, '[');
+ json_write_string(out, ctx->id);
+ write_stream(out, ']');
+ write_stream(out, 0);
+
+ write_stream(out, MARKER_EOM);
+}
+
+static void event_context_created(Context * ctx, void * args) {
+ if (ctx->mem_access == 0) return;
+ send_event_context_added(ctx);
+}
+
+static void event_context_changed(Context * ctx, void * args) {
+ if (ctx->mem_access == 0) return;
+ send_event_context_changed(ctx);
+}
+
+static void event_context_exited(Context * ctx, void * args) {
+ if (ctx->mem_access == 0) return;
+ send_event_context_removed(ctx);
+}
+
+void ini_memory_service(Protocol * proto, TCFBroadcastGroup * bcg) {
+ static ContextEventListener listener = {
+ event_context_created,
+ event_context_exited,
+ NULL,
+ NULL,
+ event_context_changed
+ };
+ broadcast_group = bcg;
+ add_context_event_listener(&listener, NULL);
+ add_command_handler(proto, MEMORY, "getContext", command_get_context);
+ add_command_handler(proto, MEMORY, "getChildren", command_get_children);
+ add_command_handler(proto, MEMORY, "set", command_set);
+ add_command_handler(proto, MEMORY, "get", command_get);
+ add_command_handler(proto, MEMORY, "fill", command_fill);
+}
+
+#endif /* SERVICE_Memory */

Back to the top