diff options
author | eutarass | 2010-03-25 23:10:17 +0000 |
---|---|---|
committer | eutarass | 2010-03-25 23:10:17 +0000 |
commit | 695424c6ae0a60fb9d2f2699aba7613b78ff5fa5 (patch) | |
tree | 6d21972456d8131828fcfcfadfbd47e8144f3645 | |
parent | a5939b6712a8c7e013f191c35af1b8dbc60143be (diff) | |
download | org.eclipse.tcf.agent-695424c6ae0a60fb9d2f2699aba7613b78ff5fa5.tar.gz org.eclipse.tcf.agent-695424c6ae0a60fb9d2f2699aba7613b78ff5fa5.tar.xz org.eclipse.tcf.agent-695424c6ae0a60fb9d2f2699aba7613b78ff5fa5.zip |
TCF Agent: added JSON functions to read/write uint64_t numbers
-rw-r--r-- | framework/context.c | 2 | ||||
-rw-r--r-- | framework/errors.c | 110 | ||||
-rw-r--r-- | framework/events.c | 2 | ||||
-rw-r--r-- | framework/json.c | 39 | ||||
-rw-r--r-- | framework/json.h | 2 | ||||
-rw-r--r-- | framework/mdep.c | 5 | ||||
-rw-r--r-- | framework/mdep.h | 1 | ||||
-rw-r--r-- | main/main.c | 3 | ||||
-rw-r--r-- | main/main_client.c | 2 | ||||
-rw-r--r-- | main/main_log.c | 2 | ||||
-rw-r--r-- | main/main_lua.c | 2 | ||||
-rw-r--r-- | main/main_reg.c | 2 | ||||
-rw-r--r-- | main/main_va.c | 2 | ||||
-rw-r--r-- | server/config.h | 8 | ||||
-rw-r--r-- | server/main/main.c | 2 | ||||
-rw-r--r-- | server/services/context-proxy.c | 42 | ||||
-rw-r--r-- | services/diagnostics.c | 2 | ||||
-rw-r--r-- | services/expressions.c | 7 | ||||
-rw-r--r-- | services/filesystem.c | 24 | ||||
-rw-r--r-- | services/linenumbers.c | 8 | ||||
-rw-r--r-- | services/linenumbers_proxy.c | 4 | ||||
-rw-r--r-- | services/memorymap.c | 2 | ||||
-rw-r--r-- | services/stacktrace.c | 14 | ||||
-rw-r--r-- | services/symbols.c | 16 | ||||
-rw-r--r-- | services/symbols.h | 2 | ||||
-rw-r--r-- | services/symbols_elf.c | 4 | ||||
-rw-r--r-- | services/symbols_proxy.c | 141 | ||||
-rw-r--r-- | services/symbols_win32.c | 3 | ||||
-rw-r--r-- | services/sysmon.c | 14 |
29 files changed, 304 insertions, 163 deletions
diff --git a/framework/context.c b/framework/context.c index 544140b2..a1c31551 100644 --- a/framework/context.c +++ b/framework/context.c @@ -257,10 +257,10 @@ void send_context_exited_event(Context * ctx) { assert(!ctx->event_notification); #if !ENABLE_ContextProxy ctx->exiting = 0; + ctx->pending_intercept = 0; #endif ctx->exited = 1; ctx->event_notification = 1; - ctx->pending_intercept = 0; while (listener != NULL) { if (listener->context_exited != NULL) { listener->context_exited(ctx, listener->client_data); diff --git a/framework/errors.c b/framework/errors.c index 3b0b9443..da28fa1d 100644 --- a/framework/errors.c +++ b/framework/errors.c @@ -29,7 +29,7 @@ #include "trace.h" #define ERR_MESSAGE_MIN (STD_ERR_BASE + 100) -#define ERR_MESSAGE_MAX (STD_ERR_BASE + 149) +#define ERR_MESSAGE_MAX (STD_ERR_BASE + 199) #define MESSAGE_CNT (ERR_MESSAGE_MAX - ERR_MESSAGE_MIN + 1) @@ -108,6 +108,22 @@ static char * system_strerror(DWORD errno_win32) { return msg; } +typedef struct EventArgs { + HANDLE done; + int win32_code; + int error_code; +} EventArgs; + +static void set_win32_errno_event(void * args) { + ErrorMessage * m = NULL; + EventArgs * e = (EventArgs *)args; + + m = alloc_msg(SRC_SYSTEM); + m->error = e->win32_code; + e->error_code = errno; + SetEvent(e->done); +} + int set_win32_errno(DWORD win32_error_code) { if (win32_error_code) { if (is_dispatch_thread()) { @@ -115,8 +131,17 @@ int set_win32_errno(DWORD win32_error_code) { m->error = win32_error_code; } else { - /* TODO: set_win32_errno() needs to be thread safe */ - errno = ERR_OTHER; + /* Called on background thread */ + int error = 0; + EventArgs * e = (EventArgs *)loc_alloc_zero(sizeof(EventArgs)); + e->done = CreateEvent(NULL, TRUE, FALSE, NULL); + e->win32_code = win32_error_code; + post_event(set_win32_errno_event, e); + WaitForSingleObject(e->done, INFINITE); + CloseHandle(e->done); + error = e->error_code; + loc_free(e); + errno = error; } } else { @@ -129,58 +154,32 @@ int set_win32_errno(DWORD win32_error_code) { const char * errno_to_str(int err) { switch (err) { - case ERR_ALREADY_STOPPED: - return "Already stopped"; - case ERR_ALREADY_EXITED: - return "Already exited"; - case ERR_ALREADY_RUNNING: - return "Already running"; - case ERR_JSON_SYNTAX: - return "JSON syntax error"; - case ERR_PROTOCOL: - return "Protocol format error"; - case ERR_INV_CONTEXT: - return "Invalid context ID"; - case ERR_INV_ADDRESS: - return "Invalid address"; - case ERR_EOF: - return "End of file"; - case ERR_BASE64: - return "Invalid BASE64 string"; - case ERR_INV_EXPRESSION: - return "Invalid expression"; - case ERR_SYM_NOT_FOUND: - return "Symbol not found"; - case ERR_ALREADY_ATTACHED: - return "Already attached"; - case ERR_BUFFER_OVERFLOW: - return "Buffer overflow"; - case ERR_INV_FORMAT: - return "Format is not supported"; - case ERR_INV_NUMBER: - return "Invalid number"; - case ERR_IS_RUNNING: - return "Execution context is running"; - case ERR_INV_DWARF: - return "Error reading DWARF data"; - case ERR_UNSUPPORTED: - return "Unsupported command"; - case ERR_CHANNEL_CLOSED: - return "Channel closed"; - case ERR_COMMAND_CANCELLED: - return "Command cancelled"; - case ERR_UNKNOWN_PEER: - return "Unknown peer ID"; - case ERR_INV_DATA_SIZE: - return "Invalid data size"; - case ERR_INV_DATA_TYPE: - return "Invalid data type"; - case ERR_INV_COMMAND: - return "Command is not recognized"; - case ERR_INV_TRANSPORT: - return "Invalid transport name"; - case ERR_CACHE_MISS: - return "Invalid data cache state"; + case ERR_ALREADY_STOPPED: return "Already stopped"; + case ERR_ALREADY_EXITED: return "Already exited"; + case ERR_ALREADY_RUNNING: return "Already running"; + case ERR_JSON_SYNTAX: return "JSON syntax error"; + case ERR_PROTOCOL: return "Protocol format error"; + case ERR_INV_CONTEXT: return "Invalid context ID"; + case ERR_INV_ADDRESS: return "Invalid address"; + case ERR_EOF: return "End of file"; + case ERR_BASE64: return "Invalid BASE64 string"; + case ERR_INV_EXPRESSION: return "Invalid expression"; + case ERR_SYM_NOT_FOUND: return "Symbol not found"; + case ERR_ALREADY_ATTACHED: return "Already attached"; + case ERR_BUFFER_OVERFLOW: return "Buffer overflow"; + case ERR_INV_FORMAT: return "Format is not supported"; + case ERR_INV_NUMBER: return "Invalid number"; + case ERR_IS_RUNNING: return "Execution context is running"; + case ERR_INV_DWARF: return "Error reading DWARF data"; + case ERR_UNSUPPORTED: return "Unsupported command"; + case ERR_CHANNEL_CLOSED: return "Channel closed"; + case ERR_COMMAND_CANCELLED: return "Command cancelled"; + case ERR_UNKNOWN_PEER: return "Unknown peer ID"; + case ERR_INV_DATA_SIZE: return "Invalid data size"; + case ERR_INV_DATA_TYPE: return "Invalid data type"; + case ERR_INV_COMMAND: return "Command is not recognized"; + case ERR_INV_TRANSPORT: return "Invalid transport name"; + case ERR_CACHE_MISS: return "Invalid data cache state"; default: if (err >= ERR_MESSAGE_MIN && err <= ERR_MESSAGE_MAX) { ErrorMessage * m = msgs + (err - ERR_MESSAGE_MIN); @@ -357,6 +356,7 @@ ErrorReport * create_error_report(void) { void release_error_report(ErrorReport * r) { if (r != NULL) { ReportBuffer * report = (ReportBuffer *)((char *)r - offsetof(ReportBuffer, pub)); + assert(is_dispatch_thread()); assert(report->gets > 0); report->gets--; release_report(report); diff --git a/framework/events.c b/framework/events.c index 605b7891..5f3e6c4f 100644 --- a/framework/events.c +++ b/framework/events.c @@ -231,7 +231,7 @@ int cancel_event(EventCallBack * handler, void *arg, int wait) { } int is_dispatch_thread(void) { - return event_thread == pthread_self(); + return pthread_equal(event_thread, pthread_self()); } void ini_events_queue(void) { diff --git a/framework/json.c b/framework/json.c index 5f5c15fa..7e71ab3b 100644 --- a/framework/json.c +++ b/framework/json.c @@ -65,17 +65,20 @@ void json_write_long(OutputStream * out, long n) { json_write_ulong(out, (unsigned long)n); } +void json_write_uint64(OutputStream * out, uint64_t n) { + if (n >= 10) { + json_write_uint64(out, n / 10); + n = n % 10; + } + write_stream(out, (int)n + '0'); +} + void json_write_int64(OutputStream * out, int64_t n) { if (n < 0) { write_stream(out, '-'); n = -n; - if (n < 0) exception(EINVAL); - } - if (n >= 10) { - json_write_int64(out, n / 10); - n = n % 10; } - write_stream(out, (int)n + '0'); + json_write_uint64(out, (uint64_t)n); } void json_write_double(OutputStream * out, double n) { @@ -295,6 +298,26 @@ int64_t json_read_int64(InputStream * inp) { return res; } +uint64_t json_read_uint64(InputStream * inp) { + uint64_t res = 0; + int neg = 0; + int ch = read_stream(inp); + if (ch == '-') { + neg = 1; + ch = read_stream(inp); + } + if (ch < '0' || ch > '9') exception(ERR_JSON_SYNTAX); + res = ch - '0'; + for (;;) { + ch = peek_stream(inp); + if (ch < '0' || ch > '9') break; + read_stream(inp); + res = res * 10 + (ch - '0'); + } + if (neg) return ~res + 1; + return res; +} + double json_read_double(InputStream * inp) { char buf[256]; int pos = 0; @@ -830,7 +853,7 @@ int read_errno(InputStream * inp) { err->code = json_read_long(inp); } else if (strcmp(name, "Time") == 0) { - err->time_stamp = json_read_int64(inp); + err->time_stamp = json_read_uint64(inp); } else if (strcmp(name, "Format") == 0) { err->format = json_read_alloc_string(inp); @@ -862,7 +885,7 @@ static void write_error_props(OutputStream * out, ErrorReport * rep) { write_stream(out, ','); json_write_string(out, "Time"); write_stream(out, ':'); - json_write_int64(out, rep->time_stamp); + json_write_uint64(out, rep->time_stamp); } if (rep->format != NULL) { diff --git a/framework/json.h b/framework/json.h index 37e74a9b..9af81e09 100644 --- a/framework/json.h +++ b/framework/json.h @@ -33,6 +33,7 @@ extern int json_read_boolean(InputStream * inp); extern long json_read_long(InputStream * inp); extern unsigned long json_read_ulong(InputStream * inp); extern int64_t json_read_int64(InputStream * inp); +extern uint64_t json_read_uint64(InputStream * inp); extern double json_read_double(InputStream * inp); extern char * json_read_alloc_string(InputStream * inp); extern char ** json_read_alloc_string_array(InputStream * inp, int * len); @@ -52,6 +53,7 @@ extern void json_skip_object(InputStream * inp); extern void json_write_ulong(OutputStream * out, unsigned long n); extern void json_write_long(OutputStream * out, long n); +extern void json_write_uint64(OutputStream * out, uint64_t n); extern void json_write_int64(OutputStream * out, int64_t n); extern void json_write_double(OutputStream * out, double n); extern void json_write_char(OutputStream * out, char ch); diff --git a/framework/mdep.c b/framework/mdep.c index 93ffc017..04ba3da8 100644 --- a/framework/mdep.c +++ b/framework/mdep.c @@ -298,7 +298,12 @@ pthread_t pthread_self(void) { return (pthread_t)GetCurrentThreadId(); } +int pthread_equal(pthread_t thread1, pthread_t thread2) { + return thread1 == thread2; +} + int pthread_attr_init(pthread_attr_t * attr) { + *attr = NULL; return 0; } diff --git a/framework/mdep.h b/framework/mdep.h index 3e6e39e0..12810deb 100644 --- a/framework/mdep.h +++ b/framework/mdep.h @@ -233,6 +233,7 @@ extern pthread_t pthread_self(void); extern int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void * arg); extern int pthread_join(pthread_t thread, void **value_ptr); +extern int pthread_equal(pthread_t thread1, pthread_t thread2); /* * Windows socket functions don't set errno as expected. diff --git a/main/main.c b/main/main.c index d22cc6c6..301d0914 100644 --- a/main/main.c +++ b/main/main.c @@ -58,6 +58,7 @@ int main(int argc, char ** argv) { ini_mdep(); ini_trace(); + ini_events_queue(); ini_asyncreq(); #if defined(_WRS_KERNEL) @@ -141,8 +142,6 @@ int main(int argc, char ** argv) { #endif - ini_events_queue(); - bcg = broadcast_group_alloc(); proto = protocol_alloc(); diff --git a/main/main_client.c b/main/main_client.c index 25fbfed0..130b8344 100644 --- a/main/main_client.c +++ b/main/main_client.c @@ -61,8 +61,8 @@ int main(int argc, char ** argv) { ini_mdep(); ini_trace(); - ini_asyncreq(); ini_events_queue(); + ini_asyncreq(); #if defined(_WRS_KERNEL) diff --git a/main/main_log.c b/main/main_log.c index 0a104bba..883d1aeb 100644 --- a/main/main_log.c +++ b/main/main_log.c @@ -130,8 +130,8 @@ int main(int argc, char ** argv) { ini_mdep(); ini_trace(); - ini_asyncreq(); ini_events_queue(); + ini_asyncreq(); log_mode = LOG_TCFLOG; diff --git a/main/main_lua.c b/main/main_lua.c index 07bf56cb..75ab4ee2 100644 --- a/main/main_lua.c +++ b/main/main_lua.c @@ -1465,8 +1465,8 @@ int main(int argc, char ** argv) { #endif ini_mdep(); ini_trace(); - ini_asyncreq(); ini_events_queue(); + ini_asyncreq(); #if defined(_WRS_KERNEL) diff --git a/main/main_reg.c b/main/main_reg.c index e4f9c27b..e77823c4 100644 --- a/main/main_reg.c +++ b/main/main_reg.c @@ -45,8 +45,8 @@ int main(int argc, char **argv) { ini_mdep(); ini_trace(); - ini_asyncreq(); ini_events_queue(); + ini_asyncreq(); #if defined(_WRS_KERNEL) diff --git a/main/main_va.c b/main/main_va.c index 5faee789..abae2ec4 100644 --- a/main/main_va.c +++ b/main/main_va.c @@ -64,8 +64,8 @@ int main(int argc, char ** argv) { ini_mdep(); ini_trace(); - ini_asyncreq(); ini_events_queue(); + ini_asyncreq(); #if defined(_WRS_KERNEL) diff --git a/server/config.h b/server/config.h index c6af3b0a..c95dc983 100644 --- a/server/config.h +++ b/server/config.h @@ -40,14 +40,6 @@ #define ENABLE_ZeroCopy 1 #endif -#if !defined(ENABLE_Splice) -# if (ENABLE_ZeroCopy) && defined(SPLICE_F_MOVE) -# define ENABLE_Splice 1 -# else -# define ENABLE_Splice 0 -# endif -#endif - #if !defined(ENABLE_Trace) # define ENABLE_Trace 1 #endif diff --git a/server/main/main.c b/server/main/main.c index c39da172..60aa16bb 100644 --- a/server/main/main.c +++ b/server/main/main.c @@ -82,8 +82,8 @@ int main(int argc, char ** argv) { ini_mdep(); ini_trace(); - ini_asyncreq(); ini_events_queue(); + ini_asyncreq(); #if defined(_WRS_KERNEL) diff --git a/server/services/context-proxy.c b/server/services/context-proxy.c index 562019eb..95afdb5a 100644 --- a/server/services/context-proxy.c +++ b/server/services/context-proxy.c @@ -80,7 +80,7 @@ struct ContextCache { /* Run Control State */ int pc_valid; - int64_t suspend_pc; + uint64_t suspend_pc; char suspend_reason[256]; /* Memory */ @@ -433,31 +433,29 @@ static void event_context_removed(Channel * c, void * args) { static void event_context_suspended(Channel * ch, void * args) { PeerCache * p = (PeerCache *)args; ContextCache * c = NULL; - char id[256]; - char reason[sizeof(c->suspend_reason)]; - int64_t pc; ContextCache buf; assert(p->target == ch); + memset(&buf, 0, sizeof(buf)); write_stringz(&p->host->out, "E"); write_stringz(&p->host->out, RUN_CONTROL); write_stringz(&p->host->out, "contextSuspended"); - json_read_string(p->fwd_inp, id, sizeof(id)); + json_read_string(p->fwd_inp, buf.id, sizeof(buf.id)); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); - pc = json_read_int64(p->fwd_inp); + buf.suspend_pc = json_read_uint64(p->fwd_inp); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); - json_read_string(p->fwd_inp, reason, sizeof(reason)); + json_read_string(p->fwd_inp, buf.suspend_reason, sizeof(buf.suspend_reason)); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); json_read_struct(p->fwd_inp, read_context_suspended_data, &buf); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(p->fwd_inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); - c = find_context_cache(p, id); + c = find_context_cache(p, buf.id); if (c != NULL) { assert(c->ctx->proxy == c); c->pc_valid = 1; - c->suspend_pc = pc; - strcpy(c->suspend_reason, reason); + c->suspend_pc = buf.suspend_pc; + strcpy(c->suspend_reason, buf.suspend_reason); if (!c->ctx->stopped) { c->ctx->stopped = 1; c->ctx->intercepted = 1; @@ -466,7 +464,7 @@ static void event_context_suspended(Channel * ch, void * args) { } } else if (p->rc_done) { - trace(LOG_ALWAYS, "Invalid ID in 'context suspended' event: %s", id); + trace(LOG_ALWAYS, "Invalid ID in 'context suspended' event: %s", buf.id); } } @@ -500,21 +498,21 @@ static void event_context_resumed(Channel * ch, void * args) { static void event_container_suspended(Channel * c, void * args) { PeerCache * p = (PeerCache *)args; - char id[256]; - char reason[256]; - int64_t pc; ContextCache ctx; + + memset(&ctx, 0, sizeof(ctx)); write_stringz(&p->host->out, "E"); write_stringz(&p->host->out, RUN_CONTROL); write_stringz(&p->host->out, "containerSuspended"); - json_read_string(p->fwd_inp, id, sizeof(id)); + json_read_string(p->fwd_inp, ctx.id, sizeof(ctx.id)); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); - pc = json_read_int64(p->fwd_inp); + ctx.suspend_pc = json_read_uint64(p->fwd_inp); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); - json_read_string(p->fwd_inp, reason, sizeof(reason)); + json_read_string(p->fwd_inp, ctx.suspend_reason, sizeof(ctx.suspend_reason)); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); json_read_struct(p->fwd_inp, read_context_suspended_data, &ctx); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); + /* TODO: save suspend data in the cache */ json_read_array(p->fwd_inp, read_container_suspended_item, p); if (read_stream(p->fwd_inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(p->fwd_inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); @@ -681,7 +679,7 @@ static void validate_peer_cache_state(Channel * c, void * args, int error) { set_rc_error(p, error = read_errno(&c->inp)); x->pc_valid = json_read_boolean(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); - x->suspend_pc = json_read_int64(&c->inp); + x->suspend_pc = json_read_uint64(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); json_read_string(&c->inp, x->suspend_reason, sizeof(x->suspend_reason)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); @@ -823,7 +821,7 @@ int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t s static void read_memory_region_property(InputStream * inp, const char * name, void * args) { MemoryRegion * m = (MemoryRegion *)args; - if (strcmp(name, "Addr") == 0) m->addr = (ContextAddress)json_read_int64(inp); + if (strcmp(name, "Addr") == 0) m->addr = (ContextAddress)json_read_uint64(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); @@ -1161,9 +1159,9 @@ static void validate_reg_children_cache(Channel * c, void * args, int error) { static void read_stack_frame_property(InputStream * inp, const char * name, void * args) { StackFrameCache * s = (StackFrameCache *)args; - if (strcmp(name, "FP") == 0) s->info.fp = json_read_int64(inp); - else if (strcmp(name, "IP") == 0) s->ip = json_read_int64(inp); - else if (strcmp(name, "RP") == 0) s->rp = json_read_int64(inp); + if (strcmp(name, "FP") == 0) s->info.fp = (ContextAddress)json_read_uint64(inp); + else if (strcmp(name, "IP") == 0) s->ip = (ContextAddress)json_read_uint64(inp); + else if (strcmp(name, "RP") == 0) s->rp = (ContextAddress)json_read_uint64(inp); else if (strcmp(name, "TopFrame") == 0) s->info.is_top_frame = json_read_boolean(inp); else json_skip_object(inp); } diff --git a/services/diagnostics.c b/services/diagnostics.c index d2b3b918..09794aab 100644 --- a/services/diagnostics.c +++ b/services/diagnostics.c @@ -202,7 +202,7 @@ static void get_symbol_cache_client(void * x) { write_stream(&c->out, ','); json_write_string(&c->out, "Value"); write_stream(&c->out, ':'); - json_write_int64(&c->out, addr); + json_write_uint64(&c->out, addr); write_stream(&c->out, '}'); write_stream(&c->out, 0); } diff --git a/services/expressions.c b/services/expressions.c index c3353004..c7abf969 100644 --- a/services/expressions.c +++ b/services/expressions.c @@ -992,6 +992,7 @@ static void op_field(int mode, Value * v) { static void op_index(int mode, Value * v) { #if ENABLE_Symbols Value i; + int64_t lower_bound = 0; ContextAddress offs = 0; ContextAddress size = 0; Symbol * type = NULL; @@ -1014,10 +1015,10 @@ static void op_index(int mode, Value * v) { if (get_symbol_size(type, &size) < 0) { error(errno, "Cannot get array element type"); } - if (get_symbol_lower_bound(v->type, &offs) < 0) { + if (get_symbol_lower_bound(v->type, &lower_bound) < 0) { error(errno, "Cannot get array lower bound"); } - offs = ((ContextAddress)to_uns(mode, &i) - offs) * size; + offs = (ContextAddress)(to_int(mode, &i) - lower_bound) * size; if (v->type_class == TYPE_CLASS_ARRAY && offs + size > v->size) { error(ERR_INV_EXPRESSION, "Invalid index"); } @@ -2072,11 +2073,11 @@ static void get_children_callback(void * x, Symbol * symbol) { static void get_children_cache_client(void * x) { CommandArgs * args = (CommandArgs *)x; Channel * c = cache_channel(); - char parent_id[256]; int err = 0; /* TODO: Expressions.getChildren - structures */ #if ENABLE_Symbols + char parent_id[256]; { Context * ctx; int frame = STACK_NO_FRAME; diff --git a/services/filesystem.c b/services/filesystem.c index db0ebc66..b33059a5 100644 --- a/services/filesystem.c +++ b/services/filesystem.c @@ -81,8 +81,8 @@ struct FileAttrs { int uid; int gid; int permissions; - int64_t atime; - int64_t mtime; + uint64_t atime; + uint64_t mtime; }; struct OpenFileInfo { @@ -250,8 +250,8 @@ static void fill_attrs(FileAttrs * attrs, struct stat * buf) { attrs->uid = buf->st_uid; attrs->gid = buf->st_gid; attrs->permissions = buf->st_mode; - attrs->atime = (int64_t)buf->st_atime * 1000; - attrs->mtime = (int64_t)buf->st_mtime * 1000; + attrs->atime = (uint64_t)buf->st_atime * 1000; + attrs->mtime = (uint64_t)buf->st_mtime * 1000; } static void read_file_attrs(InputStream * inp, const char * nm, void * arg) { @@ -273,11 +273,11 @@ static void read_file_attrs(InputStream * inp, const char * nm, void * arg) { attrs->flags |= ATTR_PERMISSIONS; } else if (strcmp(nm, "ATime") == 0) { - attrs->atime = json_read_int64(inp); + attrs->atime = json_read_uint64(inp); attrs->flags |= ATTR_ACMODTIME; } else if (strcmp(nm, "MTime") == 0) { - attrs->mtime = json_read_int64(inp); + attrs->mtime = json_read_uint64(inp); attrs->flags |= ATTR_ACMODTIME; } else { @@ -322,11 +322,11 @@ static void write_file_attrs(OutputStream * out, FileAttrs * attrs) { if (cnt) write_stream(out, ','); json_write_string(out, "ATime"); write_stream(out, ':'); - json_write_int64(out, attrs->atime); + json_write_uint64(out, attrs->atime); write_stream(out, ','); json_write_string(out, "MTime"); write_stream(out, ':'); - json_write_int64(out, attrs->mtime); + json_write_uint64(out, attrs->mtime); cnt++; } write_stream(out, '}'); @@ -581,8 +581,8 @@ static void post_io_requst(OpenFileInfo * handle) { #endif if (attrs.flags & ATTR_ACMODTIME) { struct utimbuf buf; - buf.actime = (long)(attrs.atime / 1000); - buf.modtime = (long)(attrs.mtime / 1000); + buf.actime = (time_t)(attrs.atime / 1000); + buf.modtime = (time_t)(attrs.mtime / 1000); if (utime(handle->path, &buf) < 0) err = errno; } reply_setstat(req->token, handle->out, err); @@ -798,8 +798,8 @@ static void command_setstat(char * token, Channel * c) { } if (attrs.flags & ATTR_ACMODTIME) { struct utimbuf buf; - buf.actime = (long)(attrs.atime / 1000); - buf.modtime = (long)(attrs.mtime / 1000); + buf.actime = (time_t)(attrs.atime / 1000); + buf.modtime = (time_t)(attrs.mtime / 1000); if (utime(path, &buf) < 0) err = errno; } diff --git a/services/linenumbers.c b/services/linenumbers.c index 1390b148..73676ceb 100644 --- a/services/linenumbers.c +++ b/services/linenumbers.c @@ -64,7 +64,7 @@ static void write_line_info(OutputStream * out, int cnt) { write_stream(out, '{'); json_write_string(out, "SAddr"); write_stream(out, ':'); - json_write_int64(out, area->start_address); + json_write_uint64(out, area->start_address); if (area->start_line > 0) { write_stream(out, ','); json_write_string(out, "SLine"); @@ -81,7 +81,7 @@ static void write_line_info(OutputStream * out, int cnt) { write_stream(out, ','); json_write_string(out, "EAddr"); write_stream(out, ':'); - json_write_int64(out, area->end_address); + json_write_uint64(out, area->end_address); } if (area->end_line > 0) { write_stream(out, ','); @@ -190,9 +190,9 @@ static void command_map_to_source(char * token, Channel * c) { json_read_string(&c->inp, args.id, sizeof(args.id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); - args.addr0 = (ContextAddress)json_read_int64(&c->inp); + args.addr0 = (ContextAddress)json_read_uint64(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); - args.addr1 = (ContextAddress)json_read_int64(&c->inp); + args.addr1 = (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); diff --git a/services/linenumbers_proxy.c b/services/linenumbers_proxy.c index 40db42fe..7a501113 100644 --- a/services/linenumbers_proxy.c +++ b/services/linenumbers_proxy.c @@ -142,10 +142,10 @@ static void read_code_area_props(InputStream * inp, const char * name, void * ar CodeArea * area = (CodeArea *)args; if (strcmp(name, "SLine") == 0) area->start_line = json_read_long(inp); else if (strcmp(name, "SCol") == 0) area->start_column = json_read_long(inp); - else if (strcmp(name, "SAddr") == 0) area->start_address = (ContextAddress)json_read_int64(inp); + else if (strcmp(name, "SAddr") == 0) area->start_address = (ContextAddress)json_read_uint64(inp); else if (strcmp(name, "ELine") == 0) area->end_line = json_read_long(inp); else if (strcmp(name, "ECol") == 0) area->end_column = json_read_long(inp); - else if (strcmp(name, "EAddr") == 0) area->end_address = (ContextAddress)json_read_int64(inp); + else if (strcmp(name, "EAddr") == 0) area->end_address = (ContextAddress)json_read_uint64(inp); else if (strcmp(name, "File") == 0) area->file = json_read_alloc_string(inp); else if (strcmp(name, "Dir") == 0) area->directory = json_read_alloc_string(inp); else if (strcmp(name, "ISA") == 0) area->isa = json_read_long(inp); diff --git a/services/memorymap.c b/services/memorymap.c index 63ea2c55..a024107d 100644 --- a/services/memorymap.c +++ b/services/memorymap.c @@ -309,7 +309,7 @@ static void command_get(char * token, Channel * c) { write_stream(&c->out, '{'); json_write_string(&c->out, "Addr"); write_stream(&c->out, ':'); - json_write_int64(&c->out, m->addr); + json_write_uint64(&c->out, m->addr); write_stream(&c->out, ','); json_write_string(&c->out, "Size"); write_stream(&c->out, ':'); diff --git a/services/stacktrace.c b/services/stacktrace.c index f88db64e..c7a0c7e7 100644 --- a/services/stacktrace.c +++ b/services/stacktrace.c @@ -177,6 +177,7 @@ static int trace_stack(Context * ctx) { #endif static StackTrace * create_stack_trace(Context * ctx) { + int error = 0; StackTrace * stack_trace = (StackTrace *)ctx->stack_trace; if (stack_trace != NULL) return stack_trace; @@ -185,10 +186,11 @@ static StackTrace * create_stack_trace(Context * ctx) { ctx->stack_trace = stack_trace; if (ctx->regs_error != NULL) { stack_trace->error = get_error_report(set_error_report_errno(ctx->regs_error)); + return stack_trace; } - else if (trace_stack(ctx) < 0) { - stack_trace->error = get_error_report(errno); - } + if (trace_stack(ctx) < 0) error = errno; + stack_trace = (StackTrace *)ctx->stack_trace; + if (error) stack_trace->error = get_error_report(error); return stack_trace; } @@ -230,21 +232,21 @@ static void write_context(OutputStream * out, char * id, Context * ctx, int leve write_stream(out, ','); json_write_string(out, "FP"); write_stream(out, ':'); - json_write_int64(out, frame->fp); + json_write_uint64(out, frame->fp); } if (read_reg_value(reg_def, frame, &v) == 0) { write_stream(out, ','); json_write_string(out, "IP"); write_stream(out, ':'); - json_write_int64(out, v); + json_write_uint64(out, v); } if (down != NULL && read_reg_value(reg_def, down, &v) == 0) { write_stream(out, ','); json_write_string(out, "RP"); write_stream(out, ':'); - json_write_int64(out, v); + json_write_uint64(out, v); } write_stream(out, '}'); diff --git a/services/symbols.c b/services/symbols.c index fa8b107d..b422f3a9 100644 --- a/services/symbols.c +++ b/services/symbols.c @@ -52,7 +52,7 @@ static void command_get_context_cache_client(void * x) { int has_address = 0; ContextAddress size = 0; ContextAddress length = 0; - ContextAddress lower_bound = 0; + int64_t lower_bound = 0; ContextAddress offset = 0; ContextAddress address = 0; void * value = NULL; @@ -149,14 +149,14 @@ static void command_get_context_cache_client(void * x) { if (has_size) { json_write_string(&c->out, "Size"); write_stream(&c->out, ':'); - json_write_int64(&c->out, size); + 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_int64(&c->out, length); + json_write_uint64(&c->out, length); write_stream(&c->out, ','); if (has_lower_bound) { @@ -167,7 +167,7 @@ static void command_get_context_cache_client(void * x) { json_write_string(&c->out, "UpperBound"); write_stream(&c->out, ':'); - json_write_int64(&c->out, lower_bound + length - 1); + json_write_int64(&c->out, lower_bound + (int64_t)length - 1); write_stream(&c->out, ','); } } @@ -175,14 +175,14 @@ static void command_get_context_cache_client(void * x) { if (has_offset) { json_write_string(&c->out, "Offset"); write_stream(&c->out, ':'); - json_write_int64(&c->out, offset); + 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_int64(&c->out, address); + json_write_uint64(&c->out, address); write_stream(&c->out, ','); } @@ -388,7 +388,7 @@ static void command_list(char * token, Channel * c) { typedef struct CommandGetArrayTypeArgs { char token[256]; char id[256]; - int64_t length; + uint64_t length; } CommandGetArrayTypeArgs; static void command_get_array_type_cache_client(void * x) { @@ -423,7 +423,7 @@ static void command_get_array_type(char * token, Channel * c) { json_read_string(&c->inp, args.id, sizeof(args.id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); - args.length = json_read_int64(&c->inp); + 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); diff --git a/services/symbols.h b/services/symbols.h index 830d0f97..381a6699 100644 --- a/services/symbols.h +++ b/services/symbols.h @@ -124,7 +124,7 @@ extern int get_symbol_index_type(const Symbol * sym, Symbol ** index_type); extern int get_symbol_length(const Symbol * sym, ContextAddress * length); /* Get array index lower bound (index of first element) */ -extern int get_symbol_lower_bound(const Symbol * sym, ContextAddress * value); +extern int get_symbol_lower_bound(const Symbol * sym, int64_t * value); /* Get children type IDs (struct, union, class, function and enum). * The array returned shall not be modified by the client, diff --git a/services/symbols_elf.c b/services/symbols_elf.c index 718857ac..04c67a16 100644 --- a/services/symbols_elf.c +++ b/services/symbols_elf.c @@ -1072,7 +1072,7 @@ int get_symbol_length(const Symbol * sym, ContextAddress * length) { return -1; } -int get_symbol_lower_bound(const Symbol * sym, ContextAddress * value) { +int get_symbol_lower_bound(const Symbol * sym, int64_t * value) { assert(sym->magic == SYMBOL_MAGIC); if (sym->base) { *value = 0; @@ -1098,7 +1098,7 @@ int get_symbol_lower_bound(const Symbol * sym, ContextAddress * value) { if (!set_trap(&trap)) return -1; y = get_num_prop(obj, AT_lower_bound, &x); clear_trap(&trap); - *value = y ? (ContextAddress)x : 0; + *value = y ? (int64_t)x : 0; return 0; } } diff --git a/services/symbols_proxy.c b/services/symbols_proxy.c index a9f64072..fa0e05f4 100644 --- a/services/symbols_proxy.c +++ b/services/symbols_proxy.c @@ -42,6 +42,7 @@ typedef struct SymbolsCache { LINK link_sym[HASH_SIZE]; LINK link_find[HASH_SIZE]; LINK link_list[HASH_SIZE]; + LINK link_frame[HASH_SIZE]; } SymbolsCache; /* Symbol properties cache */ @@ -69,8 +70,8 @@ typedef struct SymInfoCache { ContextAddress size; ContextAddress offset; ContextAddress length; - ContextAddress lower_bound; - ContextAddress upper_bound; + int64_t lower_bound; + int64_t upper_bound; char * value; int value_size; char ** children_ids; @@ -123,6 +124,18 @@ typedef struct ListSymCache { int disposed; } ListSymCache; +typedef struct StackFrameCache { + LINK link_syms; + AbstractCache cache; + ReplyHandlerInfo * pending; + ErrorReport * error; + pid_t mem; + uint64_t address; + uint64_t size; + + int disposed; +} StackFrameCache; + #define SYM_CACHE_MAGIC 0x38254865 #define root2syms(A) ((SymbolsCache *)((char *)(A) - offsetof(SymbolsCache, link_root))) @@ -130,6 +143,7 @@ typedef struct ListSymCache { #define syms2find(A) ((FindSymCache *)((char *)(A) - offsetof(FindSymCache, link_syms))) #define syms2list(A) ((ListSymCache *)((char *)(A) - offsetof(ListSymCache, link_syms))) #define sym2arr(A) ((ArraySymCache *)((char *)(A) - offsetof(ArraySymCache, link_sym))) +#define syms2frame(A)((StackFrameCache *)((char *)(A) - offsetof(StackFrameCache, link_syms))) struct Symbol { unsigned magic; @@ -160,6 +174,10 @@ static unsigned hash_list(uint64_t ip, pid_t pid) { return ((unsigned)ip + (unsigned)pid) % HASH_SIZE; } +static unsigned hash_frame(pid_t pid) { + return (unsigned)pid % HASH_SIZE; +} + static SymbolsCache * get_symbols_cache(void) { LINK * l = NULL; SymbolsCache * syms = NULL; @@ -248,6 +266,16 @@ static void free_list_sym_cache(ListSymCache * c) { } } +static void free_stack_frame_cache(StackFrameCache * c) { + list_remove(&c->link_syms); + c->disposed = 1; + if (c->pending == NULL) { + cache_dispose(&c->cache); + release_error_report(c->error); + loc_free(c); + } +} + static void free_symbols_cache(SymbolsCache * syms) { int i; for (i = 0; i < HASH_SIZE; i++) { @@ -260,6 +288,9 @@ static void free_symbols_cache(SymbolsCache * syms) { while (!list_is_empty(syms->link_list + i)) { free_list_sym_cache(syms2list(syms->link_list[i].next)); } + while (!list_is_empty(syms->link_frame + i)) { + free_stack_frame_cache(syms2frame(syms->link_frame[i].next)); + } } channel_unlock(syms->channel); list_remove(&syms->link_root); @@ -280,10 +311,10 @@ static void read_context_data(InputStream * inp, const char * name, void * args) else if (strcmp(name, "IndexTypeID") == 0) s->index_type_id = json_read_alloc_string(inp); else if (strcmp(name, "Size") == 0) { s->size = json_read_long(inp); s->has_size = 1; } else if (strcmp(name, "Length") == 0) { s->length = json_read_long(inp); s->has_length = 1; } - else if (strcmp(name, "LowerBound") == 0) { s->lower_bound = json_read_long(inp); s->has_lower_bound = 1; } - else if (strcmp(name, "UpperBound") == 0) { s->upper_bound = json_read_long(inp); s->has_upper_bound = 1; } + else if (strcmp(name, "LowerBound") == 0) { s->lower_bound = json_read_int64(inp); s->has_lower_bound = 1; } + else if (strcmp(name, "UpperBound") == 0) { s->upper_bound = json_read_int64(inp); s->has_upper_bound = 1; } else if (strcmp(name, "Offset") == 0) { s->offset = json_read_long(inp); s->has_offset = 1; } - else if (strcmp(name, "Address") == 0) { s->address = (ContextAddress)json_read_int64(inp); s->has_address = 1; } + else if (strcmp(name, "Address") == 0) { s->address = (ContextAddress)json_read_uint64(inp); s->has_address = 1; } else if (strcmp(name, "Value") == 0) s->value = json_read_alloc_binary(inp, &s->value_size); else json_skip_object(inp); } @@ -628,15 +659,19 @@ int get_symbol_size(const Symbol * sym, ContextAddress * size) { int get_symbol_length(const Symbol * sym, ContextAddress * length) { SymInfoCache * c = get_sym_info_cache(sym); if (c == NULL) return -1; - if (!c->has_length) { - errno = ERR_INV_CONTEXT; - return -1; + if (c->has_length) { + *length = c->length; + return 0; } - *length = c->length; - return 0; + if (c->has_lower_bound && c->has_upper_bound) { + *length = (ContextAddress)(c->has_upper_bound - c->has_lower_bound + 1); + return 0; + } + errno = ERR_INV_CONTEXT; + return -1; } -int get_symbol_lower_bound(const Symbol * sym, ContextAddress * lower_bound) { +int get_symbol_lower_bound(const Symbol * sym, int64_t * lower_bound) { SymInfoCache * c = get_sym_info_cache(sym); if (c == NULL) return -1; if (!c->has_lower_bound) { @@ -794,7 +829,7 @@ int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { a->pending = protocol_send_command(c, "Symbols", "getArrayType", validate_type_id, a); json_write_string(&c->out, s->id); write_stream(&c->out, 0); - json_write_int64(&c->out, length); + json_write_uint64(&c->out, length); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); flush_stream(&c->out); @@ -820,10 +855,92 @@ ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { return 0; } +static void validate_frame(Channel * c, void * args, int error) { + Trap trap; + StackFrameCache * f = (StackFrameCache *)args; + assert(f->pending != NULL); + assert(f->error == NULL); + if (set_trap(&trap)) { + f->pending = NULL; + if (!error) { + error = read_errno(&c->inp); + + + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + } + clear_trap(&trap); + } + else { + error = trap.error; + } + f->error = get_error_report(error); + cache_notify(&f->cache); + if (f->disposed) free_stack_frame_cache(f); +} + int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { + Trap trap; + unsigned h; + LINK * l; + uint64_t ip = 0; + SymbolsCache * syms = NULL; + StackFrameCache * f = NULL; + + if (!set_trap(&trap)) return -1; + + if (read_reg_value(get_PC_definition(ctx), frame, &ip) < 0) { + if (frame->is_top_frame) exception(errno); + clear_trap(&trap); + return 0; + } + + h = hash_frame(ctx->mem); + syms = get_symbols_cache(); + for (l = syms->link_frame[h].next; l != syms->link_frame + h; l = l->next) { + StackFrameCache * c = syms2frame(l); + if (c->mem == ctx->mem) { + if (c->pending != NULL) { + cache_wait(&c->cache); + } + else if (c->address <= ip && c->address + c->size > ip) { + f = c; + break; + } + } + } + + assert(f == NULL || f->pending == NULL); + + if (f == NULL) { + Channel * c = cache_channel(); + if (c == NULL) exception(ERR_SYM_NOT_FOUND); + f = (StackFrameCache *)loc_alloc_zero(sizeof(StackFrameCache)); + list_add_first(&f->link_syms, syms->link_frame + h); + f->mem = ctx->mem; + f->address = ip; + f->size = 1; + f->pending = protocol_send_command(c, "Symbols", "getFrameInfo", validate_frame, f); + json_write_string(&c->out, pid2id(ctx->mem, 0)); + write_stream(&c->out, 0); + json_write_uint64(&c->out, ip); + write_stream(&c->out, 0); + write_stream(&c->out, MARKER_EOM); + flush_stream(&c->out); + cache_wait(&f->cache); + } + else if (f->error != NULL) { + exception(set_error_report_errno(f->error)); + } + else { + } + + clear_trap(&trap); return 0; } +/*************************************************************************************************/ + static void flush_syms(Context * ctx, int mode, int keep_pending) { LINK * l; LINK * m; diff --git a/services/symbols_win32.c b/services/symbols_win32.c index 268175a3..f051ce69 100644 --- a/services/symbols_win32.c +++ b/services/symbols_win32.c @@ -604,7 +604,7 @@ int get_symbol_length(const Symbol * sym, ContextAddress * length) { return 0; } -int get_symbol_lower_bound(const Symbol * sym, ContextAddress * value) { +int get_symbol_lower_bound(const Symbol * sym, int64_t * value) { Symbol type = *sym; DWORD tag = 0; @@ -620,6 +620,7 @@ int get_symbol_lower_bound(const Symbol * sym, ContextAddress * value) { if (get_type_tag(&type, &tag)) return -1; switch (tag) { case SymTagArrayType: + /* TODO: Windows array symbol lower bound value */ *value = 0; return 0; } diff --git a/services/sysmon.c b/services/sysmon.c index 0a6468e7..d6a818c6 100644 --- a/services/sysmon.c +++ b/services/sysmon.c @@ -200,12 +200,12 @@ static void write_context(OutputStream * out, char * id, char * parent_id, kinfo json_write_string(out, "UTime"); write_stream(out, ':'); - json_write_int64(out, p->kp_proc.p_uticks); + json_write_uint64(out, p->kp_proc.p_uticks); write_stream(out, ','); json_write_string(out, "STime"); write_stream(out, ':'); - json_write_int64(out, p->kp_proc.p_sticks); + json_write_uint64(out, p->kp_proc.p_sticks); write_stream(out, ','); json_write_string(out, "Priority"); @@ -1275,22 +1275,22 @@ static void write_context(OutputStream * out, char * id, char * parent_id, char json_write_string(out, "UTime"); write_stream(out, ':'); - json_write_int64(out, (int64_t)utime * 1000 / HZ); + json_write_uint64(out, (uint64_t)utime * 1000 / HZ); write_stream(out, ','); json_write_string(out, "STime"); write_stream(out, ':'); - json_write_int64(out, (int64_t)stime * 1000 / HZ); + json_write_uint64(out, (uint64_t)stime * 1000 / HZ); write_stream(out, ','); json_write_string(out, "CUTime"); write_stream(out, ':'); - json_write_int64(out, (int64_t)cutime * 1000 / HZ); + json_write_uint64(out, (uint64_t)cutime * 1000 / HZ); write_stream(out, ','); json_write_string(out, "CSTime"); write_stream(out, ':'); - json_write_int64(out, (int64_t)cstime * 1000 / HZ); + json_write_uint64(out, (uint64_t)cstime * 1000 / HZ); write_stream(out, ','); json_write_string(out, "Priority"); @@ -1314,7 +1314,7 @@ static void write_context(OutputStream * out, char * id, char * parent_id, char json_write_string(out, "StartTime"); write_stream(out, ':'); - json_write_int64(out, (int64_t)starttime * 1000 / HZ); + json_write_uint64(out, (uint64_t)starttime * 1000 / HZ); write_stream(out, ','); json_write_string(out, "VSize"); |