void send_event_memory_changed(Context * ctx, ContextAddress addr, unsigned long size) { OutputStream * out = &broadcast_group->out; if (!context_has_state(ctx) || is_intercepted(ctx)) { 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 subscribe_cb(Channel * c, void * x, int error) { Trap trap; PortConnection * conn = (PortConnection *)x; PortAttribute * attr = conn->server->redir_info->attrs; OutputStream * out = &conn->server->channel->out; if (set_trap(&trap)) { if (!error) { error = read_errno(&c->inp); json_test_char(&c->inp, MARKER_EOM); } clear_trap(&trap); } else { error = trap.error; } /* Ignore error for subscribe since we may already have subscribed for this channel */ conn->pending = protocol_send_command(conn->server->channel, "PortForward", "create", portcreate_cb, conn); write_stream(out, '{'); json_write_string(out, "ID"); write_stream(out, ':'); json_write_string(out, conn->id); write_stream(out, ','); while (attr != NULL) { json_write_string(out, attr->name); write_stream(out, ':'); write_string(out, attr->value); attr = attr->next; } write_stream(out, '}'); write_stream(out, MARKER_EOA); write_stream(out, MARKER_EOM); }
FIO_status curve_save(const char* path, curve_points_type* curve){ FIL fff; // File handler FIO_status res = FIO_OK; if (SDFS_open(&fff, path, F_WR_CLEAR) != SDFS_OK) { return FIO_FILE_CREATE_ERROR; } json_write_string(0, "{", &fff); json_write_number(1, ATTR_CURVE_XW1, curve->xw1, 1, &fff); json_write_number(1, ATTR_CURVE_YW1, curve->yw1, 1, &fff); json_write_number(1, ATTR_CURVE_XW2, curve->xw2, 1, &fff); json_write_number(1, ATTR_CURVE_YW2, curve->yw2, 1, &fff); json_write_number(1, ATTR_CURVE_XW3, curve->xw3, 1, &fff); json_write_number(1, ATTR_CURVE_YW3, curve->yw3, 1, &fff); json_write_number(1, ATTR_CURVE_XB1, curve->xb1, 1, &fff); json_write_number(1, ATTR_CURVE_YB1, curve->yb1, 1, &fff); json_write_number(1, ATTR_CURVE_XB2, curve->xb2, 1, &fff); json_write_number(1, ATTR_CURVE_YB2, curve->yb2, 1, &fff); json_write_number(1, ATTR_CURVE_XB3, curve->xb3, 1, &fff); json_write_number(1, ATTR_CURVE_YB3, curve->yb3, 0, &fff); json_write_string(0, "}", &fff); curve->Crc = getCRC(curve, sizeof(curve_points_type)); if (SDFS_close(&fff)!= SDFS_OK) return FIO_FILE_CLOSE_ERROR; return res; }
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->exited) continue; if (ctx->parent != NULL) continue; if (cnt > 0) write_stream(&c->out, ','); json_write_string(&c->out, container_id(ctx)); cnt++; } } else if (id[0] == 'P') { LINK * qp; int cnt = 0; pid_t ppd = 0; Context * parent = id2ctx(id); id2pid(id, &ppd); if (parent != NULL && parent->parent == NULL && ppd == 0) { if (!parent->exited && context_has_state(parent)) { if (cnt > 0) write_stream(&c->out, ','); json_write_string(&c->out, thread_id(parent)); cnt++; } for (qp = parent->children.next; qp != &parent->children; qp = qp->next) { Context * ctx = cldl2ctxp(qp); assert(!ctx->exited); assert(ctx->parent == parent); if (cnt > 0) write_stream(&c->out, ','); json_write_string(&c->out,thread_id(ctx)); cnt++; } } } write_stream(&c->out, ']'); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); }
static void send_event_stream_disposed(OutputStream * out, VirtualStream * stream) { char id[256]; virtual_stream_get_id(stream, id, sizeof(id)); write_stringz(out, "E"); write_stringz(out, STREAMS); write_stringz(out, "disposed"); json_write_string(out, stream->type); write_stream(out, 0); json_write_string(out, id); write_stream(out, 0); write_stream(out, MARKER_EOM); }
static void command_get_address_info_cache_client(void * x) { int err = 0; Channel * c = cache_channel(); CommandAddressInfo * args = (CommandAddressInfo *)x; Context * ctx = NULL; const char * isa = NULL; ContextAddress range_addr = 0; ContextAddress range_size = 0; ContextAddress plt = 0; ctx = id2ctx(args->id); if (ctx == NULL) err = ERR_INV_CONTEXT; if (!err && get_context_isa(ctx, args->addr, &isa, &range_addr, &range_size) < 0) err = errno; if (!err) plt = is_plt_section(ctx, args->addr); cache_exit(); write_stringz(&c->out, "R"); write_stringz(&c->out, args->token); write_errno(&c->out, err); if (!err) { write_stream(&c->out, '{'); json_write_string(&c->out, "Addr"); write_stream(&c->out, ':'); json_write_uint64(&c->out, range_addr); write_stream(&c->out, ','); json_write_string(&c->out, "Size"); write_stream(&c->out, ':'); json_write_uint64(&c->out, range_size); if (isa != NULL) { write_stream(&c->out, ','); json_write_string(&c->out, "ISA"); write_stream(&c->out, ':'); json_write_string(&c->out, isa); } if (plt != 0) { write_stream(&c->out, ','); json_write_string(&c->out, "PLT"); write_stream(&c->out, ':'); json_write_uint64(&c->out, plt); } write_stream(&c->out, '}'); write_stream(&c->out, 0); } else { write_stringz(&c->out, "null"); } write_stream(&c->out, MARKER_EOM); }
FIO_status currentState_save(void){ FIL fff; // File handler FIO_status res = FIO_OK; if (SDFS_open(&fff, "0:/" SETTING_NAME, F_WR_CLEAR) != SDFS_OK){ return FIO_FILE_CREATE_ERROR; } json_write_string(0,"{",&fff); json_write_value(1, ATTR_SET_CALIBR,Current_state.calibration_name,1,&fff); json_write_value(1, ATTR_SET_PRESET,Current_state.preset_name,0,&fff); json_write_string(0,"}",&fff); if (SDFS_close(&fff)!= SDFS_OK) return FIO_FILE_CLOSE_ERROR; return res; }
void send_event_register_changed(const char * id) { unsigned i; Context * ctx = NULL; int frame = STACK_NO_FRAME; RegisterDefinition * def = NULL; OutputStream * out = &broadcast_group->out; id2register(id, &ctx, &frame, &def); if (ctx == NULL) return; for (i = 0; i < listener_cnt; i++) { Listener * l = listeners + i; if (l->func->register_changed == NULL) continue; l->func->register_changed(ctx, frame, def, l->args); } if (frame >= 0 && frame == get_top_frame(ctx)) { id = register2id(ctx, STACK_TOP_FRAME, def); } write_stringz(out, "E"); write_stringz(out, REGISTERS); write_stringz(out, "registerChanged"); json_write_string(out, id); write_stream(out, 0); write_stream(out, MARKER_EOM); }
static void command_get_children(char * token, Channel * c) { int err = 0; char id[256]; Symbol sym; Symbol * list = NULL; int cnt = 0; 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); if (id2symbol(id, &sym) < 0) err = errno; if (err == 0 && get_symbol_children(&sym, &list, &cnt) < 0) err = errno; write_stringz(&c->out, "R"); write_stringz(&c->out, 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); loc_free(list); }
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 int send_packet(PortConnection * conn, char * buffer, size_t size) { JsonWriteBinaryState state; assert (is_dispatch_thread()); assert (conn->pending_write_request < MAX_STREAM_WRITE); protocol_send_command(conn->server->channel, "Streams", "write", write_stream_done, conn); json_write_string(&conn->server->channel->out, conn->out_stream_id); write_stream(&conn->server->channel->out, 0); json_write_long(&conn->server->channel->out, size); write_stream(&conn->server->channel->out, MARKER_EOA); json_write_binary_start(&state, &conn->server->channel->out, size); json_write_binary_data(&state, buffer, size); json_write_binary_end(&state); write_stream(&conn->server->channel->out, MARKER_EOA); write_stream(&conn->server->channel->out, MARKER_EOM); conn->pending_write_request ++; if (conn->pending_write_request == MAX_STREAM_WRITE) { return 0; } else { send_packet_callback(conn, 0); } return 0; }
static void delete_config_done(Channel *c, void *client_data, int error) { PortConnection * conn = (PortConnection *) client_data; Trap trap; if (set_trap(&trap)) { if (!error) { error = read_errno(&c->inp); json_test_char(&c->inp, MARKER_EOM); } clear_trap(&trap); } else { error = trap.error; } if (!conn->auto_connect_stream) { protocol_send_command(conn->server->channel, "Streams", "disconnect", disconnect_stream_done, conn); json_write_string(&conn->server->channel->out, conn->out_stream_id); write_stream(&conn->server->channel->out, MARKER_EOA); write_stream(&conn->server->channel->out, MARKER_EOM); } else { loc_free(conn->out_stream_id); conn->out_stream_id = NULL; loc_free(conn->in_stream_id); conn->in_stream_id = NULL; port_unlock(conn); port_connection_close(conn); } }
static void add_report_prop_str(ReportBuffer * report, const char * name, const char * str) { ByteArrayOutputStream buf; OutputStream * out = create_byte_array_output_stream(&buf); json_write_string(out, str); write_stream(out, 0); add_report_prop(report, name, &buf); }
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_children(char * token, Channel * c) { char id[256]; json_read_string(&c->inp, id, sizeof(id)); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); 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 void send_event_stream_created(OutputStream * out, VirtualStream * stream, const char * context_id) { char id[256]; virtual_stream_get_id(stream, id, sizeof(id)); write_stringz(out, "E"); write_stringz(out, STREAMS); write_stringz(out, "created"); json_write_string(out, stream->type); write_stream(out, 0); json_write_string(out, id); write_stream(out, 0); json_write_string(out, context_id); write_stream(out, 0); write_stream(out, MARKER_EOM); flush_stream(out); }
static void send_event_context_removed(OutputStream * out, Context * ctx) { write_stringz(out, "E"); write_stringz(out, RUN_CONTROL); write_stringz(out, "contextRemoved"); /* <array of context IDs> */ write_stream(out, '['); if (context_has_state(ctx)) json_write_string(out, thread_id(ctx)); if (ctx->parent == NULL && list_is_empty(&ctx->children)) { if (context_has_state(ctx)) write_stream(out, ','); json_write_string(out, container_id(ctx)); } write_stream(out, ']'); write_stream(out, 0); write_stream(out, MARKER_EOM); }
static void write_boolean_member(OutputStream * out, const char * name, int val) { /* For this service FALSE is same as absence of the member */ if (!val) return; write_stream(out, ','); json_write_string(out, name); write_stream(out, ':'); json_write_boolean(out, 1); }
static void write_port_server_info(OutputStream * out, PortServer * server) { PortAttribute * attr = server->redir_info ? server->redir_info->attrs : NULL; write_stream(out, '{'); json_write_string(out, "ID"); write_stream(out, ':'); json_write_string(out, server->id); write_stream(out, ','); json_write_string(out, "AutoConnect"); write_stream(out, ':'); json_write_boolean(out, server->auto_connect); write_stream(out, ','); json_write_string(out, "LocalPort"); write_stream(out, ':'); json_write_uint64(out, server->local_port); if (server->is_udp) { write_stream(out, ','); json_write_string(out, "LocalPortIsUDP"); write_stream(out, ':'); json_write_boolean(out, server->is_udp); } while (attr != NULL) { write_stream(out, ','); if (strcmp(attr->name, "RemotePort") == 0) { json_write_string(out, "Port"); } else { json_write_string(out, attr->name); } write_stream(out, ':'); write_string(out, attr->value); attr = attr->next; } write_stream(out, '}'); }
static void send_event_context_exception(OutputStream * out, Context * ctx) { char buf[128]; write_stringz(out, "E"); write_stringz(out, RUN_CONTROL); write_stringz(out, "contextException"); /* String: Context ID */ json_write_string(out, thread_id(ctx)); write_stream(out, 0); /* String: Human readable description of the exception */ snprintf(buf, sizeof(buf), "Signal %d", ctx->signal); json_write_string(out, buf); write_stream(out, 0); write_stream(out, MARKER_EOM); }
static void disconnect_port(PortConnection * conn) { assert (is_dispatch_thread()); conn->shutdown_in_progress = 1; port_lock(conn); protocol_send_command(conn->server->channel, "PortForward", "delete", delete_config_done, conn); json_write_string(&conn->server->channel->out, conn->id); write_stream(&conn->server->channel->out, MARKER_EOA); write_stream(&conn->server->channel->out, MARKER_EOM); }
static void write_symbol_list(OutputStream * out) { if (list_cnt == 0) { write_stringz(out, "null"); } else if (list_cnt == 1) { json_write_string(out, symbol2id(list_buf[0])); write_stream(out, 0); } else { unsigned i = 0; write_stream(out, '['); for (i = 0; i < list_cnt; i++) { if (i > 0) write_stream(out, ','); json_write_string(out, symbol2id(list_buf[i])); } write_stream(out, ']'); write_stream(out, 0); } }
static void getcapabilities_cb(Channel * c, void * x, int error) { Trap trap; PortConnection * conn = (PortConnection *)x; PortAttribute * attr = conn->server->attrs; OutputStream * out = &conn->server->channel->out; if (set_trap(&trap)) { if (!error) { error = read_errno(&c->inp); json_read_struct(&c->inp, read_getcapabilities_struct, (void *)conn); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); } clear_trap(&trap); } else { error = trap.error; } if (error) { connect_port_callback(conn, error); } else { conn->pending = protocol_send_command(conn->server->channel, "PortForward", "create", portcreate_cb, conn); write_stream(out, '{'); json_write_string(out, "ID"); write_stream(out, ':'); json_write_string(out, conn->id); while (attr != NULL) { if (strncmp(attr->name, "AutoConnect", 11) != 0) { write_stream(out, ','); json_write_string(out, attr->name); write_stream(out, ':'); write_string(out, attr->value); } attr = attr->next; } write_stream(out, '}'); write_stream(out, MARKER_EOA); write_stream(out, MARKER_EOM); } }
static void write_inlined_subroutine_info(OutputStream * out, StackFrameInlinedSubroutine * info) { unsigned cnt = 0; write_stream(out, '{'); if (info->func_id != NULL) { if (cnt++ > 0) write_stream(out, ','); json_write_string(out, "ID"); write_stream(out, ':'); json_write_string(out, info->func_id); } #if ENABLE_LineNumbers if (cnt++ > 0) write_stream(out, ','); json_write_string(out, "Area"); write_stream(out, ':'); write_code_area(out, &info->area, NULL); #endif /* ENABLE_LineNumbers */ write_stream(out, '}'); }
FIO_status calibration_save(const char* path, calibrationType* cal){ FIL fff; // File handler FIO_status res = FIO_OK; int i; if (SDFS_open(&fff, path, F_WR_CLEAR) != SDFS_OK) { return FIO_FILE_CREATE_ERROR; } json_write_string(0, "{", &fff); json_write_string(1, "\"" ATTR_CAL_SLIDERS "\":{", &fff); for (i = 0; i < SLIDERS_AMOUNT; i++) { json_write_object(2, slider_names[i], &fff); json_write_number(3, ATTR_CAL_S_MIN, cal->calibr[i].min_in_value, 1, &fff); json_write_number(3, ATTR_CAL_S_MAX, cal->calibr[i].max_in_value, 1, &fff); json_write_number(3, ATTR_CAL_S_DELTA, cal->calibr[i].delta, 1, &fff); json_write_number(3, ATTR_CAL_S_DEAD, cal->calibr[i].dead, 1, &fff); json_write_number(3, ATTR_CAL_S_GAP, cal->calibr[i].gap, 0, &fff); if (i < SLIDERS_AMOUNT-1){ json_write_string(2, "},", &fff); }else{ json_write_string(2, "}", &fff); } } json_write_string(1, "}", &fff); json_write_string(0, "}", &fff); cal->Crc = getCRC(cal, sizeof(calibrationType)); if (SDFS_close(&fff)!= SDFS_OK) return FIO_FILE_CLOSE_ERROR; return res; }
static void write_port_server_info(OutputStream * out, PortServer * server) { PortAttribute * attr = server->attrs; write_stream(out, '{'); json_write_string(out, "ID"); write_stream(out, ':'); json_write_string(out, server->id); write_stream(out, ','); json_write_string(out, "AutoConnect"); write_stream(out, ':'); json_write_boolean(out, server->auto_connect); write_stream(out, ','); if (server->is_udp) json_write_string(out, "UdpPort"); else json_write_string(out, "TcpPort"); write_stream(out, ':'); json_write_ulong(out, server->local_port); while (attr != NULL) { if (strcmp(attr->name, "AutoConnect") != 0) { write_stream(out, ','); json_write_string(out, attr->name); write_stream(out, ':'); write_string(out, attr->value); } attr = attr->next; } write_stream(out, '}'); }
static void send_event_process_exited(OutputStream * out, ChildProcess * prs) { write_stringz(out, "E"); write_stringz(out, PROCESSES); write_stringz(out, "exited"); json_write_string(out, pid2id(prs->pid, 0)); write_stream(out, 0); json_write_long(out, prs->exit_code); write_stream(out, 0); write_stream(out, MARKER_EOM); }
static void command_get_capabilities(char * token, Channel * c) { char id[256]; Context * ctx; OutputStream * out = &c->out; int err = 0; json_read_string(&c->inp, id, sizeof(id)); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); ctx = id2ctx(id); if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; write_stringz(out, "R"); write_stringz(out, token); write_errno(out, err); write_stream(out, '['); if (!err) { unsigned i; ContextExtensionRS * ext = EXT(get_reset_context(ctx)); for (i = 0; i < ext->resets_cnt; i++) { ResetInfo * ri = ext->resets + i; if (i > 0) write_stream(&c->out, ','); write_stream(out, '{'); json_write_string(out, "Type"); write_stream(out, ':'); json_write_string(out, ri->type); write_stream(out, ','); json_write_string(out, "Description"); write_stream(out, ':'); json_write_string(out, ri->desc); write_stream(out, '}'); } } write_stream(out, ']'); write_stream(out, 0); write_stream(out, MARKER_EOM); }
static void send_event_terminal_exited(OutputStream * out, Terminal * term) { write_stringz(out, "E"); write_stringz(out, TERMINALS); write_stringz(out, "exited"); json_write_string(out, tid2id(get_process_pid(term->prs))); write_stream(out, 0); json_write_ulong(out, get_process_exit_code(term->prs)); write_stream(out, 0); write_stream(out, MARKER_EOM); }
static void command_get_children_cache_client(void * x) { GetChildrenArgs * args = (GetChildrenArgs *)x; Channel * c = cache_channel(); Context * ctx = NULL; int frame = STACK_NO_FRAME; StackFrame * frame_info = NULL; RegisterDefinition * defs = NULL; RegisterDefinition * parent = NULL; Trap trap; if (set_trap(&trap)) { if (id2register(args->id, &ctx, &frame, &parent) == 0) { if (frame != STACK_TOP_FRAME && get_frame_info(ctx, frame, &frame_info) < 0) exception(errno); } else if (id2frame(args->id, &ctx, &frame) == 0) { if (get_frame_info(ctx, frame, &frame_info) < 0) exception(errno); } else { ctx = id2ctx(args->id); frame = STACK_TOP_FRAME; } if (ctx != NULL) defs = get_reg_definitions(ctx); clear_trap(&trap); } cache_exit(); write_stringz(&c->out, "R"); write_stringz(&c->out, args->token); write_errno(&c->out, trap.error); write_stream(&c->out, '['); if (defs != NULL) { int cnt = 0; RegisterDefinition * reg_def; for (reg_def = defs; reg_def->name != NULL; reg_def++) { if (reg_def->parent != parent) continue; if (frame < 0 || frame_info->is_top_frame || reg_def->size == 0 || read_reg_value(frame_info, reg_def, NULL) == 0) { if (cnt > 0) write_stream(&c->out, ','); json_write_string(&c->out, register2id(ctx, frame, reg_def)); cnt++; } } } write_stream(&c->out, ']'); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); }