/******************************************************************************* * 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 service line Numbers - common part. * * The service associates locations in the source files with the corresponding * machine instruction addresses in the executable object. */ #include #if SERVICE_LineNumbers #include #include #include #include #include #include #include #include #include #include #include #define MAX_AREA_CNT 256 typedef struct MapToSourceArgs { char token[256]; char id[256]; ContextAddress addr0; ContextAddress addr1; } MapToSourceArgs; typedef struct MapToMemoryArgs { char token[256]; char id[256]; char * file; int line; int column; } MapToMemoryArgs; static int code_area_cnt = 0; static int code_area_max = 0; static CodeArea * code_area_buf = NULL; static const char * LINENUMBERS = "LineNumbers"; static void write_line_info(OutputStream * out, int cnt) { CodeArea * area = code_area_buf + cnt; CodeArea * prev = cnt == 0 ? NULL : code_area_buf + cnt - 1; write_stream(out, '{'); json_write_string(out, "SAddr"); write_stream(out, ':'); json_write_uint64(out, area->start_address); if (area->start_line > 0) { write_stream(out, ','); json_write_string(out, "SLine"); write_stream(out, ':'); json_write_ulong(out, area->start_line); if (area->start_column > 0) { write_stream(out, ','); json_write_string(out, "SCol"); write_stream(out, ':'); json_write_ulong(out, area->start_column); } } if (area->end_address != 0) { write_stream(out, ','); json_write_string(out, "EAddr"); write_stream(out, ':'); json_write_uint64(out, area->end_address); } if (area->end_line > 0) { write_stream(out, ','); json_write_string(out, "ELine"); write_stream(out, ':'); json_write_ulong(out, area->end_line); if (area->end_column > 0) { write_stream(out, ','); json_write_string(out, "ECol"); write_stream(out, ':'); json_write_ulong(out, area->end_column); } } if (area->file != NULL && (prev == NULL || prev->file != area->file)) { write_stream(out, ','); json_write_string(out, "File"); write_stream(out, ':'); json_write_string(out, area->file); } if (area->directory != NULL && (prev == NULL || prev->directory != area->directory)) { write_stream(out, ','); json_write_string(out, "Dir"); write_stream(out, ':'); json_write_string(out, area->directory); } if (area->isa > 0) { write_stream(out, ','); json_write_string(out, "ISA"); write_stream(out, ':'); json_write_ulong(out, area->isa); } if (area->is_statement) { write_stream(out, ','); json_write_string(out, "IsStmt"); write_stream(out, ':'); json_write_boolean(out, 1); } if (area->basic_block) { write_stream(out, ','); json_write_string(out, "BasicBlock"); write_stream(out, ':'); json_write_boolean(out, 1); } if (area->prologue_end) { write_stream(out, ','); json_write_string(out, "PrologueEnd"); write_stream(out, ':'); json_write_boolean(out, 1); } if (area->epilogue_begin) { write_stream(out, ','); json_write_string(out, "EpilogueBegin"); write_stream(out, ':'); json_write_boolean(out, 1); } write_stream(out, '}'); } static void add_code_area(CodeArea * area, void * args) { if (code_area_cnt >= code_area_max) { if (code_area_max >= MAX_AREA_CNT) exception(ERR_BUFFER_OVERFLOW); code_area_max += 8; code_area_buf = (CodeArea *)loc_realloc(code_area_buf, sizeof(CodeArea) * code_area_max); } code_area_buf[code_area_cnt++] = *area; } static void map_to_source_cache_client(void * x) { int err = 0; Context * ctx = NULL; MapToSourceArgs * args = (MapToSourceArgs *)x; Channel * c = cache_channel(); ctx = id2ctx(args->id); if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; else ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS); code_area_cnt = 0; if (err == 0 && address_to_line(ctx, args->addr0, args->addr1, add_code_area, NULL) < 0) err = errno; cache_exit(); write_stringz(&c->out, "R"); write_stringz(&c->out, args->token); write_errno(&c->out, err); if (err != 0) { write_stringz(&c->out, "null"); } else { int cnt = 0; write_stream(&c->out, '['); while (cnt < code_area_cnt) { if (cnt > 0) write_stream(&c->out, ','); write_line_info(&c->out, cnt); cnt++; } write_stream(&c->out, ']'); write_stream(&c->out, 0); } write_stream(&c->out, MARKER_EOM); } static void command_map_to_source(char * token, Channel * c) { MapToSourceArgs args; 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_uint64(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); 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); strlcpy(args.token, token, sizeof(args.token)); cache_enter(map_to_source_cache_client, c, &args, sizeof(args)); } static void map_to_memory_cache_client(void * x) { int err = 0; Context * ctx = NULL; MapToMemoryArgs * args = (MapToMemoryArgs *)x; Channel * c = cache_channel(); ctx = id2ctx(args->id); if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; else ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS); code_area_cnt = 0; if (err == 0 && line_to_address(ctx, args->file, args->line, args->column, add_code_area, NULL) < 0) err = errno; cache_exit(); write_stringz(&c->out, "R"); write_stringz(&c->out, args->token); write_errno(&c->out, err); if (err != 0) { write_stringz(&c->out, "null"); } else { int cnt = 0; write_stream(&c->out, '['); while (cnt < code_area_cnt) { if (cnt > 0) write_stream(&c->out, ','); write_line_info(&c->out, cnt); cnt++; } write_stream(&c->out, ']'); write_stream(&c->out, 0); } write_stream(&c->out, MARKER_EOM); loc_free(args->file); } static void command_map_to_memory(char * token, Channel * c) { MapToMemoryArgs args; json_read_string(&c->inp, args.id, sizeof(args.id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); args.file = json_read_alloc_string(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); args.line = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); args.column = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); strlcpy(args.token, token, sizeof(args.token)); cache_enter(map_to_memory_cache_client, c, &args, sizeof(args)); } void ini_line_numbers_service(Protocol * proto) { ini_line_numbers_lib(); add_command_handler(proto, LINENUMBERS, "mapToSource", command_map_to_source); add_command_handler(proto, LINENUMBERS, "mapToMemory", command_map_to_memory); } #endif /* SERVICE_LineNumbers */