diff options
author | eutarass | 2009-12-19 00:41:43 +0000 |
---|---|---|
committer | eutarass | 2009-12-19 00:41:43 +0000 |
commit | b7d627d444635e21b3a06f52ae36b72d03e823a0 (patch) | |
tree | 41110c1e3089724e133fa57eda4c4a41ef83fb54 /server | |
parent | 58102f2a785fffa0e2585b387f948c9b975f909e (diff) | |
download | org.eclipse.tcf.agent-b7d627d444635e21b3a06f52ae36b72d03e823a0.tar.gz org.eclipse.tcf.agent-b7d627d444635e21b3a06f52ae36b72d03e823a0.tar.xz org.eclipse.tcf.agent-b7d627d444635e21b3a06f52ae36b72d03e823a0.zip |
TCF Agent: more support for developing value-add TCF servers, including:
1. remote data cache abstraction.
2. support for storing and re-sending TCF error reports: struct ErrorReport.
3. new service: Memory Map.
4. byte array output stream implementation.
Diffstat (limited to 'server')
-rw-r--r-- | server/config.h | 16 | ||||
-rw-r--r-- | server/main/main.c | 50 | ||||
-rw-r--r-- | server/server.vcproj | 44 | ||||
-rw-r--r-- | server/services/context-proxy.c | 375 | ||||
-rw-r--r-- | server/services/context-proxy.h | 27 |
5 files changed, 474 insertions, 38 deletions
diff --git a/server/config.h b/server/config.h index 6bd046c6..2e8ba79f 100644 --- a/server/config.h +++ b/server/config.h @@ -20,6 +20,12 @@ #if !defined(SERVICE_Locator) #define SERVICE_Locator 1 #endif +#if !defined(SERVICE_FileSystem) +#define SERVICE_FileSystem 1 +#endif +#if !defined(SERVICE_LineNumbers) +#define SERVICE_LineNumbers 1 +#endif #if !defined(ENABLE_ZeroCopy) #define ENABLE_ZeroCopy 1 @@ -54,7 +60,7 @@ #endif #if !defined(ENABLE_SSL) -# if (TARGET_UNIX) && !defined(__APPLE__) +# if defined(__linux__) # define ENABLE_SSL 1 # else # define ENABLE_SSL 0 @@ -68,12 +74,20 @@ */ #include "discovery.h" +#include "filesystem.h" +#include "linenumbers.h" #include "diagnostics.h" static void ini_services(Protocol * proto, TCFBroadcastGroup * bcg, TCFSuspendGroup * spg) { #if SERVICE_Locator ini_locator_service(proto, bcg); #endif +#if SERVICE_FileSystem + ini_file_system_service(proto); +#endif +#if SERVICE_LineNumbers + ini_line_numbers_service(proto); +#endif ini_diagnostics_service(proto); } diff --git a/server/main/main.c b/server/main/main.c index ba453890..0b1ce582 100644 --- a/server/main/main.c +++ b/server/main/main.c @@ -29,12 +29,8 @@ #include "events.h" #include "trace.h" #include "myalloc.h" -#include "json.h" -#include "channel.h" -#include "protocol.h" -#include "proxy.h" -#include "discovery.h" #include "errors.h" +#include "context-proxy.h" static char * progname; static Protocol * proto; @@ -42,37 +38,25 @@ static ChannelServer * serv; static TCFBroadcastGroup * bcg; static TCFSuspendGroup * spg; -static void channel_server_connecting(Channel * c) { - trace(LOG_PROTOCOL, "channel server connecting"); - - send_hello_message(c->client_data, c); - flush_stream(&c->out); -} - -static void channel_server_connected(Channel * c) { +static void channel_redirected(Channel * host, Channel * target) { int i; - - trace(LOG_PROTOCOL, "channel server connected, peer services:"); - for (i = 0; i < c->peer_service_cnt; i++) { - trace(LOG_PROTOCOL, " %s", c->peer_service_list[i]); + int service_ln = 0; + int service_mm = 0; + for (i = 0; i < target->peer_service_cnt; i++) { + protocol_get_service(host->protocol, target->peer_service_list[i]); + if (strcmp(target->peer_service_list[i], "LineNumbers") == 0) service_ln = 1; + if (strcmp(target->peer_service_list[i], "MemoryMap") == 0) service_mm = 1; + } + if (!service_ln && service_mm) { + ini_line_numbers_service(host->protocol); + create_context_proxy(host, target); } -} - -static void channel_server_receive(Channel * c) { - handle_protocol_message(c->client_data, c); -} - -static void channel_server_disconnected(Channel * c) { - trace(LOG_PROTOCOL, "channel server disconnected"); } static void channel_new_connection(ChannelServer * serv, Channel * c) { protocol_reference(proto); - c->client_data = proto; - c->connecting = channel_server_connecting; - c->connected = channel_server_connected; - c->receive = channel_server_receive; - c->disconnected = channel_server_disconnected; + c->protocol = proto; + c->redirected = channel_redirected; channel_set_suspend_group(c, spg); channel_set_broadcast_group(c, bcg); channel_start(c); @@ -162,22 +146,20 @@ int main(int argc, char ** argv) { ps = channel_peer_from_url(url); if (ps == NULL) { - fprintf(stderr, "invalid server URL (-s option value): %s\n", url); + fprintf(stderr, "%s: invalid server URL (-s option value): %s\n", progname, url); exit(1); } peer_server_addprop(ps, loc_strdup("Name"), loc_strdup("TCF Proxy")); peer_server_addprop(ps, loc_strdup("Proxy"), loc_strdup("")); serv = channel_server(ps); if (serv == NULL) { - fprintf(stderr, "cannot create TCF server\n"); + fprintf(stderr, "%s: cannot create TCF server: %s\n", progname, errno_to_str(errno)); exit(1); } serv->new_conn = channel_new_connection; discovery_start(); - /* Process events - must run on the initial thread since ptrace() - * returns ECHILD otherwise, thinking we are not the owner. */ run_event_loop(); return 0; } diff --git a/server/server.vcproj b/server/server.vcproj index e1e76838..ddf7ba73 100644 --- a/server/server.vcproj +++ b/server/server.vcproj @@ -177,6 +177,10 @@ >
</File>
<File
+ RelativePath=".\services\context-proxy.h"
+ >
+ </File>
+ <File
RelativePath="..\agent\services\diagnostics.c"
>
</File>
@@ -188,6 +192,34 @@ RelativePath="..\agent\services\discovery_udp.c"
>
</File>
+ <File
+ RelativePath="..\agent\services\dwarfcache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\services\dwarfexpr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\services\dwarfframe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\services\dwarfio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\services\filesystem.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\services\linenumbers_elf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\services\tcf_elf.c"
+ >
+ </File>
</Filter>
<Filter
Name="main"
@@ -209,6 +241,14 @@ >
</File>
<File
+ RelativePath="..\agent\framework\cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\framework\cache.h"
+ >
+ </File>
+ <File
RelativePath="..\agent\framework\channel.c"
>
</File>
@@ -221,6 +261,10 @@ >
</File>
<File
+ RelativePath="..\agent\framework\cpudefs.c"
+ >
+ </File>
+ <File
RelativePath="..\agent\framework\errors.c"
>
</File>
diff --git a/server/services/context-proxy.c b/server/services/context-proxy.c index f57aea74..830407b9 100644 --- a/server/services/context-proxy.c +++ b/server/services/context-proxy.c @@ -21,21 +21,305 @@ #if ENABLE_DebugContext && ENABLE_ContextProxy #include <errno.h> +#include <assert.h> #include "context.h" +#include "myalloc.h" +#include "exceptions.h" +#include "protocol.h" +#include "json.h" +#include "cache.h" +#include "memorymap.h" +#include "context-proxy.h" typedef struct ContextCache ContextCache; +typedef struct MemoryCache MemoryCache; typedef struct PeerCache PeerCache; struct ContextCache { Context * ctx; + PeerCache * peer; + AbstractCache cache; + + /* Memory Map */ + ErrorReport * mem_regions_error; + unsigned mem_regions_cnt; + MemoryRegion * mem_regions; + ReplyHandlerInfo * pending_get_map; + + /* Register definitions */ + ErrorReport * reg_error; + unsigned reg_cnt; + char ** reg_ids; + char * reg_ids_str; + RegisterDefinition * reg_defs; + RegisterDefinition * pc_def; + ReplyHandlerInfo * pending_get_regs; + + /* Run Control */ + int has_state; + + /* Memory */ + LINK mem_cache; +}; + +struct MemoryCache { + LINK link; + AbstractCache cache; + int canceled; + ErrorReport * error; + ContextAddress addr; + void * buf; + size_t size; + ReplyHandlerInfo * pending_command; }; struct PeerCache { - int x; + LINK link_all; + Channel * host; + Channel * target; }; +#define peers2peer(A) ((PeerCache *)((char *)(A) - offsetof(PeerCache, link_all))) +#define mems2mem(A) ((MemoryCache *)((char *)(A) - offsetof(MemoryCache, link))) + +static LINK peers; + +static MemoryRegion * mem_buf = NULL; +static unsigned mem_buf_max = 0; +static unsigned mem_buf_pos = 0; + +static unsigned * ids_buf = NULL; +static unsigned ids_buf_max = 0; +static unsigned ids_buf_pos = 0; + +static char * str_buf = NULL; +static unsigned str_buf_max = 0; +static unsigned str_buf_pos = 0; + +static char * map_to_local_file(char * file_name) { + return file_name; +} + +static void read_memory_map_struct(InputStream * inp, char * name, void * args) { + MemoryRegion * m = (MemoryRegion *)args; + if (strcmp(name, "Addr") == 0) m->addr = (ContextAddress)json_read_int64(inp); + else if (strcmp(name, "Size") == 0) m->size = json_read_ulong(inp); + else if (strcmp(name, "Offs") == 0) m->file_offs = json_read_ulong(inp); + else if (strcmp(name, "Flags") == 0) m->flags = json_read_ulong(inp); + else if (strcmp(name, "FileName") == 0) m->file_name = json_read_alloc_string(inp); + else loc_free(json_skip_object(inp)); +} + +static void read_memory_map_item(InputStream * inp, void * args) { + MemoryRegion * m; + if (mem_buf_pos >= mem_buf_max) { + mem_buf_max = mem_buf_max == 0 ? 16 : mem_buf_max * 2; + mem_buf = loc_realloc(mem_buf, sizeof(MemoryRegion) * mem_buf_max); + } + m = mem_buf + mem_buf_pos; + memset(m, 0, sizeof(MemoryRegion)); + if (json_read_struct(inp, read_memory_map_struct, m) && m->file_name != NULL) { + struct stat buf; + char * fnm = map_to_local_file(m->file_name); + if (fnm != m->file_name) { + loc_free(m->file_name); + m->file_name = fnm == NULL ? NULL : loc_strdup(fnm); + } + if (fnm == NULL || stat(fnm, &buf) < 0) { + loc_free(m->file_name); + } + else { + m->dev = buf.st_dev; + m->ino = buf.st_ino; + mem_buf_pos++; + } + } +} + +static void read_ids_item(InputStream * inp, void * args) { + int n; + char id[256]; + if (ids_buf_pos >= ids_buf_max) { + ids_buf_max = ids_buf_max == 0 ? 16 : ids_buf_max * 2; + ids_buf = loc_realloc(ids_buf, sizeof(unsigned) * ids_buf_max); + } + n = json_read_string(inp, id, sizeof(id)); + if (n <= 0) return; + n++; + if (n > sizeof(id)) n = sizeof(id); + if (str_buf_pos + n > str_buf_max) { + str_buf_max = str_buf_max == 0 ? sizeof(id) : str_buf_max * 2; + str_buf = loc_realloc(str_buf, str_buf_max); + } + memcpy(str_buf + str_buf_pos, id, n); + ids_buf[ids_buf_pos++] = str_buf_pos; + str_buf_pos += n; +} + +static int validate_context_cache(Channel * c, void * args, int error) { + ContextCache * cache = (ContextCache *)args; + + assert(cache->peer->target == c); + if (cache->ctx->parent == NULL) { + /* Get memory map */ + if (cache->pending_get_map != NULL) { + assert(cache->mem_regions == NULL); + cache->mem_regions_error = get_error_report(error); + if (!error) { + cache->mem_regions_error = get_error_report(read_errno(&c->inp)); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + mem_buf_pos = 0; + json_read_array(&c->inp, read_memory_map_item, NULL); + cache->mem_regions_cnt = mem_buf_pos; + cache->mem_regions = loc_alloc(sizeof(MemoryRegion) * mem_buf_pos); + memcpy(cache->mem_regions, mem_buf, sizeof(MemoryRegion) * mem_buf_pos); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + } + } + else if (cache->mem_regions == NULL && cache->mem_regions_error == 0) { + cache->pending_get_map = protocol_send_command(c, "MemoryMap", "get", validate_context_cache, args); + write_stringz(&c->out, container_id(cache->ctx)); + write_stream(&c->out, MARKER_EOM); + flush_stream(&c->out); + return 0; + } + } + else { + /* Get register descriptions */ + if (cache->pending_get_regs != NULL) { + assert(cache->reg_ids == NULL); + assert(cache->reg_ids_str == NULL); + cache->reg_error = get_error_report(error); + if (!error) { + unsigned i; + cache->reg_error = get_error_report(read_errno(&c->inp)); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + ids_buf_pos = 0; + str_buf_pos = 0; + json_read_array(&c->inp, read_ids_item, NULL); + cache->reg_cnt = ids_buf_pos; + cache->reg_ids = loc_alloc(sizeof(char *) * ids_buf_pos); + cache->reg_ids_str = loc_alloc(str_buf_pos); + memcpy(cache->reg_ids_str, str_buf, str_buf_pos); + for (i = 0; i < cache->reg_cnt; i++) { + cache->reg_ids[i] = cache->reg_ids_str + ids_buf[i]; + } + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + } + } + else if (cache->reg_ids == NULL && cache->reg_error == 0) { + cache->pending_get_regs = protocol_send_command(c, "Registers", "getChildren", validate_context_cache, args); + write_stringz(&c->out, thread_id(cache->ctx)); + write_stream(&c->out, MARKER_EOM); + flush_stream(&c->out); + return 0; + } + } + + return 1; +} + +static void event_context_added(Channel * c, void * args) { + PeerCache * p = (PeerCache *)args; +} + +static void event_context_removed(Channel * c, void * args) { + PeerCache * p = (PeerCache *)args; +} + +static ContextCache * alloc_context_cache(void) { + ContextCache * c = loc_alloc_zero(sizeof(ContextCache)); + list_init(&c->mem_cache); +} + +void create_context_proxy(Channel * host, Channel * target) { + LINK * l; + PeerCache * p; + for (l = peers.next; l != &peers; l = l->next) { + p = peers2peer(l); + if (p->target == target) return; + } + p = loc_alloc_zero(sizeof(PeerCache)); + p->host = host; + p->target = target; + list_add_first(&p->link_all, &peers); + channel_lock(host); +#if 0 + /* TODO: need to read and forward event message at same time */ + add_event_handler2(target, "RunControl", "contextAdded", event_context_added, p); + add_event_handler2(target, "RunControl", "contextRemoved", event_context_removed, p); +#endif +} + +void context_lock(Context * ctx) { + assert(ctx->ref_count > 0); + ctx->ref_count++; +} + +void context_unlock(Context * ctx) { + assert(ctx->ref_count > 0); + if (--ctx->ref_count == 0) { + ContextCache * c = ctx->proxy; + assert(list_is_empty(&ctx->children)); + assert(ctx->parent == NULL); + assert(c->pending_get_map == NULL); + assert(c->pending_get_regs == NULL); + list_remove(&ctx->ctxl); + list_remove(&ctx->pidl); + release_error_report(ctx->regs_error); + loc_free(ctx->bp_ids); + loc_free(ctx->regs); + loc_free(ctx); + loc_free(c->mem_regions); + loc_free(c->reg_ids); + loc_free(c->reg_ids_str); + loc_free(c->reg_defs); + while (!list_is_empty(&c->mem_cache)) { + MemoryCache * m = mems2mem(c->mem_cache.next); + list_remove(&m->link); + if (m->pending_command != NULL) { + m->canceled = 1; + } + else { + loc_free(m->buf); + loc_free(m); + } + } + loc_free(c); + } +} + +Context * id2ctx(char * id) { + return NULL; +} + int context_has_state(Context * ctx) { - return 0; + ContextCache * cache = (ContextCache *)ctx->proxy; + if (!validate_context_cache(cache->peer->target, cache, 0)) cache_wait(&cache->cache); + return cache->has_state; +} + +static void validate_memory_cache(Channel * c, void * args, int error) { + MemoryCache * m = (MemoryCache *)args; + m->error = get_error_report(error); + if (!error) { + size_t pos = 0; + JsonReadBinaryState state; + json_read_binary_start(&state, &c->inp); + for (;;) { + int rd = json_read_binary_data(&state, (int8_t *)m->buf + pos, m->size - pos); + if (rd == 0) break; + pos += rd; + } + json_read_binary_end(&state); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + m->error = get_error_report(read_errno(&c->inp)); + + + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + } } int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { @@ -44,11 +328,96 @@ int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t } int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - errno = EINVAL; + ContextCache * cache = (ContextCache *)ctx->proxy; + Channel * c = cache->peer->target; + MemoryCache * m = NULL; + LINK * l = NULL; + + for (l = cache->mem_cache.next; l != &cache->mem_cache; l = l->next) { + m = mems2mem(l); + if (address >= m->addr && address + size <= m->addr + m->size) { + if (m->pending_command != NULL) cache_wait(&m->cache); + memcpy(buf, (int8_t *)m->buf + (address - m->addr), size); + errno = set_error_report_errno(m->error); + return !errno ? 0 : -1; + } + } + + m = loc_alloc_zero(sizeof(MemoryCache)); + m->addr = address; + m->buf = loc_alloc(size); + m->size = size; + m->pending_command = protocol_send_command(c, "Memory", "get", validate_memory_cache, m); + write_stringz(&c->out, container_id(cache->ctx)); + json_write_int64(&c->out, m->addr); + write_stream(&c->out, 0); + json_write_long(&c->out, 1); + write_stream(&c->out, 0); + json_write_long(&c->out, m->size); + write_stream(&c->out, 0); + json_write_long(&c->out, 0); + write_stream(&c->out, 0); + write_stream(&c->out, MARKER_EOM); + flush_stream(&c->out); + cache_wait(&m->cache); return -1; } +void memory_map_get_regions(Context * ctx, MemoryRegion ** regions, unsigned * cnt) { + ContextCache * cache = (ContextCache *)ctx->proxy; + if (!validate_context_cache(cache->peer->target, cache, 0)) cache_wait(&cache->cache); + *regions = cache->mem_regions; + *cnt = cache->mem_regions_cnt; +} + +RegisterDefinition * get_reg_definitions(Context * ctx) { + ContextCache * cache = (ContextCache *)ctx->proxy; + if (!validate_context_cache(cache->peer->target, cache, 0)) cache_wait(&cache->cache); + return cache->reg_defs; +} + +RegisterDefinition * get_PC_definition(Context * ctx) { + ContextCache * cache = (ContextCache *)ctx->proxy; + if (!validate_context_cache(cache->peer->target, cache, 0)) cache_wait(&cache->cache); + return cache->pc_def; +} + +RegisterDefinition * get_reg_by_id(Context * ctx, unsigned id, unsigned munbering_convention) { + RegisterDefinition * defs; + ContextCache * cache = (ContextCache *)ctx->proxy; + if (!validate_context_cache(cache->peer->target, cache, 0)) cache_wait(&cache->cache); + defs = cache->reg_defs; + while (defs != NULL && defs->name != NULL) { + switch (munbering_convention) { + case REGNUM_DWARF: + if (defs->dwarf_id == id) return defs; + break; + case REGNUM_EH_FRAME: + if (defs->eh_frame_id == id) return defs; + break; + } + defs++; + } + return NULL; +} + +static void channel_close_listener(Channel * c) { + LINK * l = NULL; + + for (l = peers.next; l != &peers; l = l->next) { + PeerCache * p = peers2peer(l); + if (p->target == c) { + channel_unlock(p->host); + list_remove(&p->link_all); + loc_free(p); + return; + } + } +} + void init_contexts_sys_dep(void) { + list_init(&peers); + add_channel_close_listener(channel_close_listener); } #endif /* ENABLE_DebugContext && ENABLE_ContextProxy */ diff --git a/server/services/context-proxy.h b/server/services/context-proxy.h new file mode 100644 index 00000000..3217654e --- /dev/null +++ b/server/services/context-proxy.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007, 2009 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. + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +/* + * This module forwards handling of process/thread OS contexts to remote peer. + */ + +#ifndef D_context_proxy +#define D_context_proxy + +#include "channel.h" + +extern void create_context_proxy(Channel * host, Channel * target); + +#endif /* D_context_proxy */ + |