diff options
Diffstat (limited to 'agent/tcf')
59 files changed, 3084 insertions, 1055 deletions
diff --git a/agent/tcf/config.h b/agent/tcf/config.h index 2353d2ec..640f028a 100644 --- a/agent/tcf/config.h +++ b/agent/tcf/config.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 20018 Xilinx, Inc. and others. + * Copyright (c) 2018-2020 Xilinx, 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. diff --git a/agent/tcf/framework/channel_tcp.c b/agent/tcf/framework/channel_tcp.c index 70d30abe..02807a2d 100644 --- a/agent/tcf/framework/channel_tcp.c +++ b/agent/tcf/framework/channel_tcp.c @@ -39,7 +39,7 @@ # include <openssl/rand.h> # include <openssl/err.h> # if defined(_WIN32) || defined(__CYGWIN__) -# include <ShlObj.h> +# include <shlobj.h> # endif #else typedef void SSL; @@ -1545,6 +1545,7 @@ void channel_tcp_connect(PeerServer * ps, ChannelConnectCallBack callback, void info->sock = -1; for (res = reslist; res != NULL; res = res->ai_next) { info->addr_len = res->ai_addrlen; + if (info->addr_buf != NULL) loc_free(info->addr_buf); info->addr_buf = (struct sockaddr *)loc_alloc(res->ai_addrlen); memcpy(info->addr_buf, res->ai_addr, res->ai_addrlen); info->sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); diff --git a/agent/tcf/framework/context.c b/agent/tcf/framework/context.c index 2472fffe..64baf7cd 100644 --- a/agent/tcf/framework/context.c +++ b/agent/tcf/framework/context.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2016 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -52,7 +52,7 @@ const char * REASON_ERROR = "Error"; char * pid2id(pid_t pid, pid_t parent) { static char s[64]; char * p = s + sizeof(s); - unsigned long n = (long)pid; + uint64_t n = pid; *(--p) = 0; do { *(--p) = (char)(n % 10 + '0'); @@ -60,7 +60,7 @@ char * pid2id(pid_t pid, pid_t parent) { } while (n != 0); if (parent != 0) { - n = (long)parent; + n = parent; *(--p) = '.'; do { *(--p) = (char)(n % 10 + '0'); @@ -74,7 +74,7 @@ char * pid2id(pid_t pid, pid_t parent) { pid_t id2pid(const char * id, pid_t * parent) { /* TODO: (pid_t)0 is valid value in Windows, should use (pid_t)-1 to indicate an error */ - pid_t pid = 0; + uint64_t pid = 0; if (parent != NULL) *parent = 0; if (id == NULL) return 0; if (*id++ != 'P') return 0; @@ -82,7 +82,7 @@ pid_t id2pid(const char * id, pid_t * parent) { pid = pid * 10 + (*id++ - '0'); } if (*id == '.') { - if (parent != NULL) *parent = pid; + if (parent != NULL) *parent = (pid_t)pid; id++; pid = 0; while (*id >= '0' && *id <= '9') { @@ -90,7 +90,7 @@ pid_t id2pid(const char * id, pid_t * parent) { } } if (*id != 0) return 0; - return pid; + return (pid_t)pid; } void add_context_event_listener(ContextEventListener * listener, void * client_data) { diff --git a/agent/tcf/framework/cpudefs-ext.h b/agent/tcf/framework/cpudefs-ext.h index b63a4214..20bc46ff 100644 --- a/agent/tcf/framework/cpudefs-ext.h +++ b/agent/tcf/framework/cpudefs-ext.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -114,7 +114,7 @@ int read_reg_bytes(StackFrame * frame, RegisterDefinition * reg_def, unsigned of uint8_t * m_addr = (uint8_t *)&((SysRegisterData *)frame->regs)->mask + reg_def->offset; for (i = 0; i < size; i++) { if (m_addr[offs + i] != 0xff) { - set_fmt_errno(ERR_OTHER, "Value of register %s is unknown in the selected frame", reg_def->name); + set_fmt_errno(ERR_OTHER, "Value of register %s is unknown in frame %d", reg_def->name, frame->frame); return -1; } } diff --git a/agent/tcf/framework/cpudefs.c b/agent/tcf/framework/cpudefs.c index 8db5a72f..fec3cacb 100644 --- a/agent/tcf/framework/cpudefs.c +++ b/agent/tcf/framework/cpudefs.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -33,6 +33,15 @@ #include <tcf/framework/cpudefs-ext.h> +typedef struct ContextExtensionRegisters { + unsigned reg_seq; + unsigned reg_cnt; +} ContextExtensionRegisters; + +static unsigned reg_defs_seq = 1; +static size_t context_extension_offset = 0; +#define EXT(ctx) ((ContextExtensionRegisters *)((char *)(ctx) + context_extension_offset)) + void create_reg_children_refs(RegisterDefinition * defs) { #if ENABLE_RegisterChildrenRefs RegisterDefinition * r = NULL; @@ -196,10 +205,27 @@ const char * frame2id(Context * ctx, int frame) { return tmp_printf("FP%d.%s", frame, ctx->id); } +static void update_reg_cnt(Context * ctx, RegisterDefinition * defs) { + ContextExtensionRegisters * ext = EXT(ctx); + assert(reg_defs_seq != 0); + if (ext->reg_seq != reg_defs_seq) { + ext->reg_cnt = 0; + if (defs != NULL) { + while (defs->name != NULL) { + ext->reg_cnt++; + defs++; + } + } + ext->reg_seq = reg_defs_seq; + } +} + const char * register2id(Context * ctx, int frame, RegisterDefinition * reg) { RegisterDefinition * defs = get_reg_definitions(ctx); + update_reg_cnt(ctx, defs); assert(defs != NULL); assert(reg >= defs); + assert(reg < defs + EXT(ctx)->reg_cnt); if (frame < 0) return tmp_printf("R%d.%s", (int)(reg - defs), ctx->id); return tmp_printf("R%d@%d.%s", (int)(reg - defs), frame, ctx->id); } @@ -209,7 +235,7 @@ int id2reg_num(const char * id, const char ** ctx_id, int * frame, unsigned * re *frame = STACK_TOP_FRAME; *reg_num = 0; if (*id++ != 'R') { - errno = ERR_INV_CONTEXT; + errno = ERR_OTHER; return -1; } while (*id != '.' && *id != '@') { @@ -217,7 +243,7 @@ int id2reg_num(const char * id, const char ** ctx_id, int * frame, unsigned * re *reg_num = *reg_num * 10 + (*id++ - '0'); } else { - errno = ERR_INV_CONTEXT; + errno = ERR_OTHER; return -1; } } @@ -229,7 +255,7 @@ int id2reg_num(const char * id, const char ** ctx_id, int * frame, unsigned * re n = n * 10 + (*id++ - '0'); } else { - errno = ERR_INV_CONTEXT; + errno = ERR_OTHER; return -1; } } @@ -248,7 +274,10 @@ int id2register(const char * id, Context ** ctx, int * frame, RegisterDefinition *ctx = NULL; *reg_def = NULL; - if (id2reg_num(id, &ctx_id, frame, ®_num) < 0) return -1; + if (id2reg_num(id, &ctx_id, frame, ®_num) < 0) { + if (errno == ERR_OTHER) set_errno(errno, "Malformed register ID"); + return -1; + } *ctx = id2ctx(ctx_id); if (*ctx == NULL) { @@ -264,10 +293,20 @@ int id2register(const char * id, Context ** ctx, int * frame, RegisterDefinition set_errno(ERR_OTHER, "Context has no registers"); return -1; } + update_reg_cnt(*ctx, defs); + if (reg_num >= EXT(*ctx)->reg_cnt) { + set_errno(ERR_OTHER, "Invalid register ID"); + return -1; + } *reg_def = defs + reg_num; return 0; } +void invalidate_register_ids(void) { + do reg_defs_seq++; + while (reg_defs_seq == 0); +} + static void location_expression_error(void) { str_exception(ERR_OTHER, "Invalid location expression"); } @@ -526,7 +565,8 @@ LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame } else { stk_pos--; - piece->addr = (ContextAddress)stk[stk_pos]; + piece->addr = (ContextAddress)stk[stk_pos] + piece->bit_offs / 8; + piece->bit_offs %= 8; } } break; @@ -550,7 +590,7 @@ LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame #define bit_mask(n) (1u << (big_endian ? 7 - (n) % 8 : (n) % 8)) -void read_location_pieces(Context * ctx, StackFrame * frame, +void read_location_pieces_local(Context * ctx, StackFrame * frame, void * loc_buf, size_t loc_size, LocationPiece * pieces, unsigned pieces_cnt, int big_endian, void ** value, size_t * size) { /* Note: 'big_endian' should match endianness of LocationPiece.value in 'pieces' */ @@ -562,7 +602,22 @@ void read_location_pieces(Context * ctx, StackFrame * frame, unsigned i = 0; while (i < pieces_cnt) { LocationPiece * piece = pieces + i++; - bf_bits += piece->bit_size ? piece->bit_size : piece->size * 8; + if (piece->optimized_away) { + str_exception(ERR_OTHER, "Cannot get symbol value: optimized away"); + } + else if (piece->implicit_pointer) { + if (piece->implicit_pointer == 1 && + piece->reg == NULL && piece->value == NULL && + piece->bit_offs == 0 && piece->bit_size == 0) { + bf_bits += context_word_size(ctx) * 8; + } + else { + str_exception(ERR_OTHER, "Cannot get symbol value: implicit pointer"); + } + } + else { + bf_bits += piece->bit_size ? piece->bit_size : piece->size * 8; + } } bf_size = (size_t)((bf_bits + 7) / 8); bf = (uint8_t *)tmp_alloc_zero(bf_size); @@ -573,15 +628,16 @@ void read_location_pieces(Context * ctx, StackFrame * frame, unsigned piece_bits = piece->bit_size ? piece->bit_size : piece->size * 8; uint8_t * pbf = NULL; uint8_t * rbf = NULL; - if (piece->optimized_away) { - set_errno(ERR_OTHER, "Cannot get symbol value: optimized away"); - exception(errno); - } if (piece->implicit_pointer) { - set_errno(ERR_OTHER, "Cannot get symbol value: implicit pointer"); - exception(errno); + piece_size = context_word_size(ctx); + piece_bits = piece_size * 8; + pbf = (uint8_t *)tmp_alloc(piece_size); + rbf = (uint8_t *)&piece->addr; + if (sizeof(piece->addr) > piece_size && big_endian_host()) rbf += sizeof(piece->addr) - piece_size; + memcpy(pbf, rbf, piece_size); + if (!big_endian_host() != !big_endian) swap_bytes(pbf, piece_size); } - if (piece->reg) { + else if (piece->reg) { if (piece->reg->size < piece_size) { rbf = pbf = (uint8_t *)tmp_alloc_zero(piece_size); if (big_endian) rbf += piece_size - piece->reg->size; @@ -602,7 +658,15 @@ void read_location_pieces(Context * ctx, StackFrame * frame, } else { pbf = (uint8_t *)tmp_alloc(piece_size); - if (context_read_mem(ctx, piece->addr, pbf, piece_size) < 0) exception(errno); + if (loc_buf == NULL) { + if (context_read_mem(ctx, piece->addr, pbf, piece_size) < 0) exception(errno); + } + else { + if (piece->addr + piece_size > loc_size) { + str_exception(ERR_OTHER, "Cannot get symbol value: invalid location expression"); + } + memcpy(pbf, (uint8_t *)loc_buf + piece->addr, piece_size); + } } for (i = piece->bit_offs; i < piece->bit_offs + piece_bits; i++) { if (pbf[i / 8] & bit_mask(i)) bf[bf_offs / 8] |= bit_mask(bf_offs); @@ -614,6 +678,12 @@ void read_location_pieces(Context * ctx, StackFrame * frame, *size = bf_size; } +void read_location_pieces(Context * ctx, StackFrame * frame, + LocationPiece * pieces, unsigned pieces_cnt, int big_endian, + void ** value, size_t * size) { + read_location_pieces_local(ctx, frame, NULL, 0, pieces, pieces_cnt, big_endian, value, size); +} + void write_location_pieces(Context * ctx, StackFrame * frame, LocationPiece * pieces, unsigned pieces_cnt, int big_endian, void * value, size_t size) { @@ -739,6 +809,7 @@ void ini_cpu_disassembler(Context * cpu) { } void ini_cpudefs(void) { + context_extension_offset = context_extension(sizeof(ContextExtensionRegisters)); #if defined(ENABLE_ini_cpudefs_mdep) && ENABLE_ini_cpudefs_mdep ini_cpudefs_mdep(); #endif diff --git a/agent/tcf/framework/cpudefs.h b/agent/tcf/framework/cpudefs.h index a11a1342..35edc913 100644 --- a/agent/tcf/framework/cpudefs.h +++ b/agent/tcf/framework/cpudefs.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -66,16 +66,16 @@ struct RegisterDefinition { size_t size; /* register size in bytes */ int16_t dwarf_id; /* ID of the register in DWARF sections, or -1 */ int16_t eh_frame_id; /* ID of the register in .eh_frame section, or -1 */ - uint8_t big_endian; /* 0 - little endian, 1 - big endian */ - uint8_t fp_value; /* true if the register value is a floating-point value */ - uint8_t no_read; /* true if context value can not be read */ - uint8_t no_write; /* true if context value can not be written */ - uint8_t read_once; /* true if reading the context (register) destroys its current value */ - uint8_t write_once; /* true if register value can not be overwritten - every write counts */ - uint8_t side_effects; /* true if writing the context can change values of other registers */ - uint8_t volatile_value;/* true if the register value can change even when target is stopped */ - uint8_t left_to_right; /* true if the lowest numbered bit should be shown to user as the left-most bit */ - int first_bit; /* bit numbering base (0 or 1) to use when showing bits to user */ + unsigned big_endian : 1; /* 0 - little endian, 1 - big endian */ + unsigned fp_value : 1; /* true if the register value is a floating-point value */ + unsigned no_read : 1; /* true if context value can not be read */ + unsigned no_write : 1; /* true if context value can not be written */ + unsigned read_once : 1; /* true if reading the context (register) destroys its current value */ + unsigned write_once : 1; /* true if register value can not be overwritten - every write counts */ + unsigned side_effects : 1; /* true if writing the context can change values of other registers */ + unsigned volatile_value : 1; /* true if the register value can change even when target is stopped */ + unsigned left_to_right : 1; /* true if the lowest numbered bit should be shown to user as the left-most bit */ + unsigned first_bit : 1; /* bit numbering base (0 or 1) to use when showing bits to user */ int * bits; /* if context is a bit field, contains the field bit numbers in the parent register definition, -1 marks end of the list */ RegisterDefinition * parent; /* parent register definition, NULL for top level definitions */ NamedRegisterValue ** values; /* predefined names (mnemonics) for some of register values */ @@ -282,7 +282,7 @@ extern int write_reg_location(StackFrame * frame, RegisterDefinition * reg_def, #endif /* Get instruction pointer (PC) value. -* Deprecated: use get_PC() */ + * Deprecated: use get_PC() */ extern ContextAddress get_regs_PC(Context * ctx); /* Set instruction pointer (PC) value. @@ -308,6 +308,10 @@ extern const char * register2id(Context * ctx, int frame, RegisterDefinition * r extern int id2reg_num(const char * id, const char ** ctx_id, int * frame, unsigned * reg_num); extern int id2register(const char * id, Context ** ctx, int * frame, RegisterDefinition ** reg_def); +/* Invalidate register IDs. + * This function is called by the RunControl service when register definitions change. */ +extern void invalidate_register_ids(void); + /* Get breakpoint instruction code and size. * Return NULL if the context does not support software breakpoints. */ extern uint8_t * get_break_instruction(Context * ctx, size_t * size); @@ -336,6 +340,12 @@ extern void read_location_pieces( LocationPiece * pieces, unsigned pieces_cnt, int big_endian, void ** value, size_t * size); +extern void read_location_pieces_local( + Context * ctx, StackFrame * frame, + void * loc_buf, size_t loc_size, + LocationPiece * pieces, unsigned pieces_cnt, int big_endian, + void ** value, size_t * size); + extern void write_location_pieces( Context * ctx, StackFrame * frame, LocationPiece * pieces, unsigned pieces_cnt, int big_endian, diff --git a/agent/tcf/framework/errors.c b/agent/tcf/framework/errors.c index 641346cd..753599db 100644 --- a/agent/tcf/framework/errors.c +++ b/agent/tcf/framework/errors.c @@ -67,7 +67,7 @@ typedef struct ErrorMessage { } ErrorMessage; static ErrorMessage msgs[MESSAGE_CNT]; -static int msgs_pos = 0; +static unsigned msgs_pos = 0; static char * msg_buf = NULL; static size_t msg_buf_max = 0; @@ -162,7 +162,7 @@ int set_nt_status_errno(DWORD status) { int error = 0; assert(is_dispatch_thread()); if (status != 0) { - HMODULE module = LoadLibrary("NTDLL.DLL"); + HMODULE module = LoadLibrarySystem32("NTDLL.DLL"); char * msg = system_strerror(status, module); error = set_errno(ERR_OTHER, msg); FreeLibrary(module); @@ -392,34 +392,35 @@ const char * errno_to_str(int err) { int set_errno(int no, const char * msg) { errno = no; - if (no != 0 && msg != NULL) { + if (no != 0 && msg != NULL && *msg != 0) { ErrorMessage * m = alloc_msg(SRC_MESSAGE); /* alloc_msg() assigns new value to 'errno', * need to be sure it does not change until this function exits. */ int err = errno; - m->error = get_error_code(no); if (no == ERR_OTHER) { m->text = loc_strdup(msg); + m->error = ERR_OTHER; + } + else if (no == err) { + /* Overflow of error message buffer */ + m->text = loc_strdup2(msg, "..."); + m->error = ERR_OTHER; } else { size_t msg_len = strlen(msg); - if (msg_len == 0) { - m->text = loc_strdup(errno_to_str(no)); + const char * str = errno_to_str(no); + if (msg[msg_len - 1] == '.' || msg[msg_len - 1] == '\n') { + size_t len = msg_len + strlen(str) + 2; + m->text = (char *)loc_alloc(len); + snprintf(m->text, len, "%s %s", msg, str); } else { - const char * str = errno_to_str(no); - if (msg[msg_len - 1] == '.' || msg[msg_len - 1] == '\n') { - size_t len = msg_len + strlen(str) + 2; - m->text = (char *)loc_alloc(len); - snprintf(m->text, len, "%s %s", msg, str); - } - else { - size_t len = msg_len + strlen(str) + 3; - m->text = (char *)loc_alloc(len); - snprintf(m->text, len, "%s. %s", msg, str); - } + size_t len = msg_len + strlen(str) + 3; + m->text = (char *)loc_alloc(len); + snprintf(m->text, len, "%s. %s", msg, str); } + m->error = get_error_code(no); } errno = err; } diff --git a/agent/tcf/framework/events.c b/agent/tcf/framework/events.c index 3a35fde7..12f0b5c4 100644 --- a/agent/tcf/framework/events.c +++ b/agent/tcf/framework/events.c @@ -227,7 +227,7 @@ void post_event_with_delay(EventCallBack * handler, void * arg, unsigned long de } check_error(pthread_mutex_unlock(&event_lock)); - trace(LOG_EVENTCORE, "post_event: event %#" PRIxPTR ", handler %#" PRIxPTR ", arg %#" PRIxPTR ", runtime %02u%02u.%03u", + trace(LOG_EVENTCORE, "post_event: event %#" PRIxPTR ", handler %#" PRIxPTR ", arg %#" PRIxPTR ", runtime %02u:%02u.%03u", (uintptr_t)ev, (uintptr_t)ev->handler, (uintptr_t)ev->arg, (unsigned)(ev->runtime.tv_sec / 60 % 60), (unsigned)(ev->runtime.tv_sec % 60), diff --git a/agent/tcf/framework/inputbuf.c b/agent/tcf/framework/inputbuf.c index 2ba5efb3..3901e993 100644 --- a/agent/tcf/framework/inputbuf.c +++ b/agent/tcf/framework/inputbuf.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -49,6 +49,7 @@ static void ibuf_eof(InputBuf * ibuf) { } static size_t ibuf_free_size(InputBuf * ibuf) { + assert(ibuf->stream->cur <= ibuf->stream->end); if (ibuf->eof) return 0; if (ibuf->stream->cur == ibuf->buf + ibuf->buf_size) { assert(ibuf->stream->cur == ibuf->stream->end); @@ -67,7 +68,7 @@ void ibuf_trigger_read(InputBuf * ibuf) { size_t size = ibuf_free_size(ibuf); if (size > 0) { assert(ibuf->inp + size <= ibuf->buf + ibuf->buf_size); - assert(ibuf->inp + size <= ibuf->stream->cur || ibuf->inp >= ibuf->stream->end); + assert(ibuf->inp + size < ibuf->stream->cur || ibuf->inp >= ibuf->stream->end); ibuf->post_read(ibuf, ibuf->inp, size); } } @@ -87,7 +88,8 @@ int ibuf_get_more(InputBuf * ibuf, int peeking) { if (out == ibuf->inp) { /* No data available */ assert(ibuf->long_msg || ibuf->eof); - inp->cur = out; + /* Note: async read may be running, don't change ibuf->inp */ + inp->cur = inp->end = out; if (ibuf->eof) return MARKER_EOS; assert(ibuf->message_count == 1); ibuf_trigger_read(ibuf); @@ -173,7 +175,6 @@ int ibuf_get_more(InputBuf * ibuf, int peeking) { while (out != max && *out != ESC) out++; inp->end = out; if (!peeking) inp->cur++; - assert(inp->cur <= inp->end); ibuf_trigger_read(ibuf); return ch; } diff --git a/agent/tcf/framework/json.c b/agent/tcf/framework/json.c index 04e6f6c0..c0d35531 100644 --- a/agent/tcf/framework/json.c +++ b/agent/tcf/framework/json.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -59,7 +59,7 @@ #define ENCODING_BASE64 1 #define read_no_whitespace(ch, inp) do { int _c_ = read_stream(inp); \ - while (_c_ > 0 && isspace(_c_)) _c_ = read_stream(inp); (ch) = _c_; } while (0) + while (_c_ > 0 && isspace(_c_)) { _c_ = read_stream(inp); } (ch) = _c_; } while (0) #define skip_whitespace(inp) do { int _c_ = peek_stream(inp); \ while (_c_ > 0 && isspace(_c_)) { read_stream(inp); _c_ = peek_stream(inp); } } while (0) @@ -1114,6 +1114,7 @@ int read_error_object(InputStream * inp) { err->time_stamp = json_read_uint64(inp); } else if (strcmp(name, "Format") == 0) { + if (err->format != NULL) loc_free(err->format); err->format = json_read_alloc_string(inp); } else if (strcmp(name, "Params") == 0) { diff --git a/agent/tcf/framework/mdep-inet.h b/agent/tcf/framework/mdep-inet.h index 32f4b849..e7688544 100644 --- a/agent/tcf/framework/mdep-inet.h +++ b/agent/tcf/framework/mdep-inet.h @@ -30,7 +30,7 @@ #include <cygwin/version.h> -#if CYGWIN_VERSION_CYGWIN_CONV < 157 +#if defined(CYGWIN_VERSION_CYGWIN_CONV) && CYGWIN_VERSION_CYGWIN_CONV < 157 extern void __stdcall freeaddrinfo(struct addrinfo *); extern int __stdcall getaddrinfo(const char *, const char *, @@ -45,7 +45,7 @@ extern const char * loc_gai_strerror(int ecode); /* inet_ntop()/inet_pton() are not available in MinGW */ /* inet_ntop()/inet_pton() are not available in Windows before Windows Vista */ -#if defined(__MINGW32__) || (defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600) +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) || (defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600) extern const char * inet_ntop(int af, const void * src, char * dst, socklen_t size); extern int inet_pton(int af, const char * src, void * dst); #endif diff --git a/agent/tcf/framework/mdep.c b/agent/tcf/framework/mdep.c index 24343c79..148c9b8e 100644 --- a/agent/tcf/framework/mdep.c +++ b/agent/tcf/framework/mdep.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -264,7 +264,7 @@ int wsa_closesocket(int socket) { /* inet_ntop()/inet_pton() are not available in MinGW */ /* inet_ntop()/inet_pton() are not available in Windows before Windows Vista */ -#if defined(__MINGW32__) || (defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600) +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) || (defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600) const char * inet_ntop(int af, const void * src, char * dst, socklen_t size) { char * str = NULL; if (af != AF_INET) { @@ -319,20 +319,41 @@ int clock_gettime(clockid_t clock_id, struct timespec * tp) { return 0; } if (clock_id == CLOCK_MONOTONIC) { - typedef ULONGLONG (FAR WINAPI * ProcType)(void); - static ProcType proc = NULL; + typedef ULONGLONG (FAR WINAPI * ProcTickType)(void); + typedef BOOL (FAR WINAPI * ProcPerfType)(LARGE_INTEGER *); + typedef BOOL (FAR WINAPI * ProcFreqType)(LARGE_INTEGER *); + static ProcTickType proc_tick = NULL; + static ProcPerfType proc_perf = NULL; + static LONGLONG perf_freq = 0; /* Hz */ static int chk_done = 0; ULONGLONG time_ms = 0; /* GetTickCount() is valid only first 49 days */ - /* GetTickCount64 not available before Windows Vista */ + /* GetTickCount64() not available before Windows Vista */ + /* QueryPerformanceCounter() not available before Windows 2000 */ + /* GetTickCount64() appears delayed 200ms relative to QueryPerformanceCounter() */ if (!chk_done) { - HMODULE kernel_dll = LoadLibraryA("Kernel32.dll"); + HMODULE kernel_dll = LoadLibrarySystem32("Kernel32.dll"); if (kernel_dll != NULL) { - proc = (ProcType)GetProcAddress(kernel_dll, "GetTickCount64"); + LARGE_INTEGER li; + ProcFreqType proc_freq = (ProcFreqType)GetProcAddress(kernel_dll, "QueryPerformanceFrequency"); + if (proc_freq != NULL && proc_freq(&li)) { + proc_perf = (ProcPerfType)GetProcAddress(kernel_dll, "QueryPerformanceCounter"); + perf_freq = li.QuadPart; + } + proc_tick = (ProcTickType)GetProcAddress(kernel_dll, "GetTickCount64"); } chk_done = 1; } - time_ms = proc != NULL ? proc() : (ULONGLONG)GetTickCount(); + if (proc_perf != NULL) { + LARGE_INTEGER li; + if (proc_perf(&li)) { + tp->tv_sec = (time_t)(li.QuadPart / perf_freq); + tp->tv_nsec = (long)(li.QuadPart % perf_freq * 1000000000 / perf_freq); + assert(tp->tv_nsec < 1000000000); + return 0; + } + } + time_ms = proc_tick != NULL ? proc_tick() : (ULONGLONG)GetTickCount(); tp->tv_sec = (time_t)(time_ms / 1000); tp->tv_nsec = (long)(time_ms % 1000) * 1000000; return 0; @@ -662,6 +683,12 @@ void swap_bytes(void * buf, size_t size) { #if defined(_WIN32) || defined(__CYGWIN__) +#ifdef _MSC_VER +# pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union (in winternl.h) */ +# include <winternl.h> +#else +# include <ntdef.h> +#endif #if USE_locale # include <locale.h> #endif @@ -692,8 +719,9 @@ const char * get_os_name(void) { if (info.wProductType == VER_NT_WORKSTATION) return "Windows 7"; return "Windows Server 2008 R2"; case 2: - if (info.wProductType == VER_NT_WORKSTATION) return "Windows 8"; - return "Windows Server 2012"; + /* Starting with Windows 8.1, GetVersionEx returns same version number, + * which is retrieved from the application manifest, or 6.2 by default. */ + return "Windows"; } } snprintf(str, sizeof(str), "Windows %d.%d", (int)info.dwMajorVersion, (int)info.dwMinorVersion); @@ -733,11 +761,69 @@ const char * get_user_name(void) { return a_buf; } +#ifndef BCRYPT_RNG_ALGORITHM +# define BCRYPT_RNG_ALGORITHM L"RNG" +#endif +#ifndef PROV_RSA_FULL +# define PROV_RSA_FULL 1 +#endif + +static PVOID crypt_handle = NULL; +typedef NTSTATUS(FAR WINAPI * BCryptRNGProcType)(PVOID, PUCHAR, ULONG, ULONG); +typedef BOOL(FAR WINAPI * WinCryptRNGProcType)(PVOID, DWORD, BYTE *); +static BCryptRNGProcType bcrypt_rng_proc = NULL; +static WinCryptRNGProcType wincrypt_rng_proc = NULL; + +uint32_t rand32(void) { + uint32_t buf = 0; + if (bcrypt_rng_proc) { + if (bcrypt_rng_proc(crypt_handle, (PUCHAR)&buf, sizeof(buf), 0) < 0) { + fprintf(stderr, "Couldn't access BCRYPT.\n"); + exit(1); + } + return buf; + } + if (wincrypt_rng_proc) { + if (wincrypt_rng_proc(crypt_handle, sizeof(buf), (BYTE *)&buf) < 0) { + fprintf(stderr, "Couldn't access WINCRYPT.\n"); + exit(1); + } + return buf; + } + fprintf(stderr, "Couldn't access random number generator.\n"); + exit(1); +} + void ini_mdep(void) { WORD wVersionRequested = MAKEWORD(1, 1); WSADATA wsaData; int err; + if (crypt_handle == NULL) { + HMODULE bcrypt_dll = LoadLibrarySystem32("Bcrypt.dll"); + if (bcrypt_dll != NULL) { + typedef NTSTATUS(FAR WINAPI * ProcType)(PVOID *, LPCWSTR, LPCWSTR, ULONG); + ProcType proc = (ProcType)GetProcAddress(bcrypt_dll, "BCryptOpenAlgorithmProvider"); + bcrypt_rng_proc = (BCryptRNGProcType)GetProcAddress(bcrypt_dll, "BCryptGenRandom"); + if (proc == NULL || bcrypt_rng_proc == NULL || proc(&crypt_handle, BCRYPT_RNG_ALGORITHM, NULL, 0) < 0) { + fprintf(stderr, "Couldn't access BCRYPT.\n"); + exit(1); + } + } + } + if (crypt_handle == NULL) { + HMODULE advapi_dll = LoadLibrarySystem32("Advapi32.dll"); + if (advapi_dll != NULL) { + typedef BOOL(FAR WINAPI * ProcType)(PVOID *, LPCWSTR, LPCWSTR, DWORD, DWORD); + ProcType proc = (ProcType)GetProcAddress(advapi_dll, "CryptAcquireContextA"); + wincrypt_rng_proc = (WinCryptRNGProcType)GetProcAddress(advapi_dll, "CryptGenRandom"); + if (proc == NULL || wincrypt_rng_proc == NULL || !proc(&crypt_handle, NULL, NULL, PROV_RSA_FULL, 0)) { + fprintf(stderr, "Couldn't call CryptAcquireContext.\n"); + exit(1); + } + } + } + #if USE_locale setlocale(LC_ALL, ""); #endif @@ -813,7 +899,15 @@ const char * get_user_name(void) { return NULL; } +uint32_t rand32(void) { + /* TODO: should we use randBytes() on vxWorks? */ + return rand(); +} + void ini_mdep(void) { + struct timespec time_now; + if (clock_gettime(CLOCK_REALTIME, &time_now)) check_error(errno); + srand((unsigned)time_now.tv_sec ^ (unsigned)time_now.tv_nsec); pthread_attr_init(&pthread_create_attr); #ifndef USE_DEFAULT_THREAD_STACK_SIZE pthread_attr_setstacksize(&pthread_create_attr, 0x8000); @@ -848,7 +942,15 @@ const char * get_user_name(void) { return NULL; } +uint32_t rand32(void) { + /* TODO: should we use random() on Symbian? */ + return rand(); +} + void ini_mdep(void) { + struct timespec time_now; + if (clock_gettime(CLOCK_REALTIME, &time_now)) check_error(errno); + srand((unsigned)time_now.tv_sec ^ (unsigned)time_now.tv_nsec); pthread_attr_init(&pthread_create_attr); } @@ -977,6 +1079,24 @@ int tkill(pid_t pid, int signal) { #endif } +uint32_t rand32(void) { + static int ini = 0; + static int crypt_handle = -1; + uint32_t buf = 0; + if (!ini) { + crypt_handle = open("/dev/urandom", O_RDONLY); + if (crypt_handle < 0) { + struct timespec time_now; + if (clock_gettime(CLOCK_REALTIME, &time_now)) check_error(errno); + srandom((unsigned)time_now.tv_sec ^ (unsigned)time_now.tv_nsec); + } + ini = 1; + } + if (crypt_handle < 0) return random(); + if (read(crypt_handle, &buf, sizeof(buf)) < 0) check_error(errno); + return buf; +} + void ini_mdep(void) { #if USE_locale setlocale(LC_ALL, ""); @@ -1314,12 +1434,6 @@ const char * loc_gai_strerror(int ecode) { #if defined(_WIN32) || defined(__CYGWIN__) # include <tlhelp32.h> -# ifdef _MSC_VER -# pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union (in winternl.h) */ -# include <winternl.h> -# else -# include <ntdef.h> -# endif # ifndef STATUS_INFO_LENGTH_MISMATCH # define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) # endif @@ -1876,15 +1990,12 @@ const char * create_uuid(void) { #else const char * create_uuid(void) { - static char buf[40]; struct timespec time_now; memset(&time_now, 0, sizeof(time_now)); if (clock_gettime(CLOCK_REALTIME, &time_now)) check_error(errno); - if (buf[0] == 0) srand((unsigned)time_now.tv_sec ^ (unsigned)time_now.tv_nsec); - snprintf(buf, sizeof(buf), "%08x-%04x-4%03x-8%03x-%04x%04x%04x", + return tmp_printf("%08x-%04x-4%03x-8%03x-%04x%04x%04x", (int)time_now.tv_sec & 0xffffffff, (int)(time_now.tv_nsec >> 13) & 0xffff, - rand() & 0xfff, rand() & 0xfff, rand() & 0xffff, rand() & 0xffff, rand() & 0xffff); - return buf; + rand32() & 0xfff, rand32() & 0xfff, rand32() & 0xffff, rand32() & 0xffff, rand32() & 0xffff); } #endif @@ -1902,7 +2013,7 @@ int tcf_set_thread_name(const char * name) { HANDLE thread; if (!init_done) { - HMODULE kernel_dll = LoadLibraryA("Kernel32.dll"); + HMODULE kernel_dll = LoadLibrarySystem32("Kernel32.dll"); if (kernel_dll != NULL) { set_td = (ProcType)GetProcAddress(kernel_dll, "SetThreadDescription"); if (set_td == NULL) { @@ -1929,7 +2040,8 @@ int tcf_set_thread_name(const char * name) { loc_free(w_name); return error; -#elif defined(_GNU_SOURCE) +#elif defined(_GNU_SOURCE) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 12)) + /* pthread_setname_np was added in glibc 2.12 */ return pthread_setname_np(pthread_self(), name); #else return 0; diff --git a/agent/tcf/framework/mdep.h b/agent/tcf/framework/mdep.h index f71751bb..f9da3f2f 100644 --- a/agent/tcf/framework/mdep.h +++ b/agent/tcf/framework/mdep.h @@ -161,14 +161,20 @@ typedef unsigned long pid_t; #endif #endif -#define CLOCK_REALTIME 1 -#define CLOCK_MONOTONIC 2 +#ifndef CLOCK_REALTIME +# define CLOCK_REALTIME 1 +#endif +#ifndef CLOCK_MONOTONIC +# define CLOCK_MONOTONIC 2 +#endif typedef int clockid_t; extern int clock_gettime(clockid_t clock_id, struct timespec * tp); extern void usleep(unsigned useconds); #define off_t __int64 -#define lseek _lseeki64 +#ifndef lseek +# define lseek _lseeki64 +#endif extern int truncate(const char * path, off_t size); extern int ftruncate(int f, off_t size); @@ -186,6 +192,12 @@ extern ssize_t pwrite(int fd, const void * buf, size_t size, off_t offset); #endif /* __CYGWIN__ */ +#if defined(LOAD_LIBRARY_SEARCH_SYSTEM32) +# define LoadLibrarySystem32(name) LoadLibraryExA(name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32) +#else +# define LoadLibrarySystem32(name) LoadLibraryA(name) +#endif + #elif defined(_WRS_KERNEL) /* VxWork kernel module */ @@ -414,7 +426,7 @@ extern size_t strlcat(char * dst, const char * src, size_t size); /* Swap bytes in a buffer - change value endianness */ extern void swap_bytes(void * buf, size_t size); -#if defined(__GNUC__) +#if defined(__GNUC__) && __GNUC__ >= 5 # define SWAP(x) do { \ switch(sizeof(x)) { \ case 8: x = __builtin_bswap64(x); break; \ @@ -445,6 +457,9 @@ extern const char * get_user_home(void); /* Get user name as known to the system */ extern const char * get_user_name(void); +/* Return 32-bit random number */ +extern uint32_t rand32(void); + /* Create new UUID - Universally Unique IDentifier */ extern const char * create_uuid(void); diff --git a/agent/tcf/framework/myalloc.c b/agent/tcf/framework/myalloc.c index 61f5ac84..3b4478b1 100644 --- a/agent/tcf/framework/myalloc.c +++ b/agent/tcf/framework/myalloc.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -48,6 +48,8 @@ static LINK tmp_alloc_list = TCF_LIST_INIT(tmp_alloc_list); static size_t tmp_alloc_size = 0; static int tmp_gc_posted = 0; +static char tmp_str_buf[0x10 * MEM_USAGE_FACTOR]; + static void gc_event(void * args) { tmp_gc_posted = 0; tmp_gc(); @@ -61,6 +63,14 @@ void tmp_gc(void) { else if (tmp_pool_avr > POOL_SIZE / 0x10) { tmp_pool_avr -= POOL_SIZE / 0x10000; } +#endif + while (!list_is_empty(&tmp_alloc_list)) { + LINK * l = tmp_alloc_list.next; + list_remove(l); + loc_free(l); + } + tmp_alloc_size = 0; +#if ENABLE_FastMemAlloc if (tmp_pool_max < tmp_pool_avr && tmp_pool_max < POOL_SIZE) { if (tmp_pool_max < POOL_SIZE / 0x10) tmp_pool_max = POOL_SIZE / 0x10; while (tmp_pool_max < tmp_pool_avr) tmp_pool_max *= 2; @@ -73,12 +83,6 @@ void tmp_gc(void) { } tmp_pool_pos = sizeof(LINK); #endif - while (!list_is_empty(&tmp_alloc_list)) { - LINK * l = tmp_alloc_list.next; - list_remove(l); - loc_free(l); - } - tmp_alloc_size = 0; } void * tmp_alloc(size_t size) { @@ -180,15 +184,25 @@ char * tmp_printf(const char * fmt, ...) { return buf; } +static int vsnprintf_apc(char * buf, size_t len, const char * fmt, va_list ap) { + int n; + /* Some implementations of vsnprintf destructively modifies the passed va_list */ + /* We need to use va_list multiple times, so make a copy */ + va_list apc; + va_copy(apc, ap); + n = vsnprintf(buf, len, fmt, apc); + va_end(apc); + return n; +} + char * tmp_vprintf(const char * fmt, va_list ap) { - char arr[0x100]; void * mem = NULL; - char * buf = arr; - size_t len = sizeof(arr); + char * buf = tmp_str_buf; + size_t len = sizeof(tmp_str_buf); int n; while (1) { - n = vsnprintf(buf, len, fmt, ap); + n = vsnprintf_apc(buf, len, fmt, ap); if (n < 0) { if (len > 0x1000) break; len *= 2; @@ -200,7 +214,7 @@ char * tmp_vprintf(const char * fmt, va_list ap) { mem = tmp_realloc(mem, len); buf = (char *)mem; } - if (buf == arr) buf = tmp_strdup(arr); + if (buf == tmp_str_buf) buf = tmp_strdup(tmp_str_buf); return buf; } @@ -285,14 +299,13 @@ char * loc_printf(const char * fmt, ...) { } char * loc_vprintf(const char * fmt, va_list ap) { - char arr[0x100]; void * mem = NULL; - char * buf = arr; - size_t len = sizeof(arr); + char * buf = tmp_str_buf; + size_t len = sizeof(tmp_str_buf); int n; while (1) { - n = vsnprintf(buf, len, fmt, ap); + n = vsnprintf_apc(buf, len, fmt, ap); if (n < 0) { if (len > 0x1000) break; len *= 2; @@ -304,6 +317,6 @@ char * loc_vprintf(const char * fmt, va_list ap) { mem = loc_realloc(mem, len); buf = (char *)mem; } - if (buf == arr) buf = loc_strdup(arr); + if (buf == tmp_str_buf) buf = loc_strdup(tmp_str_buf); return buf; } diff --git a/agent/tcf/framework/tcf.h b/agent/tcf/framework/tcf.h index 61c58dd8..26d3fd50 100644 --- a/agent/tcf/framework/tcf.h +++ b/agent/tcf/framework/tcf.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2023 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. @@ -17,7 +17,7 @@ #define D_tcf #define _TCF_VERSION_MAJOR 1 -#define _TCF_VERSION_MINOR 7 +#define _TCF_VERSION_MINOR 8 #define _TCF_VERSION (_TCF_VERSION_MAJOR * 100 + _TCF_VERSION_MINOR) #endif diff --git a/agent/tcf/framework/trace.c b/agent/tcf/framework/trace.c index bb1aa70e..be3ddbe6 100644 --- a/agent/tcf/framework/trace.c +++ b/agent/tcf/framework/trace.c @@ -56,7 +56,6 @@ struct trace_mode trace_mode_table[MAX_TRACE_MODES + 1] = { { LOG_PROXY, "proxy", "proxy state" }, { LOG_TCFLOG, "tcflog", "proxy traffic" }, { LOG_ELF, "elf", "ELF reader" }, - { LOG_LUA, "lua", "LUA interpreter" }, { LOG_STACK, "stack", "stack trace service" }, { LOG_PLUGIN, "plugin", "plugins" }, { LOG_SHUTDOWN, "shutdown", "shutdown of subsystems" }, @@ -182,6 +181,7 @@ int add_trace_mode(int mode, const char * name, const char * description) { void open_log_file(const char * log_name) { #if ENABLE_Trace + use_syslog = 0; if (log_name == NULL) { log_file = NULL; } diff --git a/agent/tcf/framework/trace.h b/agent/tcf/framework/trace.h index 1b3ca5df..8ada41d8 100644 --- a/agent/tcf/framework/trace.h +++ b/agent/tcf/framework/trace.h @@ -37,7 +37,6 @@ #define LOG_PROXY 0x200 #define LOG_TCFLOG 0x400 #define LOG_ELF 0x800 -#define LOG_LUA 0x1000 #define LOG_STACK 0x2000 #define LOG_PLUGIN 0x4000 #define LOG_SHUTDOWN 0x8000 diff --git a/agent/tcf/framework/waitpid.c b/agent/tcf/framework/waitpid.c index b7bd0708..3fe0a945 100644 --- a/agent/tcf/framework/waitpid.c +++ b/agent/tcf/framework/waitpid.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2009-2022 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. @@ -105,7 +105,7 @@ static void init(void) { semaphore = CreateSemaphore(NULL, 1, 1, NULL); } -void add_waitpid_process(int pid) { +void add_waitpid_process(pid_t pid) { HANDLE prs = NULL; WaitPIDThread * thread = threads; assert(listener_cnt > 0); @@ -133,7 +133,7 @@ void detach_waitpid_process(void) { #include <taskHookLib.h> typedef struct EventInfo { - UINT32 pid; + pid_t pid; SEM_ID signal; } EventInfo; @@ -153,7 +153,7 @@ static void task_delete_hook(WIND_TCB * tcb) { EventInfo info; VX_COUNTING_SEMAPHORE(signal_mem); info.signal = semCInitialize(signal_mem, SEM_Q_FIFO, 0); - info.pid = (UINT32)tcb; + info.pid = tcb; post_event(task_delete_event, &info); semTake(info.signal, WAIT_FOREVER); semTerminate(info.signal); @@ -165,7 +165,7 @@ static void init(void) { taskDeleteHookAdd((FUNCPTR)task_delete_hook); } -void add_waitpid_process(int pid) { +void add_waitpid_process(pid_t pid) { } void detach_waitpid_process(void) { @@ -236,7 +236,7 @@ static void waitpid_done(void * arg) { } } -void add_waitpid_process(int pid) { +void add_waitpid_process(pid_t pid) { AsyncReqInfo * req = (AsyncReqInfo *)loc_alloc_zero(sizeof(AsyncReqInfo)); assert(listener_cnt > 0); trace(LOG_WAITPID, "waitpid: add pid %d", pid); diff --git a/agent/tcf/framework/waitpid.h b/agent/tcf/framework/waitpid.h index c82ed6a7..5627c01e 100644 --- a/agent/tcf/framework/waitpid.h +++ b/agent/tcf/framework/waitpid.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2011 Wind River Systems, Inc. and others. + * Copyright (c) 2009-2022 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. @@ -24,11 +24,11 @@ #if (ENABLE_DebugContext && !ENABLE_ContextProxy) || SERVICE_Processes || SERVICE_Terminals -typedef void WaitPIDListener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args); +typedef void WaitPIDListener(pid_t pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args); extern void add_waitpid_listener(WaitPIDListener * listener, void * args); -extern void add_waitpid_process(int pid); +extern void add_waitpid_process(pid_t pid); extern void detach_waitpid_process(void); diff --git a/agent/tcf/http/http-tcf.c b/agent/tcf/http/http-tcf.c index 34504ba3..21f6b962 100644 --- a/agent/tcf/http/http-tcf.c +++ b/agent/tcf/http/http-tcf.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018-2019 Xilinx, Inc. and others. + * Copyright (c) 2018-2022 Xilinx, 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. @@ -711,7 +711,7 @@ static int get_page(const char * uri) { return 0; } -void http_connection_closed(OutputStream * out) { +static void http_connection_closed(OutputStream * out) { LINK * l; for (l = link_clients.next; l != &link_clients; l = l->next) { ClientData * cd = all2client(l); @@ -730,7 +730,7 @@ void http_connection_closed(OutputStream * out) { } ChannelServer * ini_http_tcf(int sock, PeerServer * ps) { - static HttpListener l = { get_page }; + static HttpListener l = { get_page, http_connection_closed }; assert(list_is_empty(&server.servlink)); add_http_listener(&l); server_sock = sock; diff --git a/agent/tcf/http/http-tcf.h b/agent/tcf/http/http-tcf.h index d15abe34..fbc751bb 100644 --- a/agent/tcf/http/http-tcf.h +++ b/agent/tcf/http/http-tcf.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Xilinx, Inc. and others. + * Copyright (c) 2018-2022 Xilinx, 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. @@ -24,7 +24,6 @@ #include <tcf/framework/channel.h> -extern void http_connection_closed(OutputStream * out); extern ChannelServer * ini_http_tcf(int sock, PeerServer * ps); #endif /* D_http_tcf */ diff --git a/agent/tcf/http/http.c b/agent/tcf/http/http.c index 37dfbc8c..66b5a90d 100644 --- a/agent/tcf/http/http.c +++ b/agent/tcf/http/http.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018-2019 Xilinx, Inc. and others. + * Copyright (c) 2018-2022 Xilinx, 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. @@ -26,7 +26,7 @@ #include <stdarg.h> #include <assert.h> #if defined(_WIN32) || defined(__CYGWIN__) -# include <ShlObj.h> +# include <shlobj.h> #endif #include <tcf/framework/trace.h> #include <tcf/framework/errors.h> @@ -144,9 +144,12 @@ static void clear_connection_state(HttpConnection * con) { } static void close_connection(HttpConnection * con) { + unsigned i; assert(!con->read_posted); assert(!con->write_posted); - http_connection_closed(&con->out.out); + for (i = 0; i < listener_cnt; i++) { + if (listener_arr[i]->closed) listener_arr[i]->closed(&con->out.out); + } clear_connection_state(con); closesocket(con->sock); list_remove(&con->link_all); @@ -295,11 +298,21 @@ static void http_send_done(void * x) { } static void send_reply(HttpConnection * con) { - unsigned i; current_con = con; create_byte_array_output_stream(&con->out); - for (i = listener_cnt; i > 0; i--) { - if (listener_arr[i - 1]->get_page(con->http_uri)) break; + if (con->http_method == NULL || con->http_uri == NULL) { + http_response_status(400, "BAD REQUEST"); + http_printf("Bad request: syntax error\n"); + } + else if (strcmp(con->http_method, "GET") != 0) { + http_response_status(400, "BAD REQUEST"); + http_printf("Bad request method: %s\n", con->http_method); + } + else { + unsigned i; + for (i = listener_cnt; i > 0; i--) { + if (listener_arr[i - 1]->get_page && listener_arr[i - 1]->get_page(con->http_uri)) break; + } } if (con->suspended) { current_con = NULL; diff --git a/agent/tcf/http/http.h b/agent/tcf/http/http.h index 6dd04e31..64166a91 100644 --- a/agent/tcf/http/http.h +++ b/agent/tcf/http/http.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018-2019 Xilinx, Inc. and others. + * Copyright (c) 2018-2022 Xilinx, 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. @@ -49,6 +49,7 @@ extern void http_close(void); typedef struct HttpListener { int (*get_page)(const char * uri); + void (*closed)(OutputStream * out); } HttpListener; extern void add_http_listener(HttpListener * l); diff --git a/agent/tcf/main/gdb-rsp.c b/agent/tcf/main/gdb-rsp.c index 5335deb2..9c4fcad6 100644 --- a/agent/tcf/main/gdb-rsp.c +++ b/agent/tcf/main/gdb-rsp.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016-2020 Xilinx, Inc. and others. + * Copyright (c) 2016-2022 Xilinx, 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. @@ -60,7 +60,7 @@ # define DEBUG_RSP 0 #endif -#define ID_ANY ~0u +#define ID_ALL ~0u typedef struct GdbServer { LINK link_a2s; @@ -78,7 +78,7 @@ typedef struct GdbClient { uint8_t * buf; AsyncReqInfo req; GdbServer * server; - ClientConnection client; + ClientConnection connection; int closed; /* Command packet */ @@ -161,7 +161,7 @@ typedef struct MonitorCommand { #define link_p2t(x) ((GdbThread *)((char *)(x) - offsetof(GdbThread, link_p2t))) #define link_p2b(x) ((GdbBreakpoint *)((char *)(x) - offsetof(GdbBreakpoint, link_p2b))) -#define client2gdb(c) ((GdbClient *)((char *)(c) - offsetof(GdbClient, client))) +#define client2gdb(c) ((GdbClient *)((char *)(c) - offsetof(GdbClient, connection))) static int ini_done = 0; static LINK link_a2s; @@ -321,9 +321,18 @@ static unsigned reg_name_hash(const char * name) { return h; } -static RegisterDefinition * find_register(GdbThread * t, GdbRegister * r) { +static RegisterDefinition * find_register_by_name(GdbThread * t, const char * name) { RegisterDefinition ** map = t->regs_nm_map; - unsigned n = 0; + unsigned n = reg_name_hash(name) & t->regs_nm_map_index_mask; + while (map[n] != NULL) { + if (strcmp(map[n]->name, name) == 0) return map[n]; + n = (n + 1) & t->regs_nm_map_index_mask; + } + return NULL; +} + +static RegisterDefinition * find_register(GdbThread * t, GdbRegister * r) { + RegisterDefinition * res = NULL; if (r->id >= 0) { RegisterDefinition * def = get_reg_definitions(t->ctx); @@ -334,9 +343,10 @@ static RegisterDefinition * find_register(GdbThread * t, GdbRegister * r) { } return NULL; } - if (map == NULL) { + if (t->regs_nm_map == NULL) { unsigned map_len = 0; unsigned map_len_p2 = 1; + RegisterDefinition ** map = NULL; RegisterDefinition * def = get_reg_definitions(t->ctx); if (def == NULL) return NULL; while (def->name != NULL) { @@ -356,12 +366,31 @@ static RegisterDefinition * find_register(GdbThread * t, GdbRegister * r) { } t->regs_nm_map = map; } - n = reg_name_hash(r->name) & t->regs_nm_map_index_mask; - while (map[n] != NULL) { - if (strcmp(map[n]->name, r->name) == 0) return map[n]; - n = (n + 1) & t->regs_nm_map_index_mask; + res = find_register_by_name(t, r->name); + if (res == NULL) { + const char * regs = get_regs(t->process->client); + /* Try alternative register names */ + if (regs == cpu_regs_gdb_i386 || regs == cpu_regs_gdb_x86_64) { + static const char * alt_names[] = { + "fctrl", "control", "fpcr", "cwd", NULL, + "fstat", "status", "fpsr", "swd", NULL, + "ftag", "tag", "fptag", "twd", NULL, + "fiseg", "fcs", NULL, + "fioff", "fip", NULL, + "foseg", "fos", NULL, + "fooff", "foo", NULL, + NULL + }; + unsigned i = 0; + for (; alt_names[i] != NULL && res == NULL; i++) { + int b = strcmp(alt_names[i++], r->name) == 0; + for (; alt_names[i] != NULL && res == NULL; i++) { + if (b) res = find_register_by_name(t, alt_names[i]); + } + } + } } - return NULL; + return res; } static int open_server(const char * port) { @@ -534,11 +563,11 @@ static void close_client(GdbClient * c) { c->closed = 1; unlock_threads(c); closesocket(c->req.u.sio.sock); - notify_client_disconnected(&c->client); + notify_client_disconnected(&c->connection); } } -static void dispose_client(ClientConnection * cc) { +static void dispose_connection(ClientConnection * cc) { GdbClient * c = client2gdb(cc); GdbServer * s = c->server; @@ -817,28 +846,41 @@ static void get_cmd_ptid(GdbClient * c, char ** pp, unsigned * res_pid, unsigned s++; } tid = get_cmd_uint(c, &s); + /* + ID is a positive number with target-specific interpretation formatted as a big-endian hex string, + or literal '-1' to indicate all processes or threads (respectively), + or '0' to indicate an arbitrary process (keep current selection if any) + */ if (neg_pid) { - pid = ID_ANY; + pid = ID_ALL; } else if (pid == 0) { - LINK * l; - pid = 0; - for (l = c->link_c2p.next; l != &c->link_c2p; l = l->next) { - GdbProcess * p = link_c2p(l); - if (p->attached) { - pid = p->pid; - break; + if (find_process_pid(c, *res_pid)) { + pid = *res_pid; + } + else { + LINK * l; + for (l = c->link_c2p.next; l != &c->link_c2p; l = l->next) { + GdbProcess * p = link_c2p(l); + if (p->attached) { + pid = p->pid; + break; + } } } } - if (neg_tid || pid == ID_ANY) { - tid = ID_ANY; + if (neg_tid || pid == ID_ALL) { + tid = ID_ALL; } else if (tid == 0) { - GdbProcess * p = find_process_pid(c, pid); - tid = 0; - if (p != NULL && !list_is_empty(&p->link_p2t)) { - tid = link_p2t(p->link_p2t.next)->tid; + if (find_thread(c, pid, *res_tid)) { + tid = *res_tid; + } + else { + GdbProcess * p = find_process_pid(c, pid); + if (p != NULL && !list_is_empty(&p->link_p2t)) { + tid = link_p2t(p->link_p2t.next)->tid; + } } } *pp = s; @@ -1409,7 +1451,7 @@ static int handle_v_command(GdbClient * c) { s++; get_cmd_ptid(c, &s, &c->cur_g_pid, &c->cur_g_tid); } - if (c->cur_g_tid == ID_ANY) { + if (c->cur_g_tid == ID_ALL) { GdbProcess * p = find_process_pid(c, c->cur_g_pid); switch (mode) { case 'c': @@ -1774,7 +1816,7 @@ static void accept_done(void * args) { c->req.u.sio.flags = 0; list_init(&c->link_c2p); list_add_last(&c->link_s2c, &s->link_s2c); - c->client.dispose = dispose_client; + c->connection.dispose = dispose_connection; for (l = context_root.next; l != &context_root; l = l->next) { Context * ctx = ctxl2ctxp(l); @@ -1787,7 +1829,7 @@ static void accept_done(void * args) { } } - notify_client_connected(&c->client); + notify_client_connected(&c->connection); async_req_post(&s->req); if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)) < 0) { diff --git a/agent/tcf/main/logfilter.c b/agent/tcf/main/logfilter.c index 2ad42a8c..01123c9d 100644 --- a/agent/tcf/main/logfilter.c +++ b/agent/tcf/main/logfilter.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Wind River Systems, Inc. and others. + * Copyright (c) 2014-2022 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. @@ -201,10 +201,10 @@ int filter_is_log_filtered(Channel * src, Channel * dst, int argc, /* Need to store the token and propagate truncation size * for reply. */ - TokenFilter * tf = (TokenFilter *)loc_alloc_zero( - sizeof(TokenFilter) + strlen(argv[1])); + const size_t len = strlen(argv[1]); + TokenFilter * tf = (TokenFilter *)loc_alloc_zero(sizeof(TokenFilter) + len); tf->chan = src; - strcpy(tf->token, argv[1]); + memcpy(tf->token, argv[1], len); list_add_last(&tf->all, &token_filters); if (mf->flags & FILTER_LIMIT_REPLY) { tf->limit = mf->limit; diff --git a/agent/tcf/main/main.c b/agent/tcf/main/main.c index bbcfd73f..d9aedc76 100644 --- a/agent/tcf/main/main.c +++ b/agent/tcf/main/main.c @@ -476,7 +476,7 @@ int main(int argc, char ** argv) { for (i = 0; i < url_cnt; i++) { if (ini_server(url_arr[i], proto, bcg) < 0) { - fprintf(stderr, "Cannot create listening port: %s\n", errno_to_str(errno)); + fprintf(stderr, "Cannot create listening port %s: %s\n", url_arr[i], errno_to_str(errno)); exit(1); } } diff --git a/agent/tcf/main/main_lua.c b/agent/tcf/main/main_lua.c index 95ff7aa0..55545093 100644 --- a/agent/tcf/main/main_lua.c +++ b/agent/tcf/main/main_lua.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2017 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2020 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. @@ -51,7 +51,8 @@ extern "C" { #include <tcf/main/framework.h> static const char * progname; -static lua_State *luastate; +static lua_State * luastate; +static int LOG_LUA = 0; struct luaref { int ref; @@ -1418,6 +1419,7 @@ int main(int argc, char ** argv) { #else + LOG_LUA = add_trace_mode(0, "lua", "LUA interpreter"); progname = argv[0]; /* Parse arguments */ diff --git a/agent/tcf/main/tcf-agent.spec b/agent/tcf/main/tcf-agent.spec index 5166b4d2..e8396bf3 100644 --- a/agent/tcf/main/tcf-agent.spec +++ b/agent/tcf/main/tcf-agent.spec @@ -1,5 +1,5 @@ %define name tcf-agent -%define version 1.7.0 +%define version 1.8.0 %define release 1.%(bin/get-os-tag) %define make_options CONF=Release PATH_Plugins=/etc/tcf/plugins diff --git a/agent/tcf/services/breakpoints.c b/agent/tcf/services/breakpoints.c index a4ba8738..61a07131 100644 --- a/agent/tcf/services/breakpoints.c +++ b/agent/tcf/services/breakpoints.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2023 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. @@ -54,6 +54,8 @@ # define ENABLE_SkipPrologueWhenPlanting 0 #endif +#define MAX_WP_SIZE 0x10000 + typedef struct BreakpointRef BreakpointRef; typedef struct InstructionRef InstructionRef; typedef struct BreakInstruction BreakInstruction; @@ -156,6 +158,10 @@ struct BreakInstruction { size_t bp_size; /* Size of breakpoint instruction */ Context * ph_ctx; ContextAddress ph_addr; + unsigned bit_offs; + unsigned bit_size; + void * bit_value; + void * bit_next; }; struct EvaluationArgs { @@ -170,6 +176,7 @@ struct ConditionEvaluationRequest { BreakInstruction * bi; int condition_ok; int triggered; + int canceled; }; struct LocationEvaluationRequest { @@ -282,11 +289,13 @@ static unsigned id2bp_hash(const char * id) { } static unsigned get_bp_access_types(BreakpointInfo * bp, int virtual_addr) { + /* Return breakpoint instruction access types for given breakpoint */ char * type = bp->type; unsigned access_types = bp->access_mode; if (access_types == 0 && (bp->file != NULL || bp->location != NULL)) access_types |= CTX_BP_ACCESS_INSTRUCTION; if (virtual_addr && type != NULL && strcmp(type, "Software") == 0) access_types |= CTX_BP_ACCESS_SOFTWARE; if (virtual_addr) access_types |= CTX_BP_ACCESS_VIRTUAL; + access_types &= ~CTX_BP_ACCESS_CHANGE; /* Handled by the service */ return access_types; } @@ -520,6 +529,8 @@ static void free_instruction(BreakInstruction * bi) { release_error_report(bi->planting_error); release_error_report(bi->condition_error); loc_free(bi->bp_encoding); + loc_free(bi->bit_value); + loc_free(bi->bit_next); loc_free(bi->refs); loc_free(bi); } @@ -554,6 +565,8 @@ static void flush_instructions(void) { list_init(&lst); + assert(list_is_empty(&evaluations_active)); + /* Validate references */ l = instructions.next; while (l != &instructions) { @@ -597,6 +610,7 @@ static void flush_instructions(void) { /* Hardware resource might be available now, try to re-plant */ list_add_last(&bi->link_lst, &lst); } + if (bi->bit_value != NULL) memcpy(bi->bit_value, bi->bit_next, bi->cb.length); } /* Unplant breakpoints */ @@ -1063,6 +1077,7 @@ static void line_offs_check(CodeArea * area, void * x) { #endif static void verify_line_offset(BreakInstruction * bi, InstructionRef * ref) { +#if ENABLE_LineNumbers ref->line_offs_error = 0; if (bi->virtual_addr && (bi->cb.access_types & CTX_BP_ACCESS_INSTRUCTION) != 0) { LineOffsCheckArgs args; @@ -1081,6 +1096,7 @@ static void verify_line_offset(BreakInstruction * bi, InstructionRef * ref) { } } } +#endif } static void get_bp_opcodes(void) { @@ -1243,8 +1259,8 @@ static BreakInstruction * address_expression_error(Context * ctx, BreakpointInfo return link_breakpoint_instruction(bp, ctx, 0, 0, NULL, 0, 0, rp); } -static void plant_breakpoint(Context * ctx, BreakpointInfo * bp, ContextAddress addr, ContextAddress size) { - link_breakpoint_instruction(bp, ctx, addr, size, ctx, 1, addr, NULL); +static BreakInstruction * plant_breakpoint(Context * ctx, BreakpointInfo * bp, ContextAddress addr, ContextAddress size) { + return link_breakpoint_instruction(bp, ctx, addr, size, ctx, 1, addr, NULL); } static BreakInstruction ** plant_at_canonical_address(BreakInstruction * v_bi) { @@ -1293,7 +1309,8 @@ static ConditionEvaluationRequest * add_condition_evaluation_request( assert(ctx->stopped_by_bp || ctx->stopped_by_cb); for (i = 0; i < req->bp_cnt; i++) { - if (req->bp_arr[i].ctx == ctx && req->bp_arr[i].bp == bp && req->bp_arr[i].bi == bi) return NULL; + c = req->bp_arr + i; + if (c->ctx == ctx && c->bp == bp && c->bi == bi && !c->canceled) return NULL; } if (req->bp_max <= req->bp_cnt) { @@ -1306,6 +1323,7 @@ static ConditionEvaluationRequest * add_condition_evaluation_request( c->bi = bi; c->condition_ok = 0; c->triggered = 0; + c->canceled = 0; return c; } @@ -1633,14 +1651,31 @@ static int skip_function_prologue(Context * ctx, Symbol * sym, ContextAddress * static void plant_at_address_expression(Context * ctx, ContextAddress ip, BreakpointInfo * bp) { ContextAddress addr = 0; ContextAddress size = 1; + unsigned bit_offs = 0; + unsigned bit_size = 0; + void * bit_value = NULL; + int read_bit_value = 0; int error = 0; #if ENABLE_Expressions Value v; - memset (&v, 0, sizeof (Value)); + memset(&v, 0, sizeof(Value)); - if (evaluate_expression(ctx, STACK_NO_FRAME, ip, bp->location, 1, &v) < 0) error = errno; - if (!error && value_to_address(&v, &addr) < 0) error = errno; + if (evaluate_expression(ctx, STACK_NO_FRAME, ip, bp->location, 0, &v) < 0) { + error = errno; + } + else if ((bp->access_mode & (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_DATA_WRITE)) != 0 && + v.sym_list == NULL && v.loc != NULL && v.loc->pieces_cnt == 1 && + v.loc->pieces->implicit_pointer == 1 && v.loc->pieces->optimized_away == 0 && + v.loc->pieces->reg == NULL && v.loc->pieces->value == NULL) { + /* Special case: bitfield watchpoint */ + addr = v.loc->pieces->addr; + bit_offs = v.loc->pieces->bit_offs; + bit_size = v.loc->pieces->bit_size; + } + else if (value_to_address(&v, &addr) < 0) { + error = errno; + } #if ENABLE_Symbols if (!error && v.sym != NULL) { SymbolProperties props; @@ -1658,6 +1693,18 @@ static void plant_at_address_expression(Context * ctx, ContextAddress ip, Breakp if (bp->access_size > 0) { size = bp->access_size; } + else if (bit_size > 0) { + unsigned i; + for (i = 0; i <= 24; i++) { + size = (ContextAddress)1 << i; + if ((addr & ~(size - 1)) + size >= addr + (bit_offs + bit_size + 7) / 8) break; + } + bit_offs += (unsigned)(addr & (size - 1)) * 8; + addr &= ~(size - 1); + if ((bp->access_mode & CTX_BP_ACCESS_DATA_READ) == 0) { + read_bit_value = 1; + } + } else if (bp->access_mode & (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_DATA_WRITE)) { size = context_word_size(ctx); #if ENABLE_Symbols @@ -1673,11 +1720,39 @@ static void plant_at_address_expression(Context * ctx, ContextAddress ip, Breakp } #endif } + if ((bp->access_mode & (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_DATA_WRITE)) != 0 && (bp->access_mode & CTX_BP_ACCESS_CHANGE) != 0) { + read_bit_value = 1; + } + if (!error && size == 0) error = set_errno(ERR_OTHER, "Invalid breakpoint size: 0"); + if (!error && read_bit_value) { + if (size > MAX_WP_SIZE) { + error = set_fmt_errno(ERR_BUFFER_OVERFLOW, "Too large watchpoint size: > 0x%x", MAX_WP_SIZE); + } + else { + bit_value = tmp_alloc_zero(size); + if (!error && context_read_mem(ctx, addr, bit_value, size) < 0) error = errno; + } + } if (error) { address_expression_error(ctx, bp, error); } else { - plant_breakpoint(ctx, bp, addr, size); + BreakInstruction * bi = plant_breakpoint(ctx, bp, addr, size); + assert(bi->cb.length == size); + bi->bit_offs = bit_offs; + bi->bit_size = bit_size; + if (bi->bit_value == NULL && bit_value != NULL) { + bi->bit_value = loc_alloc(size); + bi->bit_next = loc_alloc(size); + memcpy(bi->bit_value, bit_value, size); + memcpy(bi->bit_next, bit_value, size); + } + else if (bi->bit_value != NULL && bit_value == NULL) { + loc_free(bi->bit_value); + loc_free(bi->bit_next); + bi->bit_value = NULL; + bi->bit_next = NULL; + } #if ENABLE_Symbols /* If the expression returns multiple symbols, plant multiple breakpoints */ if (v.sym_list != NULL) { @@ -1837,6 +1912,7 @@ static void evaluate_condition(void * x) { BreakpointInfo * bp = ce->bp; BreakInstruction * bi = ce->bi; ErrorReport * condition_error = NULL; + int condition_ok = 0; assert(req != NULL); assert(req->bp_cnt > 0); @@ -1844,35 +1920,55 @@ static void evaluate_condition(void * x) { assert(cache_enter_cnt > 0); assert(args->bp == ce->bp); - if (!is_disabled(bp)) { + if (!ce->canceled && !is_disabled(bp)) { + int error = 0; Context * ctx = ce->ctx; assert(ctx->stopped); assert(ctx->stopped_by_bp || ctx->stopped_by_cb); - if (check_context_ids_condition(bp, ctx)) { - if (bp->condition != NULL) { + if (check_context_ids_condition(bp, ctx)) condition_ok = 1; + if (condition_ok && bp->condition != NULL) { #if ENABLE_Expressions - Value v; - int b = 0; - if (evaluate_expression(ctx, STACK_TOP_FRAME, 0, bp->condition, 1, &v) < 0 || - (v.size > 0 && value_to_boolean(&v, &b) < 0)) { - int error = errno; - Channel * c = cache_channel(); - if (c == NULL || !is_channel_closed(c)) { - condition_error = get_error_report(error); - ce->condition_ok = 1; - } - } - else if (b) { - ce->condition_ok = 1; - } + Value v; + if (evaluate_expression(ctx, STACK_TOP_FRAME, 0, bp->condition, 1, &v) < 0 || + (v.size > 0 && value_to_boolean(&v, &condition_ok) < 0)) { + error = errno; + } #endif + } + if (condition_ok && bi->bit_value != NULL) { + unsigned size = (unsigned)bi->cb.length; + if (context_read_mem(ctx, bi->cb.address, bi->bit_next, size) < 0) { + error = errno; } else { - ce->condition_ok = 1; + int changed = 0; + if (bi->bit_size == 0) { + changed = memcmp(bi->bit_value, bi->bit_next, size) != 0; + } + else { + unsigned i; + for (i = bi->bit_offs; i < bi->bit_offs + bi->bit_size; i++) { + uint8_t v0 = ((uint8_t *)bi->bit_value)[i / 8]; + uint8_t v1 = ((uint8_t *)bi->bit_next)[i / 8]; + if ((v0 & (1 << (i % 8))) != (v1 & (1 << (i % 8)))) { + changed = 1; + break; + } + } + } + if (!changed) condition_ok = 0; + } + } + if (error) { + Channel * c = cache_channel(); + if (c == NULL || !is_channel_closed(c)) { + condition_error = get_error_report(error); + condition_ok = 1; } } } + if (condition_ok) ce->condition_ok = 1; if (cache_miss_count() > 0 || compare_error_reports(bi->condition_error, condition_error)) { release_error_report(condition_error); } @@ -1903,7 +1999,7 @@ static void evaluate_bp_location(void * x) { bp_location_error = errno; } else if (bp_line_cnt == 0) { - bp_location_error = set_errno(ERR_OTHER, "Unresolved source line information"); + bp_location_error = set_errno(ERR_OTHER, "No debug information for this source line, check your compiler options"); } else if (bp_stmt_cnt == 0) { unsigned i; @@ -2003,11 +2099,7 @@ static void replant_breakpoints_cache_client(void * args) { assert(cache_enter_cnt >= 0); if (cache_enter_cnt == 0) { done_all_evaluations(); - - assert(list_is_empty(&evaluations_active)); - if (list_is_empty(&evaluations_posted)) { - flush_instructions(); - } + flush_instructions(); if (!list_is_empty(&evaluations_posted)) { post_event(event_replant_breakpoints, (void *)++generation_posted); @@ -2025,6 +2117,7 @@ static void replant_breakpoints_cache_client(void * args) { static void event_replant_breakpoints(void * arg) { LINK * q; + assert(!is_safe_event()); assert(!list_is_empty(&evaluations_posted)); if ((uintptr_t)arg != generation_posted) return; if (cache_enter_cnt > 0) return; @@ -2037,6 +2130,7 @@ static void event_replant_breakpoints(void * arg) { req->loc_active = req->loc_posted; memset(&req->loc_posted, 0, sizeof(LocationEvaluationRequest)); assert(list_is_empty(&req->link_active)); + post_safe_event(req->ctx, NULL, NULL); list_add_last(&req->link_active, &evaluations_active); list_remove(&req->link_posted); cache_enter_cnt++; @@ -2991,11 +3085,11 @@ void evaluate_breakpoint(Context * ctx) { if (need_to_post) continue; assert(bi->valid); if (is_disabled(bp)) continue; + if (!check_context_ids_condition(bp, ctx)) continue; if (bp->condition != NULL || bp->stop_group != NULL || bp->temporary) { need_to_post = 1; continue; } - if (!check_context_ids_condition(bp, ctx)) continue; c->condition_ok = 1; } } @@ -3014,11 +3108,11 @@ void evaluate_breakpoint(Context * ctx) { if (need_to_post) continue; assert(bi->valid); if (is_disabled(bp)) continue; - if (bp->condition != NULL || bp->stop_group != NULL || bp->temporary) { + if (!check_context_ids_condition(bp, ctx)) continue; + if (bp->condition != NULL || bp->stop_group != NULL || bp->temporary || bi->bit_value) { need_to_post = 1; continue; } - if (!check_context_ids_condition(bp, ctx)) continue; c->condition_ok = 1; } } @@ -3217,6 +3311,32 @@ static void event_context_created(Context * ctx, void * args) { list_init(&EXT(ctx)->link_hit_count); } +static void event_context_started(Context * ctx, void * args) { + LINK * l; + unsigned i; + + /* Need to cancel condition evaluation request + * if the context was resumed */ + + l = evaluations_active.next; + while (l != &evaluations_active) { + EvaluationRequest * req = link_active2erl(l); + for (i = 0; i < req->bp_cnt; i++) { + if (req->bp_arr[i].ctx == ctx) req->bp_arr[i].canceled = 1; + } + l = l->next; + } + + l = evaluations_posted.next; + while (l != &evaluations_posted) { + EvaluationRequest * req = link_posted2erl(l); + for (i = 0; i < req->bp_cnt; i++) { + if (req->bp_arr[i].ctx == ctx) req->bp_arr[i].canceled = 1; + } + l = l->next; + } +} + static void event_context_changed(Context * ctx, void * args) { if (ctx->mem_access && context_get_group(ctx, CONTEXT_GROUP_PROCESS) == ctx) { /* If the context is a memory space, we need to update @@ -3326,7 +3446,7 @@ void ini_breakpoints_service(Protocol * proto, TCFBroadcastGroup * bcg) { event_context_created, event_context_exited, NULL, - NULL, + event_context_started, event_context_changed, event_context_disposed }; diff --git a/agent/tcf/services/breakpoints.h b/agent/tcf/services/breakpoints.h index b50d8c9d..70fbfd4e 100644 --- a/agent/tcf/services/breakpoints.h +++ b/agent/tcf/services/breakpoints.h @@ -169,10 +169,18 @@ extern int is_skipping_breakpoint(Context * ctx); /* Return 1 if break instruction is planted at given address in the context memory */ extern int is_breakpoint_address(Context * ctx, ContextAddress address); -/* Clone all planted breakpoints when a process forks */ +/* + * Notify fork(): clone planted software breakpoints when a process forks. + * The process clone inherits memory contents of the original process, + * so software breakpoints are also cloned and the Breakpoints service needs to update the list of planted breakpoints. + */ extern void clone_breakpoints_on_process_fork(Context * parent, Context * child); -/* Invalidate all planted breakpoints when a process calls exec() */ +/* + * Notify exec(): invalidate planted software breakpoints when a process calls exec(). + * exec() replaces memory contents of the original process with something else, + * so software breakpoints are destroyed and the Breakpoints service needs to remove them from the list of planted breakpoints. + */ extern void invalidate_breakpoints_on_process_exec(Context * prs); /* diff --git a/agent/tcf/services/disassembly.c b/agent/tcf/services/disassembly.c index 903632c3..a9ee66c1 100644 --- a/agent/tcf/services/disassembly.c +++ b/agent/tcf/services/disassembly.c @@ -426,7 +426,7 @@ static void disassemble_cache_client(void * x) { else { mem_size = (size_t)(buf_size + MAX_INSTRUCTION_SIZE); } - /* Continue after unredable range */ + /* Continue after unreadable range */ error = 0; } } diff --git a/agent/tcf/services/dprintf.c b/agent/tcf/services/dprintf.c index 9f3e105e..2d7c6575 100644 --- a/agent/tcf/services/dprintf.c +++ b/agent/tcf/services/dprintf.c @@ -370,6 +370,7 @@ static void channel_close_listener(Channel * c) { } static void function_callback(int mode, Value * v, Value * args, unsigned args_cnt) { + uint8_t b = 0; if (args_cnt == 0) { str_exception(ERR_INV_EXPRESSION, "$printf mush have at least one argument"); } @@ -379,7 +380,8 @@ static void function_callback(int mode, Value * v, Value * args, unsigned args_c if (mode == EXPRESSION_MODE_NORMAL) { dprintf_expression_ctx(v->ctx, (char *)args[0].value, args + 1, args_cnt - 1); } - set_value(v, NULL, 0, 0); + set_value(v, &b, 1, 0); + v->type_class = TYPE_CLASS_CARDINAL; } static int identifier_callback(Context * ctx, int frame, char * name, Value * v) { diff --git a/agent/tcf/services/dwarf.h b/agent/tcf/services/dwarf.h index 0e29c61a..6ab31286 100644 --- a/agent/tcf/services/dwarf.h +++ b/agent/tcf/services/dwarf.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1996-2018 Wind River Systems, Inc. and others. + * Copyright (c) 1996-2022 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. @@ -89,8 +89,13 @@ #define TAG_wrs_throw_breakpoint 0x4081 #define TAG_wrs_catch_breakpoint 0x4082 #define TAG_wrs_extern_subroutine 0x4083 +/* GNU extension https://gcc.gnu.org/wiki/TemplateParmsDwarf */ +#define TAG_GNU_template_parameter_pack 0x4107 +#define TAG_GNU_formal_parameter_pack 0x4108 +/**/ #define TAG_GNU_call_site 0x4109 #define TAG_GNU_call_site_parameter 0x410a +/**/ #define TAG_hi_user 0xffff #define CHILDREN_no 0x00 @@ -121,7 +126,25 @@ #define FORM_SEC_OFFSET 0x0017 /* v4 */ #define FORM_EXPRLOC 0x0018 /* v4 */ #define FORM_FLAG_PRESENT 0x0019 /* v4 */ +#define FORM_STRX 0x001a /* v5 */ +#define FORM_ADDRX 0x001b /* v5 */ +#define FORM_REF_SUP4 0x001c /* v5 */ +#define FORM_STRP_SUP 0x001d /* v5 */ +#define FORM_DATA16 0x001e /* v5 */ +#define FORM_LINE_STRP 0x001f /* v5 */ #define FORM_REF_SIG8 0x0020 /* v4 */ +#define FORM_IMPLICIT_CONST 0x0021 /* v5 */ +#define FORM_LOCLISTX 0x0022 /* v5 */ +#define FORM_RNGLISTX 0x0023 /* v5 */ +#define FORM_REF_SUP8 0x0024 /* v5 */ +#define FORM_STRX1 0x0025 /* v5 */ +#define FORM_STRX2 0x0026 /* v5 */ +#define FORM_STRX3 0x0027 /* v5 */ +#define FORM_STRX4 0x0028 /* v5 */ +#define FORM_ADDRX1 0x0029 /* v5 */ +#define FORM_ADDRX2 0x002a /* v5 */ +#define FORM_ADDRX3 0x002b /* v5 */ +#define FORM_ADDRX4 0x002c /* v5 */ /* * GNU "dwz -m" extension. @@ -231,6 +254,35 @@ #define AT_const_expr 0x006c /* v4 */ #define AT_enum_class 0x006d /* v4 */ #define AT_linkage_name 0x006e /* v4 */ +#define AT_string_length_bit_size 0x006f /* v5 */ +#define AT_string_length_byte_size 0x0070 /* v5 */ +#define AT_rank 0x0071 /* v5 */ +#define AT_str_offsets_base 0x0072 /* v5 */ +#define AT_addr_base 0x0073 /* v5 */ +#define AT_rnglists_base 0x0074 /* v5 */ +#define AT_dwo_name 0x0076 /* v5 */ +#define AT_reference 0x0077 /* v5 */ +#define AT_rvalue_reference 0x0078 /* v5 */ +#define AT_macros 0x0079 /* v5 */ +#define AT_call_all_calls 0x007a /* v5 */ +#define AT_call_all_source_calls 0x007b /* v5 */ +#define AT_call_all_tail_calls 0x007c /* v5 */ +#define AT_call_return_pc 0x007d /* v5 */ +#define AT_call_value 0x007e /* v5 */ +#define AT_call_origin 0x007f /* v5 */ +#define AT_call_parameter 0x0080 /* v5 */ +#define AT_call_pc 0x0081 /* v5 */ +#define AT_call_tail_call 0x0082 /* v5 */ +#define AT_call_target 0x0083 /* v5 */ +#define AT_call_target_clobbered 0x0084 /* v5 */ +#define AT_call_data_location 0x0085 /* v5 */ +#define AT_call_data_value 0x0086 /* v5 */ +#define AT_noreturn 0x0087 /* v5 */ +#define AT_alignment 0x0088 /* v5 */ +#define AT_export_symbols 0x0089 /* v5 */ +#define AT_deleted 0x008a /* v5 */ +#define AT_defaulted 0x008b /* v5 */ +#define AT_loclists_base 0x008c /* v5 */ #define AT_lo_user_v1 0x0200 #define AT_hi_user_v1 0x03ff #define AT_push_mask 0x0220 @@ -243,12 +295,15 @@ #define AT_wrs_options 0x2001 #define AT_MIPS_linkage_name 0x2007 #define AT_GNU_call_site_value 0x2111 +#define AT_GNU_locviews 0x2137 /* GNAT descriptive type extension. * See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type */ #define AT_GNAT_use_descriptive_type 0x2301 #define AT_GNAT_descriptive_type 0x2302 #define AT_hi_user_v2 0x3fff +/* Pseudo-attribute, used to indicate first pass over comp unit info */ +#define AT_read_base_offsets 0xffff #define OP_reg 0x01 /* v1 */ #define OP_basereg 0x02 /* v1 */ @@ -409,7 +464,16 @@ #define OP_bit_piece 0x9d #define OP_implicit_value 0x9e /* v4 */ #define OP_stack_value 0x9f /* v4 */ -#define OP_implicit_pointer 0xa0 +#define OP_implicit_pointer 0xa0 /* v4 */ +#define OP_addrx 0xa1 /* v5 */ +#define OP_constx 0xa2 /* v5 */ +#define OP_entry_value 0xa3 /* v5 */ +#define OP_const_type 0xa4 /* v5 */ +#define OP_regval_type 0xa5 /* v5 */ +#define OP_deref_type 0xa6 /* v5 */ +#define OP_xderef_type 0xa7 /* v5 */ +#define OP_convert 0xa8 /* v5 */ +#define OP_reinterpret 0xa9 /* v5 */ #define OP_lo_user 0xe0 #define OP_hi_user 0xff /* GCC extensions */ @@ -503,7 +567,29 @@ #define LANG_C99 0x0000000c /* v3 */ #define LANG_ADA95 0x0000000d /* v3 */ #define LANG_FORTRAN95 0x0000000e /* v3 */ -#define LANG_PLI 0x0000000f +#define LANG_PLI 0x0000000f /* v3 */ +#define LANG_ObjC 0x00000010 /* v3 */ +#define LANG_ObjC_plus_plus 0x00000011 /* v3 */ +#define LANG_UPC 0x00000012 /* v3 */ +#define LANG_D 0x00000013 /* v3 */ +#define LANG_Python 0x00000014 /* v4 */ +#define LANG_OpenCL 0x00000015 /* v5 */ +#define LANG_Go 0x00000016 /* v5 */ +#define LANG_Modula3 0x00000017 /* v5 */ +#define LANG_Haskell 0x00000018 /* v5 */ +#define LANG_C_plus_plus_03 0x00000019 /* v5 */ +#define LANG_C_plus_plus_11 0x0000001a /* v5 */ +#define LANG_OCaml 0x0000001b /* v5 */ +#define LANG_Rust 0x0000001c /* v5 */ +#define LANG_C11 0x0000001d /* v5 */ +#define LANG_Swift 0x0000001e /* v5 */ +#define LANG_Julia 0x0000001f /* v5 */ +#define LANG_Dylan 0x00000020 /* v5 */ +#define LANG_C_plus_plus_14 0x00000021 /* v5 */ +#define LANG_Fortran03 0x00000022 /* v5 */ +#define LANG_Fortran08 0x00000023 /* v5 */ +#define LANG_RenderScript 0x00000024 /* v5 */ +#define LANG_BLISS 0x00000025 /* v5 */ #define LANG_lo_user 0x00008000 #define LANG_hi_user 0x0000ffff @@ -647,3 +733,46 @@ #define DW_END_little 0x02 #define DW_END_lo_user 0x40 #define DW_END_hi_user 0xff + +/* New in DWARF Version 5 */ +#define DW_UT_compile 0x01 +#define DW_UT_type 0x02 +#define DW_UT_partial 0x03 +#define DW_UT_skeleton 0x04 +#define DW_UT_split_compile 0x05 +#define DW_UT_split_type 0x06 +#define DW_UT_lo_user 0x80 +#define DW_UT_hi_user 0xff + +/* Line number header entry format name Value */ +/* New in DWARF Version 5 */ +#define DW_LNCT_path 0x1 +#define DW_LNCT_directory_index 0x2 +#define DW_LNCT_timestamp 0x3 +#define DW_LNCT_size 0x4 +#define DW_LNCT_MD5 0x5 +#define DW_LNCT_lo_user 0x2000 +#define DW_LNCT_hi_user 0x3fff + +/* Location list entry encoding values */ +/* New in DWARF Version 5 */ +#define DW_LLE_end_of_list 0x00 +#define DW_LLE_base_addressx 0x01 +#define DW_LLE_startx_endx 0x02 +#define DW_LLE_startx_length 0x03 +#define DW_LLE_offset_pair 0x04 +#define DW_LLE_default_location 0x05 +#define DW_LLE_base_address 0x06 +#define DW_LLE_start_end 0x07 +#define DW_LLE_start_length 0x08 + +/* Range list entry encoding values */ +/* New in DWARF Version 5 */ +#define DW_RLE_end_of_list 0x00 +#define DW_RLE_base_addressx 0x01 +#define DW_RLE_startx_endx 0x02 +#define DW_RLE_startx_length 0x03 +#define DW_RLE_offset_pair 0x04 +#define DW_RLE_base_address 0x05 +#define DW_RLE_start_end 0x06 +#define DW_RLE_start_length 0x07 diff --git a/agent/tcf/services/dwarfcache.c b/agent/tcf/services/dwarfcache.c index 3e2db14b..d3e2cb5f 100644 --- a/agent/tcf/services/dwarfcache.c +++ b/agent/tcf/services/dwarfcache.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2023 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. @@ -253,7 +253,7 @@ static ObjectInfo * find_alt_object_info(ContextAddress ID) { for (i = 0; i < File->dwz_file->section_cnt; i++) { ELF_Section * section = File->dwz_file->sections + i; if (section->name != NULL && strcmp(section->name, ".debug_info") == 0) { - if (Info != NULL) str_exception(ERR_INV_DWARF, "More then one .debug_info section in DWZ file"); + if (Info != NULL) str_exception(ERR_INV_DWARF, "More than one .debug_info section in DWZ file"); Info = find_loaded_object(section, ID); } } @@ -530,10 +530,32 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { high_pc_offs = 0; if (Tag == TAG_compile_unit || Tag == TAG_partial_unit || Tag == TAG_type_unit) { CompUnit * Unit = add_comp_unit((ContextAddress)(sDebugSection->addr + dio_gEntryPos)); + ELF_Section * Section = dio_GetSection(); + U8_T Pos = dio_GetPos(); assert(sParentObject == NULL); Info = Unit->mObject; assert(Info->mTag == 0); sCompUnit = Unit; + if (sUnitDesc.mRngListsSection != NULL) { + /* Read header of Range List Table */ + if (sUnitDesc.mRngListsOffs < 8) str_exception(ERR_INV_DWARF, "Invalid AT_rnglists_base"); + dio_EnterSection(&sUnitDesc, sUnitDesc.mRngListsSection, sUnitDesc.mRngListsOffs - 8); + if (dio_ReadU2() != 5) str_exception(ERR_INV_DWARF, "Invalid version of .debug_rnglists section"); + if (dio_ReadU1() != sUnitDesc.mAddressSize) str_exception(ERR_INV_DWARF, "Invalid header of .debug_rnglists section"); + if (dio_ReadU1() != 0) str_exception(ERR_INV_DWARF, "Invalid header of .debug_rnglists section"); + sUnitDesc.mRngListsOffsetEntryCount = dio_ReadU4(); + dio_EnterSection(&sUnitDesc, Section, Pos); + } + if (sUnitDesc.mLocListsSection != NULL) { + /* Read header of Loc List Table */ + if (sUnitDesc.mLocListsOffs < 8) str_exception(ERR_INV_DWARF, "Invalid AT_loclists_base"); + dio_EnterSection(&sUnitDesc, sUnitDesc.mLocListsSection, sUnitDesc.mLocListsOffs - 8); + if (dio_ReadU2() != 5) str_exception(ERR_INV_DWARF, "Invalid version of .debug_loclists section"); + if (dio_ReadU1() != sUnitDesc.mAddressSize) str_exception(ERR_INV_DWARF, "Invalid header of .debug_loclists section"); + if (dio_ReadU1() != 0) str_exception(ERR_INV_DWARF, "Invalid header of .debug_loclists section"); + sUnitDesc.mLocListsOffsetEntryCount = dio_ReadU4(); + dio_EnterSection(&sUnitDesc, Section, Pos); + } } else { Info = add_object_info((ContextAddress)(sDebugSection->addr + dio_gEntryPos)); @@ -599,7 +621,11 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { case LANG_C: case LANG_C89: case LANG_C99: + case LANG_C11: case LANG_C_PLUS_PLUS: + case LANG_C_plus_plus_03: + case LANG_C_plus_plus_11: + case LANG_C_plus_plus_14: Info->mType->mName = "void"; break; } @@ -618,7 +644,11 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { case LANG_C: case LANG_C89: case LANG_C99: + case LANG_C11: case LANG_C_PLUS_PLUS: + case LANG_C_plus_plus_03: + case LANG_C_plus_plus_11: + case LANG_C_plus_plus_14: Info->mType->mName = "char"; break; } @@ -762,12 +792,14 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { if (dio_gFormData) Info->mFlags |= DOIF_optional; break; case AT_low_pc: + if (Tag == TAG_base_type || Tag == TAG_fund_type || Tag == TAG_index_range) break; dio_ChkAddr(Form); Info->u.mCode.mLowPC = (ContextAddress)dio_gFormData; if (dio_gFormSection) Info->u.mCode.mSection = dio_gFormSection; Info->mFlags |= DOIF_low_pc; break; case AT_high_pc: + if (Tag == TAG_base_type || Tag == TAG_fund_type || Tag == TAG_index_range) break; if (Info->mFlags & DOIF_ranges) break; if (Form != FORM_ADDR) { dio_ChkData(Form); @@ -779,7 +811,10 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { Info->u.mCode.mHighPC.mAddr = (ContextAddress)dio_gFormData; break; case AT_ranges: - dio_ChkData(Form); + if (Tag == TAG_base_type || Tag == TAG_fund_type || Tag == TAG_index_range) break; + if (Form != FORM_RNGLISTX) { + dio_ChkData(Form); + } Info->u.mCode.mHighPC.mRanges = dio_gFormData; Info->mFlags |= DOIF_ranges; break; @@ -787,6 +822,10 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { dio_ChkFlag(Form); if (dio_gFormData) Info->mFlags |= DOIF_external; break; + case AT_inline: + dio_ChkData(Form); + if (dio_gFormData & 1) Info->mFlags |= DOIF_inlined; + break; case AT_artificial: dio_ChkFlag(Form); if (dio_gFormData) Info->mFlags |= DOIF_artificial; @@ -832,19 +871,38 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { break; case AT_location: Info->mFlags |= DOIF_location; - if (Form == FORM_DATA4 || Form == FORM_DATA8 || Form == FORM_SEC_OFFSET || Tag == TAG_formal_parameter) { + if (Tag == TAG_formal_parameter) { + Info->mFlags |= DOIF_need_frame; + } + switch (Form) { + case FORM_DATA1: + case FORM_DATA2: + case FORM_DATA4: + case FORM_DATA8: + case FORM_DATA16: + case FORM_SEC_OFFSET: + case FORM_LOCLISTX: Info->mFlags |= DOIF_need_frame; + break; } break; case AT_data_location: - if (sCompUnit->mDesc.mVersion <= 1) { + if (sUnitDesc.mVersion <= 1) { /* AT_mangled */ Info->mFlags |= DOIF_mangled_name; break; } Info->mFlags |= DOIF_data_location; - if (Form == FORM_DATA4 || Form == FORM_DATA8 || Form == FORM_SEC_OFFSET) { + switch (Form) { + case FORM_DATA1: + case FORM_DATA2: + case FORM_DATA4: + case FORM_DATA8: + case FORM_DATA16: + case FORM_SEC_OFFSET: + case FORM_LOCLISTX: Info->mFlags |= DOIF_need_frame; + break; } break; case AT_string_length: @@ -857,10 +915,18 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { case AT_vtable_elem_location: case AT_upper_bound: case AT_lower_bound: - /* Note: FORM_DATA4, FORM_DATA8 and FORM_SEC_OFFSET are location lists. + /* Note: FORM_DATAn and FORM_SEC_OFFSET are location lists. * Location list needs PC, so we set DOIF_need_frame because of that */ - if (Form == FORM_DATA4 || Form == FORM_DATA8 || Form == FORM_SEC_OFFSET) { + switch (Form) { + case FORM_DATA1: + case FORM_DATA2: + case FORM_DATA4: + case FORM_DATA8: + case FORM_DATA16: + case FORM_SEC_OFFSET: + case FORM_LOCLISTX: Info->mFlags |= DOIF_need_frame; + break; } break; case AT_const_value: @@ -876,32 +942,7 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { Unit->mDir = (char *)dio_gFormDataAddr; break; case AT_stmt_list: - if (Form == FORM_ADDR || Form == FORM_SEC_OFFSET) { - Unit->mLineInfoOffs = dio_gFormData; - if (dio_gFormSection != NULL) { - Unit->mLineInfoOffs -= dio_gFormSection->addr; - Unit->mLineInfoSection = dio_gFormSection; - } - else { - unsigned idx; - ELF_File * file = Unit->mFile; - for (idx = 1; idx < file->section_cnt; idx++) { - ELF_Section * sec = file->sections + idx; - if (sec->size == 0) continue; - if (sec->name == NULL) continue; - if (sec->type == SHT_NOBITS) continue; - if (Unit->mLineInfoOffs >= sec->addr && Unit->mLineInfoOffs < sec->addr + sec->size && - strcmp(sec->name, sUnitDesc.mVersion <= 1 ? ".line" : ".debug_line") == 0) { - Unit->mLineInfoOffs -= sec->addr; - Unit->mLineInfoSection = sec; - break; - } - } - } - break; - } - dio_ChkData(Form); - Unit->mLineInfoOffs = dio_gFormData; + dio_ReadSectionPointer(Form, &Unit->mLineInfoSection, &Unit->mLineInfoOffs, sUnitDesc.mVersion <= 1 ? sCache->mDebugLineV1 : sCache->mDebugLineV2); break; case AT_base_types: Unit->mBaseTypes = add_comp_unit((ContextAddress)dio_gFormData); @@ -961,8 +1002,10 @@ static void read_object_refs(ELF_Section * Section) { while (pos < sObjRefsCnt) { ObjectReference ref = sObjRefs[pos++]; if (ref.obj != NULL) { - assert(ref.org->mTag != 0); - if (ref.org->mFlags & DOIF_load_mark) { + if (ref.org->mTag == 0) { + ref.obj->mFlags |= DOIF_inv_reference; + } + else if (ref.org->mFlags & DOIF_load_mark) { fwd = 1; } else { @@ -1036,41 +1079,198 @@ static void add_addr_range(ELF_Section * sec, CompUnit * unit, ContextAddress ad range->mUnit = unit; } -static void add_object_addr_ranges(ObjectInfo * info) { - CompUnit * unit = info->mCompUnit; - ContextAddress base = info->u.mCode.mLowPC; - assert(info->mFlags & DOIF_low_pc); - if (info->mFlags & DOIF_ranges) { - if (sCache->mDebugRanges != NULL) { - dio_EnterSection(&unit->mDesc, sCache->mDebugRanges, info->u.mCode.mHighPC.mRanges); +U8_T read_dwarf_addr_section(CompUnit * Unit, U4_T idx, ELF_Section ** Section) { + U8_T addr = 0; + U8_T pos = dio_GetPos(); + ELF_Section * sec = dio_GetSection(); + U8_T offs = idx * Unit->mDesc.mAddressSize + Unit->mDesc.mAddrInfoOffs; + if (Unit->mDesc.mAddrInfoSection == NULL) str_exception(ERR_INV_DWARF, "Missing AT_addr_base"); + dio_EnterSection(&Unit->mDesc, Unit->mDesc.mAddrInfoSection, offs); + addr = dio_ReadAddress(Section); + dio_EnterSection(&Unit->mDesc, sec, pos); + return addr; +} + +void start_dwarf_addr_ranges(ObjectInfo * Obj, ObjectAddressRange * Range) { + memset(Range, 0, sizeof(ObjectAddressRange)); + Range->mObject = Obj; + Range->mUnit = Obj->mCompUnit; + Range->mVersion = Range->mUnit->mDesc.mVersion; + if (Obj->mFlags & DOIF_ranges) { + DWARFCache * Cache = get_dwarf_cache(Range->mUnit->mFile); + Range->mBaseAddr = Range->mUnit->mObject->u.mCode.mLowPC; + if (Range->mVersion <= 4) { + if (Cache->mDebugRanges != NULL) { + dio_EnterSection(&Range->mUnit->mDesc, Cache->mDebugRanges, Obj->u.mCode.mHighPC.mRanges); + Range->mRngSection = Cache->mDebugRanges; + } + } + else if (Cache->mDebugRngLists) { + dio_EnterSection(&Range->mUnit->mDesc, Cache->mDebugRngLists, Obj->u.mCode.mHighPC.mRanges); + Range->mRngSection = Cache->mDebugRngLists; + } + Range->mDone = Range->mRngSection == NULL; + } +} + +int read_dwarf_addr_range(ObjectAddressRange * Range) { + if (Range->mDone) return 0; + if (Range->mObject->mFlags & DOIF_ranges) { + if (Range->mVersion <= 4) { + U8_T set_base = Range->mUnit->mDesc.mAddressSize < 8 ? ((U8_T)1 << Range->mUnit->mDesc.mAddressSize * 8) - 1 : ~(U8_T)0; for (;;) { - U8_T AddrMax = ~(U8_T)0; ELF_Section * sec_x = NULL; ELF_Section * sec_y = NULL; U8_T x = dio_ReadAddress(&sec_x); U8_T y = dio_ReadAddress(&sec_y); if (x == 0 && y == 0) break; - if (unit->mDesc.mAddressSize < 8) AddrMax = ((U8_T)1 << unit->mDesc.mAddressSize * 8) - 1; - if (x == AddrMax) { - base = (ContextAddress)y; + if (x == set_base) { + Range->mBaseAddr = (ContextAddress)y; + Range->mBaseSection = sec_y; + continue; } - else if (y > x) { - ELF_Section * sec = info->u.mCode.mSection; - if (sec == NULL) sec = unit->mTextSection; - x = base + x; - y = base + y; - if (sec_x != NULL) sec = sec_x; - else if (sec_y != NULL) sec = sec_y; - add_addr_range(sec, unit, (ContextAddress)x, (ContextAddress)(y - x)); + if (y > x) { + ELF_Section * sec = sec_x; + if (sec == NULL) sec = sec_y; + if (sec == NULL) sec = Range->mBaseSection; + if (sec == NULL) sec = Range->mObject->u.mCode.mSection; + if (sec == NULL) sec = Range->mUnit->mTextSection; + x = Range->mBaseAddr + x; + y = Range->mBaseAddr + y; + Range->mSection = sec; + Range->mAddr = (ContextAddress)x; + Range->mSize = (ContextAddress)(y - x); + return 1; } } - dio_ExitSection(); } + else { + for (;;) { + U1_T type = dio_ReadU1(); + if (type == DW_RLE_end_of_list) break; + switch (type) { + case DW_RLE_base_addressx: + Range->mBaseAddr = read_dwarf_addr_section(Range->mUnit, dio_ReadULEB128(), &Range->mBaseSection); + break; + case DW_RLE_startx_endx: + { + ELF_Section * x_sec = NULL; + ELF_Section * y_sec = NULL; + U8_T x = read_dwarf_addr_section(Range->mUnit, dio_ReadULEB128(), &x_sec); + U8_T y = read_dwarf_addr_section(Range->mUnit, dio_ReadULEB128(), &y_sec); + if (y > x) { + if (x_sec == NULL) x_sec = y_sec; + if (x_sec == NULL) x_sec = Range->mObject->u.mCode.mSection; + if (x_sec == NULL) x_sec = Range->mUnit->mTextSection; + Range->mSection = x_sec; + Range->mAddr = (ContextAddress)x; + Range->mSize = (ContextAddress)(y - x); + return 1; + } + break; + } + case DW_RLE_startx_length: + { + ELF_Section * x_sec = NULL; + U8_T x = read_dwarf_addr_section(Range->mUnit, dio_ReadULEB128(), &x_sec); + U8_T y = dio_ReadU8LEB128(); + if (y > 0) { + if (x_sec == NULL) x_sec = Range->mObject->u.mCode.mSection; + if (x_sec == NULL) x_sec = Range->mUnit->mTextSection; + Range->mSection = x_sec; + Range->mAddr = (ContextAddress)x; + Range->mSize = (ContextAddress)y; + return 1; + } + break; + } + case DW_RLE_offset_pair: + { + ELF_Section * x_sec = Range->mBaseSection; + U8_T x = Range->mBaseAddr + dio_ReadU8LEB128(); + U8_T y = Range->mBaseAddr + dio_ReadU8LEB128(); + if (y > x) { + if (x_sec == NULL) x_sec = Range->mObject->u.mCode.mSection; + if (x_sec == NULL) x_sec = Range->mUnit->mTextSection; + Range->mSection = x_sec; + Range->mAddr = (ContextAddress)x; + Range->mSize = (ContextAddress)(y - x); + return 1; + } + break; + } + case DW_RLE_base_address: + Range->mBaseAddr = dio_ReadAddress(&Range->mBaseSection); + break; + case DW_RLE_start_end: + { + ELF_Section * x_sec = NULL; + ELF_Section * y_sec = NULL; + U8_T x = dio_ReadAddress(&x_sec); + U8_T y = dio_ReadAddress(&y_sec); + if (y > x) { + if (x_sec == NULL) x_sec = y_sec; + if (x_sec == NULL) x_sec = Range->mObject->u.mCode.mSection; + if (x_sec == NULL) x_sec = Range->mUnit->mTextSection; + Range->mSection = x_sec; + Range->mAddr = (ContextAddress)x; + Range->mSize = (ContextAddress)(y - x); + return 1; + } + break; + } + case DW_RLE_start_length: + { + ELF_Section * x_sec = NULL; + U8_T x = dio_ReadAddress(&x_sec); + U8_T y = dio_ReadU8LEB128(); + if (y > 0) { + if (x_sec == NULL) x_sec = Range->mObject->u.mCode.mSection; + if (x_sec == NULL) x_sec = Range->mUnit->mTextSection; + Range->mSection = x_sec; + Range->mAddr = (ContextAddress)x; + Range->mSize = (ContextAddress)y; + return 1; + } + break; + } + default: + str_exception(ERR_OTHER, "Invalid .debug_rnglists section"); + break; + } + } + } + dio_ExitSection(); + Range->mDone = 1; + return 0; } - else if (info->u.mCode.mHighPC.mAddr > base) { - ELF_Section * sec = info->u.mCode.mSection; - if (sec == NULL) sec = unit->mTextSection; - add_addr_range(sec, unit, base, info->u.mCode.mHighPC.mAddr - base); + if ((Range->mObject->mFlags & DOIF_low_pc) && Range->mObject->u.mCode.mHighPC.mAddr > Range->mObject->u.mCode.mLowPC) { + ELF_Section * sec = Range->mObject->u.mCode.mSection; + if (sec == NULL) sec = Range->mUnit->mTextSection; + Range->mSection = sec; + Range->mAddr = Range->mObject->u.mCode.mLowPC; + Range->mSize = Range->mObject->u.mCode.mHighPC.mAddr - Range->mObject->u.mCode.mLowPC; + Range->mDone = 1; + return 1; + } + if ((Range->mObject->mFlags & DOIF_low_pc) && Range->mObject->mTag == TAG_GNU_call_site) { + ELF_Section * sec = Range->mObject->u.mCode.mSection; + if (sec == NULL) sec = Range->mUnit->mTextSection; + Range->mSection = sec; + Range->mAddr = Range->mObject->u.mCode.mLowPC; + Range->mSize = 1; + Range->mDone = 1; + return 1; + } + Range->mDone = 1; + return 0; +} + +static void add_object_addr_ranges(ObjectInfo * info) { + ObjectAddressRange range; + start_dwarf_addr_ranges(info, &range); + while (read_dwarf_addr_range(&range)) { + add_addr_range(range.mSection, range.mUnit, range.mAddr, range.mSize); } } @@ -1147,7 +1347,7 @@ static void load_addr_ranges(ELF_Section * debug_info) { for (idx = 1; idx < file->section_cnt; idx++) { ObjectInfo * info = sCache->mObjectHashTable[idx].mCompUnits; while (info != NULL) { - if (info->mFlags & DOIF_low_pc) add_object_addr_ranges(info); + if (info->mFlags & (DOIF_low_pc | DOIF_ranges)) add_object_addr_ranges(info); if ((info->mFlags & DOIF_aranges) == 0 && (info->mFlags & DOIF_ranges) == 0 && info->u.mCode.mHighPC.mAddr == 0) { /* Unit does not have PC ranges data. As a workaround, add line info ranges */ @@ -1169,13 +1369,13 @@ static void load_addr_ranges(ELF_Section * debug_info) { } } - { + if (!(info->mFlags & DOIF_low_pc) || (info->mFlags & DOIF_ranges)) { /* Workaround for GCC bug - certain ranges are missing in both ".debug_aranges" and the unit info. * Add address ranges of the underlying scopes. */ ObjectInfo * obj = info->mChildren; assert(info->mFlags & DOIF_children_loaded); while (obj != NULL) { - if (obj->mFlags & DOIF_low_pc) add_object_addr_ranges(obj); + if (obj->mFlags & (DOIF_low_pc | DOIF_ranges)) add_object_addr_ranges(obj); obj = obj->mSibling; } } @@ -1450,6 +1650,36 @@ static void load_debug_sections(void) { if (strcmp(sec->name, ".debug_types") == 0) { debug_types_size += sec->size; } + else if (strcmp(sec->name, ".line") == 0) { + sCache->mDebugLineV1 = sec; + } + else if (strcmp(sec->name, ".debug_line") == 0) { + sCache->mDebugLineV2 = sec; + } + else if (strcmp(sec->name, ".debug_loc") == 0) { + sCache->mDebugLoc = sec; + } + else if (strcmp(sec->name, ".debug_loclists") == 0) { + sCache->mDebugLocLists = sec; + } + else if (strcmp(sec->name, ".debug_rnglists") == 0) { + sCache->mDebugRngLists = sec; + } + else if (strcmp(sec->name, ".debug_ranges") == 0) { + sCache->mDebugRanges = sec; + } + else if (strcmp(sec->name, ".debug_frame") == 0) { + FrameInfoIndex * idx = (FrameInfoIndex *)loc_alloc_zero(sizeof(FrameInfoIndex)); + idx->mSection = sec; + idx->mNext = frame_info_d; + frame_info_d = idx; + } + else if (strcmp(sec->name, ".eh_frame") == 0) { + FrameInfoIndex * idx = (FrameInfoIndex *)loc_alloc_zero(sizeof(FrameInfoIndex)); + idx->mSection = sec; + idx->mNext = frame_info_e; + frame_info_e = idx; + } } if (debug_types_size > 0) { @@ -1490,37 +1720,6 @@ static void load_debug_sections(void) { } } - for (idx = 1; idx < file->section_cnt; idx++) { - ELF_Section * sec = file->sections + idx; - if (sec->size == 0) continue; - if (sec->name == NULL) continue; - if (sec->type == SHT_NOBITS) continue; - if (strcmp(sec->name, ".line") == 0) { - sCache->mDebugLineV1 = sec; - } - else if (strcmp(sec->name, ".debug_line") == 0) { - sCache->mDebugLineV2 = sec; - } - else if (strcmp(sec->name, ".debug_loc") == 0) { - sCache->mDebugLoc = sec; - } - else if (strcmp(sec->name, ".debug_ranges") == 0) { - sCache->mDebugRanges = sec; - } - else if (strcmp(sec->name, ".debug_frame") == 0) { - FrameInfoIndex * idx = (FrameInfoIndex *)loc_alloc_zero(sizeof(FrameInfoIndex)); - idx->mSection = sec; - idx->mNext = frame_info_d; - frame_info_d = idx; - } - else if (strcmp(sec->name, ".eh_frame") == 0) { - FrameInfoIndex * idx = (FrameInfoIndex *)loc_alloc_zero(sizeof(FrameInfoIndex)); - idx->mSection = sec; - idx->mNext = frame_info_e; - frame_info_e = idx; - } - } - while (frame_info_e != NULL) { FrameInfoIndex * idx = frame_info_e; frame_info_e = idx->mNext; @@ -1814,13 +2013,14 @@ void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T case FORM_DATA2 : case FORM_DATA4 : case FORM_DATA8 : + case FORM_DATA16 : case FORM_FLAG : case FORM_BLOCK1 : case FORM_BLOCK2 : case FORM_BLOCK4 : case FORM_BLOCK : case FORM_STRP : - case FORM_SEC_OFFSET: + case FORM_LINE_STRP : case FORM_EXPRLOC : case FORM_REF_SIG8 : case FORM_STRING : @@ -1830,6 +2030,7 @@ void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T break; case FORM_SDATA : case FORM_UDATA : + case FORM_IMPLICIT_CONST: Value->mValue = gop_gFormData; break; case FORM_ADDR : @@ -1837,6 +2038,10 @@ void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T Value->mValue = elf_map_to_run_time_address(Ctx, Obj->mCompUnit->mFile, gop_gFormSection, (ContextAddress)gop_gFormData); if (errno) str_exception(errno, "Cannot get object run-time address"); break; + case FORM_SEC_OFFSET: + case FORM_LOCLISTX : + Value->mValue = gop_gFormData; + break; default: if (Attr == AT_data_member_location && Obj->mTag == TAG_member && Obj->mParent->mTag == TAG_union_type) { Value->mForm = FORM_UDATA; @@ -1904,7 +2109,9 @@ void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T break; } } - exception(ERR_SYM_NOT_FOUND); + str_fmt_exception(ERR_SYM_NOT_FOUND, + "Cannot read symbol attribute 0x%02x at 0x%" PRIx64, + (unsigned)Attr, (U8_T)Obj->mID); } sCache = NULL; @@ -1931,6 +2138,7 @@ void read_and_evaluate_dwarf_object_property_with_args( case FORM_DATA8 : case FORM_SDATA : case FORM_UDATA : + case FORM_IMPLICIT_CONST: if (ArgsCnt == 0) exception(ERR_INV_CONT_OBJ); Value->mValue = Args[0] + get_numeric_property_value(Value); Value->mForm = FORM_UDATA; @@ -1941,19 +2149,25 @@ void read_and_evaluate_dwarf_object_property_with_args( case FORM_BLOCK2 : case FORM_BLOCK4 : case FORM_BLOCK : + case FORM_SEC_OFFSET: + case FORM_LOCLISTX : dwarf_evaluate_expression(Value, Args, ArgsCnt); break; } } else if (Attr == AT_location || Attr == AT_string_length || Attr == AT_frame_base || Attr == AT_use_location) { switch (Value->mForm) { + case FORM_DATA1 : + case FORM_DATA2 : case FORM_DATA4 : case FORM_DATA8 : + case FORM_DATA16 : case FORM_BLOCK1 : case FORM_BLOCK2 : case FORM_BLOCK4 : case FORM_BLOCK : case FORM_SEC_OFFSET: + case FORM_LOCLISTX : dwarf_evaluate_expression(Value, Args, ArgsCnt); break; } @@ -1964,6 +2178,8 @@ void read_and_evaluate_dwarf_object_property_with_args( case FORM_BLOCK2 : case FORM_BLOCK4 : case FORM_BLOCK : + case FORM_SEC_OFFSET: + case FORM_LOCLISTX : dwarf_evaluate_expression(Value, Args, ArgsCnt); break; } @@ -2052,7 +2268,6 @@ DWARFCache * get_dwarf_cache(ELF_File * file) { sCache->mObjectArrayPos = OBJECT_ARRAY_SIZE; sCache->mObjectHashTable = (ObjectHashTable *)loc_alloc_zero(sizeof(ObjectHashTable) * file->section_cnt); if (set_trap(&trap)) { - dio_LoadAbbrevTable(file); load_debug_sections(); clear_trap(&trap); } @@ -2074,6 +2289,7 @@ static void add_dir(CompUnit * unit, char * name) { } static void add_file(FileInfo * file) { + unsigned i; CompUnit * unit = file->mCompUnit; file->mNameHash = calc_file_name_hash(file->mName); if (unit->mFilesCnt >= unit->mFilesMax) { @@ -2081,6 +2297,16 @@ static void add_file(FileInfo * file) { unit->mFiles = (FileInfo *)loc_realloc(unit->mFiles, sizeof(FileInfo) * unit->mFilesMax); } if (file->mDir == NULL) file->mDir = unit->mDir; + /* Workaround: check for duplicate entries */ + file->mDup = ~(unsigned)0; + for (i = 0; i < unit->mFilesCnt; i++) { + if (unit->mFiles[i].mNameHash == file->mNameHash && + unit->mFiles[i].mDir != NULL && file->mDir != NULL && strcmp(unit->mFiles[i].mDir, file->mDir) == 0 && + unit->mFiles[i].mName != NULL && file->mName != NULL && strcmp(unit->mFiles[i].mName, file->mName) == 0) { + file->mDup = i; + break; + } + } unit->mFiles[unit->mFilesCnt++] = *file; } @@ -2089,6 +2315,10 @@ static void add_state(CompUnit * unit, LineNumbersState * state) { /* Workaround: Diab compiler generates invalid file indices for an empty compilation unit */ return; } + if (unit->mFiles[state->mFile].mDup < unit->mFilesCnt) { + /* Workaround: dublicate file IDs break line numbers service */ + state->mFile = unit->mFiles[state->mFile].mDup; + } if (unit->mFiles[state->mFile].mAreaCnt++ == 0) { /* Workaround: compilers don't produce mapping for first lines in a source file. * Such mapping is needed, for example, for re-positioning of source line breakpoints. @@ -2165,21 +2395,30 @@ static int state_text_pos_comparator(const void * x1, const void * x2) { } static void compute_reverse_lookup_indices(DWARFCache * Cache, CompUnit * Unit) { - U4_T i; + U4_T i, j; qsort(Unit->mStates, Unit->mStatesCnt, sizeof(LineNumbersState), state_address_comparator); Unit->mStatesIndex = (LineNumbersState **)loc_alloc(sizeof(LineNumbersState *) * Unit->mStatesCnt); - for (i = 0; i < Unit->mStatesCnt; i++) { - LineNumbersState * s1 = Unit->mStates + i; - while (i + 1 < Unit->mStatesCnt) { - LineNumbersState * s2 = s1 + 1; - if (s1->mFile != s2->mFile || - s1->mLine != s2->mLine || s1->mColumn != s2->mColumn || + for (i = 0, j = 0; i < Unit->mStatesCnt;) { + LineNumbersState * s1 = Unit->mStates + i++; + while (i < Unit->mStatesCnt) { + LineNumbersState * s2 = Unit->mStates + i; + if (s1->mLine != s2->mLine || s1->mColumn != s2->mColumn || s1->mFile != s2->mFile || s1->mFlags != s2->mFlags || s1->mISA != s2->mISA || s1->mOpIndex != s2->mOpIndex || s1->mDiscriminator != s2->mDiscriminator) break; - memmove(s2, s2 + 1, sizeof(LineNumbersState) * (Unit->mStatesCnt - i - 2)); - Unit->mStatesCnt--; + /* Workaround for GCC bug: skip redundant entries in line info */ + i++; } - Unit->mStatesIndex[i] = s1; + Unit->mStatesIndex[j++] = s1; + } + assert(j <= Unit->mStatesCnt); + if (j < Unit->mStatesCnt) { + Unit->mStatesCnt = j; + for (i = 0; i < j && Unit->mStates + i == Unit->mStatesIndex[i]; i++) {} + for (; i < j; i++) { + Unit->mStates[i] = *Unit->mStatesIndex[i]; + Unit->mStatesIndex[i] = Unit->mStates + i; + } + Unit->mStatesIndex = (LineNumbersState **)loc_realloc(Unit->mStatesIndex, sizeof(LineNumbersState *) * Unit->mStatesCnt); } qsort(Unit->mStatesIndex, Unit->mStatesCnt, sizeof(LineNumbersState *), state_text_pos_comparator); for (i = 0; i < Unit->mStatesCnt; i++) Unit->mStatesIndex[i]->mStatesIndexPos = i; @@ -2214,6 +2453,13 @@ static void load_line_numbers_v1(CompUnit * Unit, U4_T unit_size) { ELF_Section * sec = NULL; ContextAddress addr = 0; U4_T line = 0; + FileInfo file; + + memset(&file, 0, sizeof(file)); + file.mCompUnit = Unit; + file.mDir = Unit->mDir; + file.mName = Unit->mObject->mName; + add_file(&file); memset(&state, 0, sizeof(state)); addr = (ContextAddress)dio_ReadAddress(&sec); @@ -2234,6 +2480,8 @@ static void load_line_numbers_v1(CompUnit * Unit, U4_T unit_size) { static void load_line_numbers_v2(CompUnit * Unit, U8_T unit_size, int dwarf64) { U2_T version = 0; + U1_T address_size = dwarf64 ? 8 : 4; + U1_T segment_selector_size = 0; U8_T header_pos = 0; U1_T opcode_base = 0; U1_T opcode_size[256]; @@ -2246,7 +2494,22 @@ static void load_line_numbers_v2(CompUnit * Unit, U8_T unit_size, int dwarf64) { LineNumbersState state; version = dio_ReadU2(); - if (version < 2 || version > 4) str_exception(ERR_INV_DWARF, "Invalid line number info version"); + if (version < 2 || version > 5) str_exception(ERR_INV_DWARF, "Invalid line number info version"); + if (version >= 5) { + address_size = dio_ReadU1(); + segment_selector_size = dio_ReadU1(); + } + if (version < 5) { + /* Prior to DWARF Version 5, the current compilation file name was not represented in + the file_names field. In DWARF Version 5, the current compilation file name is + explicitly present and has index 0 */ + FileInfo file; + memset(&file, 0, sizeof(file)); + file.mCompUnit = Unit; + file.mDir = Unit->mDir; + file.mName = Unit->mObject->mName; + add_file(&file); + } header_size = dwarf64 ? dio_ReadU8() : (U8_T)dio_ReadU4(); header_pos = dio_GetPos(); min_instruction_length = dio_ReadU1(); @@ -2258,26 +2521,102 @@ static void load_line_numbers_v2(CompUnit * Unit, U8_T unit_size, int dwarf64) { memset(opcode_size, 0, sizeof(opcode_size)); dio_Read(opcode_size + 1, opcode_base - 1); + if (segment_selector_size > 0) str_exception(ERR_INV_DWARF, "Segment selectors not supported"); + if (address_size > 8) str_exception(ERR_INV_DWARF, "Address size > 8 not supported"); + /* Read directory names */ - for (;;) { - char * name = dio_ReadString(); - if (name == NULL) break; - add_dir(Unit, name); + if (version <= 4) { + add_dir(Unit, NULL); + for (;;) { + char * name = dio_ReadString(); + if (name == NULL) break; + add_dir(Unit, name); + } + } + else { + U1_T directory_entry_format_count = dio_ReadU1(); + typedef struct { + U4_T type; + U4_T form; + } DirectoryEntryFormat; + DirectoryEntryFormat * format = (DirectoryEntryFormat *)tmp_alloc_zero(sizeof(DirectoryEntryFormat) * directory_entry_format_count); + U8_T directories_count = 0; + unsigned i, j; + for (i = 0; i < directory_entry_format_count; i++) { + format[i].type = dio_ReadULEB128(); + format[i].form = dio_ReadULEB128(); + } + directories_count = dio_ReadULEB128(); + for (j = 0; j < directories_count; j++) { + for (i = 0; i < directory_entry_format_count; i++) { + dio_ReadAttribute(0, format[i].form); + switch (format[i].type) { + case DW_LNCT_path: + add_dir(Unit, (char *)dio_gFormDataAddr); + break; + } + } + } } /* Read source files info */ - for (;;) { - U4_T dir = 0; - FileInfo file; - memset(&file, 0, sizeof(file)); - file.mName = dio_ReadString(); - if (file.mName == NULL) break; - dir = dio_ReadULEB128(); - if (dir > 0 && dir <= Unit->mDirsCnt) file.mDir = Unit->mDirs[dir - 1]; - file.mCompUnit = Unit; - file.mModTime = dio_ReadULEB128(); - file.mSize = dio_ReadULEB128(); - add_file(&file); + if (version <= 4) { + for (;;) { + U4_T dir = 0; + FileInfo file; + memset(&file, 0, sizeof(file)); + file.mName = dio_ReadString(); + if (file.mName == NULL) break; + dir = dio_ReadULEB128(); + if (dir < Unit->mDirsCnt) file.mDir = Unit->mDirs[dir]; + file.mModTime = dio_ReadULEB128(); + file.mSize = dio_ReadU8LEB128(); + file.mCompUnit = Unit; + add_file(&file); + } + } + else { + U1_T file_name_entry_format_count = dio_ReadU1(); + typedef struct { + U4_T type; + U4_T form; + } FileNameEntryFormat; + FileNameEntryFormat * format = (FileNameEntryFormat *)tmp_alloc_zero(sizeof(FileNameEntryFormat) * file_name_entry_format_count); + U8_T file_names_count = 0; + unsigned i, j; + for (i = 0; i < file_name_entry_format_count; i++) { + format[i].type = dio_ReadULEB128(); + format[i].form = dio_ReadULEB128(); + } + file_names_count = dio_ReadULEB128(); + for (j = 0; j < file_names_count; j++) { + FileInfo file; + memset(&file, 0, sizeof(file)); + for (i = 0; i < file_name_entry_format_count; i++) { + dio_ReadAttribute(0, format[i].form); + switch (format[i].type) { + case DW_LNCT_path: + file.mName = (char *)dio_gFormDataAddr; + break; + case DW_LNCT_directory_index: + if (dio_gFormData >= Unit->mDirsCnt) break; + file.mDir = Unit->mDirs[dio_gFormData]; + break; + case DW_LNCT_timestamp: + file.mModTime = (U4_T)dio_gFormData; + break; + case DW_LNCT_size: + file.mSize = dio_gFormData; + break; + case DW_LNCT_MD5: + if (dio_gFormDataSize < sizeof(file.mMD5)) break; + memcpy(file.mMD5, dio_gFormDataAddr, sizeof(file.mMD5)); + break; + } + } + file.mCompUnit = Unit; + if (file.mName != NULL) add_file(&file); + } } if (header_pos + header_size != dio_GetPos()) { @@ -2317,10 +2656,10 @@ static void load_line_numbers_v2(CompUnit * Unit, U8_T unit_size, int dwarf64) { memset(&file, 0, sizeof(file)); file.mName = dio_ReadString(); dir = dio_ReadULEB128(); - if (dir > 0 && dir <= Unit->mDirsCnt) file.mDir = Unit->mDirs[dir - 1]; + if (dir < Unit->mDirsCnt) file.mDir = Unit->mDirs[dir]; file.mCompUnit = Unit; file.mModTime = dio_ReadULEB128(); - file.mSize = dio_ReadULEB128(); + file.mSize = dio_ReadU8LEB128(); add_file(&file); break; } @@ -2397,19 +2736,11 @@ void load_line_numbers(CompUnit * Unit) { Trap trap; DWARFCache * Cache = (DWARFCache *)Unit->mFile->dwarf_dt_cache; ELF_Section * LineInfoSection = Unit->mLineInfoSection; - if (LineInfoSection == NULL) LineInfoSection = Unit->mDesc.mVersion <= 1 ? Cache->mDebugLineV1 : Cache->mDebugLineV2; if (LineInfoSection == NULL) return; if (Unit->mLineInfoLoaded) return; - if (elf_load(LineInfoSection)) exception(errno); dio_EnterSection(&Unit->mDesc, LineInfoSection, Unit->mLineInfoOffs); if (set_trap(&trap)) { U8_T unit_size = 0; - FileInfo file; - memset(&file, 0, sizeof(file)); - file.mCompUnit = Unit; - file.mDir = Unit->mDir; - file.mName = Unit->mObject->mName; - add_file(&file); /* Read header */ unit_size = dio_ReadU4(); if (Unit->mDesc.mVersion <= 1) { diff --git a/agent/tcf/services/dwarfcache.h b/agent/tcf/services/dwarfcache.h index 41d7c6c1..ffabf212 100644 --- a/agent/tcf/services/dwarfcache.h +++ b/agent/tcf/services/dwarfcache.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2006-2023 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. @@ -50,17 +50,20 @@ typedef struct UnitAddressRange UnitAddressRange; typedef struct FrameInfoRange FrameInfoRange; typedef struct FrameInfoIndex FrameInfoIndex; typedef struct ObjectHashTable ObjectHashTable; +typedef struct ObjectAddressRange ObjectAddressRange; typedef struct DWARFCache DWARFCache; struct FileInfo { const char * mName; const char * mDir; U4_T mModTime; - U4_T mSize; + U8_T mSize; + U1_T mMD5[16]; unsigned mNameHash; FileInfo * mNextInHash; CompUnit * mCompUnit; unsigned mAreaCnt; + unsigned mDup; }; #define TAG_fund_type 0x2000 @@ -68,30 +71,32 @@ struct FileInfo { #define TAG_mod_pointer 0x2002 #define TAG_mod_reference 0x2003 -#define DOIF_declaration 0x000001 -#define DOIF_external 0x000002 -#define DOIF_artificial 0x000004 -#define DOIF_specification 0x000008 -#define DOIF_abstract_origin 0x000010 -#define DOIF_extension 0x000020 -#define DOIF_private 0x000040 -#define DOIF_protected 0x000080 -#define DOIF_public 0x000100 -#define DOIF_children_loaded 0x000200 -#define DOIF_ranges 0x000400 -#define DOIF_aranges 0x000800 -#define DOIF_find_mark 0x001000 -#define DOIF_load_mark 0x002000 -#define DOIF_pub_mark 0x004000 -#define DOIF_low_pc 0x008000 -#define DOIF_need_frame 0x010000 -#define DOIF_mips_linkage_name 0x020000 -#define DOIF_linkage_name 0x040000 -#define DOIF_mangled_name 0x080000 -#define DOIF_optional 0x100000 -#define DOIF_location 0x200000 -#define DOIF_data_location 0x400000 -#define DOIF_const_value 0x800000 +#define DOIF_declaration 0x0000001 +#define DOIF_external 0x0000002 +#define DOIF_artificial 0x0000004 +#define DOIF_specification 0x0000008 +#define DOIF_abstract_origin 0x0000010 +#define DOIF_extension 0x0000020 +#define DOIF_private 0x0000040 +#define DOIF_protected 0x0000080 +#define DOIF_public 0x0000100 +#define DOIF_children_loaded 0x0000200 +#define DOIF_ranges 0x0000400 +#define DOIF_aranges 0x0000800 +#define DOIF_find_mark 0x0002000 +#define DOIF_load_mark 0x0004000 +#define DOIF_pub_mark 0x0008000 +#define DOIF_low_pc 0x0010000 +#define DOIF_need_frame 0x0020000 +#define DOIF_mips_linkage_name 0x0040000 +#define DOIF_linkage_name 0x0080000 +#define DOIF_mangled_name 0x0100000 +#define DOIF_optional 0x0200000 +#define DOIF_location 0x0400000 +#define DOIF_data_location 0x0800000 +#define DOIF_const_value 0x1000000 +#define DOIF_inv_reference 0x2000000 +#define DOIF_inlined 0x4000000 struct ObjectInfo { @@ -252,6 +257,19 @@ struct ObjectHashTable { unsigned mCompUnitsIndexSize; }; +struct ObjectAddressRange { + ObjectInfo * mObject; + CompUnit * mUnit; + ELF_Section * mRngSection; + ELF_Section * mBaseSection; + ContextAddress mBaseAddr; + unsigned mVersion; + ELF_Section * mSection; + ContextAddress mAddr; /* Link-time start address of the range */ + ContextAddress mSize; /* Size of the range */ + int mDone; +}; + #define DWARF_CACHE_MAGIC 0x34625490 struct DWARFCache { @@ -261,6 +279,8 @@ struct DWARFCache { ELF_Section * mDebugLineV1; ELF_Section * mDebugLineV2; ELF_Section * mDebugLoc; + ELF_Section * mDebugLocLists; + ELF_Section * mDebugRngLists; ELF_Section * mDebugRanges; ObjectHashTable * mObjectHashTable; /* per ELF section */ struct ObjectArray * mObjectList; @@ -307,6 +327,13 @@ extern ObjectInfo * find_object(ELF_Section * sec, ContextAddress ID); extern UnitAddressRange * find_comp_unit_addr_range(DWARFCache * cache, ELF_Section * section, ContextAddress addr_min, ContextAddress addr_max); +/* Read an address from .debug_addr section */ +extern U8_T read_dwarf_addr_section(CompUnit * Unit, U4_T idx, ELF_Section ** Section); + +/* Read address ranges */ +extern void start_dwarf_addr_ranges(ObjectInfo * Obj, ObjectAddressRange * Range); +extern int read_dwarf_addr_range(ObjectAddressRange * Range); + /* * Read a property of a DWARF object, perform ELF relocations if any. * FORM_ADDR values are mapped to run-time address space. diff --git a/agent/tcf/services/dwarfecomp.c b/agent/tcf/services/dwarfecomp.c index 8b29497e..c7540274 100644 --- a/agent/tcf/services/dwarfecomp.c +++ b/agent/tcf/services/dwarfecomp.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2011-2022 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. @@ -61,6 +61,8 @@ static ObjectInfo ** call_site_buf = NULL; static unsigned call_site_cnt = 0; static unsigned call_site_max = 0; +static const char * name_synopsys = "CHESS, Synopsys Inc"; + static void add(unsigned n) { if (buf_pos >= buf_max) { buf_max *= 2; @@ -170,40 +172,53 @@ static int get_num_prop(ObjectInfo * obj, U2_T at, U8_T * res) { return 1; } -static void op_addr(void) { +static ContextAddress get_relocated_addr(ELF_Section * src_section, U8_T pos, ELF_Section ** dst_section, int * rt) { + DIO_UnitDescriptor * desc = &expr->object->mCompUnit->mDesc; ContextAddress addr = 0; - ELF_Section * section = NULL; - U8_T pos = 0; - int rt = 0; - - expr_pos++; - pos = expr->expr_addr + expr_pos - (U1_T *)expr->section->data; - dio_EnterSection(&expr->object->mCompUnit->mDesc, expr->section, pos); - switch (expr->object->mCompUnit->mDesc.mAddressSize) { + dio_EnterSection(desc, src_section, pos); + switch (desc->mAddressSize) { case 2: { U2_T x = dio_ReadU2(); - drl_relocate_in_context(expr_ctx, expr->section, pos, &x, sizeof(x), §ion, &rt); + drl_relocate_in_context(expr_ctx, src_section, pos, &x, sizeof(x), dst_section, rt); addr = x; break; } case 4: { U4_T x = dio_ReadU4(); - drl_relocate_in_context(expr_ctx, expr->section, pos, &x, sizeof(x), §ion, &rt); + drl_relocate_in_context(expr_ctx, src_section, pos, &x, sizeof(x), dst_section, rt); addr = x; break; } case 8: { U8_T x = dio_ReadU8(); - drl_relocate_in_context(expr_ctx, expr->section, pos, &x, sizeof(x), §ion, &rt); + drl_relocate_in_context(expr_ctx, src_section, pos, &x, sizeof(x), dst_section, rt); addr = x; break; } default: str_exception(ERR_INV_DWARF, "Invalid data size"); - return; + break; } - expr_pos += (size_t)(dio_GetPos() - pos); dio_ExitSection(); + return addr; +} + +static void op_addr(void) { + ContextAddress addr = 0; + DIO_UnitDescriptor * desc = &expr->object->mCompUnit->mDesc; + ELF_Section * section = NULL; + U8_T pos = 0; + int rt = 0; + + expr_pos++; + pos = expr->expr_addr + expr_pos - (U1_T *)expr->section->data; + addr = get_relocated_addr(expr->section, pos, §ion, &rt); + expr_pos += (size_t)desc->mAddressSize; + if (expr_pos < expr->expr_size && expr->expr_addr[expr_pos] == OP_addr && expr->object->mCompUnit->mProducer && + !strncmp(expr->object->mCompUnit->mProducer, name_synopsys, strlen(name_synopsys))) { + /* Workaround: Synopsys compiler for Xilinx AIE generates multiple OP_addr where 1 is expected */ + return; + } if (expr_pos < expr->expr_size && expr->expr_addr[expr_pos] == OP_GNU_push_tls_address) { /* Bug in some versions of GCC: OP_addr used instead of OP_const, use link-time value */ } @@ -215,6 +230,55 @@ static void op_addr(void) { add_uleb128(addr); } +static void op_addrx(void) { + ContextAddress addr = 0; + DIO_UnitDescriptor * desc = &expr->object->mCompUnit->mDesc; + ELF_Section * section = NULL; + U8_T pos = 0; + U4_T idx = 0; + int rt = 0; + + expr_pos++; + pos = expr->expr_addr + expr_pos - (U1_T *)expr->section->data; + dio_EnterSection(desc, expr->section, pos); + idx = dio_ReadULEB128(); + expr_pos += (size_t)(dio_GetPos() - pos); + dio_ExitSection(); + if (desc->mAddrInfoSection == NULL) str_exception(ERR_INV_DWARF, "Missing AT_addr_base"); + addr = get_relocated_addr(desc->mAddrInfoSection, desc->mAddrInfoOffs + idx * desc->mAddressSize, §ion, &rt); + if (!rt) { + addr = elf_map_to_run_time_address(expr_ctx, expr->object->mCompUnit->mFile, section, addr); + if (errno) str_exception(errno, "Cannot get object run-time address"); + } + add(OP_constu); + add_uleb128(addr); +} + +static void op_constx(void) { + ContextAddress addr = 0; + DIO_UnitDescriptor * desc = &expr->object->mCompUnit->mDesc; + U8_T pos = 0; + U4_T idx = 0; + + expr_pos++; + pos = expr->expr_addr + expr_pos - (U1_T *)expr->section->data; + dio_EnterSection(desc, expr->section, pos); + idx = dio_ReadULEB128(); + expr_pos += (size_t)(dio_GetPos() - pos); + dio_ExitSection(); + if (desc->mAddrInfoSection == NULL) str_exception(ERR_INV_DWARF, "Missing AT_addr_base"); + dio_EnterSection(desc, desc->mAddrInfoSection, desc->mAddrInfoOffs + idx * desc->mAddressSize); + switch (desc->mAddressSize) { + case 2: addr = dio_ReadU2(); break; + case 4: addr = dio_ReadU4(); break; + case 8: addr = dio_ReadU8(); break; + default: str_exception(ERR_INV_DWARF, "Invalid data size"); break; + } + dio_ExitSection(); + add(OP_constu); + add_uleb128(addr); +} + static ObjectInfo * get_parent_function(ObjectInfo * info) { while (info != NULL) { switch (info->mTag) { @@ -238,58 +302,22 @@ static int check_section(CompUnit * unit, ELF_Section * sec_obj, ELF_Section * s } int dwarf_check_in_range(ObjectInfo * obj, ELF_Section * sec, U8_T addr) { - if (obj->mFlags & DOIF_ranges) { - Trap trap; - if (set_trap(&trap)) { - CompUnit * unit = obj->mCompUnit; - DWARFCache * cache = get_dwarf_cache(unit->mFile); - ELF_Section * debug_ranges = cache->mDebugRanges; - if (debug_ranges != NULL) { - ContextAddress base = unit->mObject->u.mCode.mLowPC; - int res = 0; - -#if 0 - U8_T entry_pc = 0; - if (obj->mTag == TAG_inlined_subroutine && - get_num_prop(obj, AT_entry_pc, &entry_pc)) - base = (ContextAddress)entry_pc; -#endif - - dio_EnterSection(&unit->mDesc, debug_ranges, obj->u.mCode.mHighPC.mRanges); - for (;;) { - U8_T AddrMax = ~(U8_T)0; - ELF_Section * x_sec = NULL; - ELF_Section * y_sec = NULL; - U8_T x = dio_ReadAddress(&x_sec); - U8_T y = dio_ReadAddress(&y_sec); - if (x == 0 && y == 0) break; - if (unit->mDesc.mAddressSize < 8) AddrMax = ((U8_T)1 << unit->mDesc.mAddressSize * 8) - 1; - if (x == AddrMax) { - base = (ContextAddress)y; - } - else if (check_section(unit, x_sec, sec) && check_section(unit, y_sec, sec)) { - x = base + x; - y = base + y; - if (x <= addr && addr < y) { - res = 1; - break; - } - } - } + Trap trap; + int res = 0; + ObjectAddressRange range; + if (set_trap(&trap)) { + start_dwarf_addr_ranges(obj, &range); + while (read_dwarf_addr_range(&range)) { + if (check_section(range.mUnit, range.mSection, sec) && + range.mAddr <= addr && (range.mAddr + range.mSize == 0 || addr < range.mAddr + range.mSize)) { dio_ExitSection(); - clear_trap(&trap); - return res; + res = 1; + break; } - clear_trap(&trap); } - return 0; - } - - if (obj->u.mCode.mHighPC.mAddr > obj->u.mCode.mLowPC && check_section(obj->mCompUnit, obj->u.mCode.mSection, sec)) { - return addr >= obj->u.mCode.mLowPC && addr < obj->u.mCode.mHighPC.mAddr; + clear_trap(&trap); } - - return 0; + return res; } static ObjectInfo * get_function_by_addr(ObjectInfo * parent, ELF_Section * sec, U8_T addr) { @@ -516,7 +544,7 @@ static void op_fbreg(void) { dwarf_get_expression_list(&fp, &info); add_expression_list(info, 1, offs); } - else if (trap.error != ERR_SYM_NOT_FOUND) { + else if (get_error_code(trap.error) != ERR_SYM_NOT_FOUND) { str_exception(trap.error, "OP_fbreg: cannot read AT_frame_base"); } else { @@ -588,6 +616,7 @@ static void op_implicit_pointer(void) { switch (pv.mForm) { case FORM_SDATA: case FORM_UDATA: + case FORM_IMPLICIT_CONST: pv.mAddr = buf.arr; if (unit->mFile->elf64) { pv.mSize = 8; @@ -662,7 +691,7 @@ static void op_call(void) { expr_pos += (size_t)(dio_GetPos() - dio_pos); dio_ExitSection(); - ref_obj = find_object(expr->object->mCompUnit->mDesc.mSection, ref_id); + ref_obj = find_object(desc->mSection, ref_id); if (ref_obj == NULL) str_exception(ERR_INV_DWARF, "Invalid reference in OP_call"); read_dwarf_object_property(expr_ctx, STACK_NO_FRAME, ref_obj, AT_location, &pv); dwarf_get_expression_list(&pv, &info); @@ -688,7 +717,7 @@ static void op_gnu_variable_value(void) { expr_pos += (size_t)(dio_GetPos() - dio_pos); dio_ExitSection(); - ref_obj = find_object(expr->object->mCompUnit->mDesc.mSection, ref_id); + ref_obj = find_object(desc->mSection, ref_id); if (ref_obj == NULL) str_exception(ERR_INV_DWARF, "Invalid reference in OP_GNU_variable_value"); elf_object2symbol(NULL, ref_obj, &sym); id = symbol2id(sym); @@ -775,7 +804,7 @@ static void op_parameter_ref(void) { PropertyValue pv; expr_pos++; - add(OP_GNU_entry_value); + add(OP_entry_value); size_pos = buf_pos; add(0); add(0); @@ -792,7 +821,7 @@ static void op_parameter_ref(void) { ObjectInfo * site = call_site_buf[n]; ObjectInfo * args = get_dwarf_children(site); while (args != NULL) { - if (args->mTag == TAG_GNU_call_site_parameter && args->mFlags & DOIF_abstract_origin) { + if (args->mTag == TAG_GNU_call_site_parameter && (args->mFlags & DOIF_abstract_origin) != 0) { read_and_evaluate_dwarf_object_property(expr_ctx, STACK_NO_FRAME, args, AT_abstract_origin, &pv); if (get_numeric_property_value(&pv) == ref_id) { Trap trap; @@ -882,7 +911,6 @@ static void add_expression(DWARFExpressionInfo * info) { DWARFExpressionInfo * org_expr = expr; size_t org_expr_pos = expr_pos; JumpInfo * org_jumps = jumps; - const char * name_synopsys = "CHESS, Synopsys Inc"; expr = info; expr_pos = 0; @@ -895,6 +923,9 @@ static void add_expression(DWARFExpressionInfo * info) { size_t op_dst_pos = buf_pos; U1_T op = info->expr_addr[expr_pos]; switch (op) { + case OP_nop: + expr_pos++; + break; case OP_const1u: case OP_const1s: case OP_pick: @@ -907,7 +938,6 @@ static void add_expression(DWARFExpressionInfo * info) { copy(1 + info->object->mCompUnit->mDesc.mAddressSize); break; case OP_basereg: - check_frame(); copy(1 + info->object->mCompUnit->mDesc.mAddressSize); break; case OP_const2u: @@ -954,7 +984,6 @@ static void add_expression(DWARFExpressionInfo * info) { case OP_breg29: case OP_breg30: case OP_breg31: - check_frame(); add(op); expr_pos++; copy_leb128(); @@ -991,7 +1020,6 @@ static void add_expression(DWARFExpressionInfo * info) { } break; case OP_bregx: - check_frame(); add(op); expr_pos++; copy_leb128(); @@ -1023,6 +1051,12 @@ static void add_expression(DWARFExpressionInfo * info) { case OP_addr: op_addr(); break; + case OP_addrx: + op_addrx(); + break; + case OP_constx: + op_constx(); + break; case OP_implicit_pointer: case OP_GNU_implicit_pointer: op_implicit_pointer(); @@ -1036,6 +1070,7 @@ static void add_expression(DWARFExpressionInfo * info) { case OP_call_ref: op_call(); break; + case OP_entry_value: case OP_GNU_entry_value: check_frame(); op_entry_value(); @@ -1044,6 +1079,7 @@ static void add_expression(DWARFExpressionInfo * info) { check_frame(); op_parameter_ref(); break; + case OP_const_type: case OP_GNU_const_type: expr_pos++; { @@ -1090,6 +1126,7 @@ static void add_expression(DWARFExpressionInfo * info) { copy(size); } break; + case OP_regval_type: case OP_GNU_regval_type: expr_pos++; { @@ -1122,6 +1159,8 @@ static void add_expression(DWARFExpressionInfo * info) { } } break; + case OP_deref_type: + case OP_xderef_type: case OP_GNU_deref_type: expr_pos++; { @@ -1138,18 +1177,19 @@ static void add_expression(DWARFExpressionInfo * info) { case ATE_unsigned_fixed: case ATE_UTF: ok = 1; - add(OP_deref_size); + add(op == OP_xderef_type ? OP_xderef_size : OP_deref_size); add(size); break; } if (!ok) { - add(OP_GNU_deref_type); + add(op == OP_xderef_type ? OP_xderef_type : OP_GNU_deref_type); add_uleb128(size); add_uleb128(fund_type); add_uleb128(byte_size); } } break; + case OP_convert: case OP_GNU_convert: expr_pos++; { @@ -1184,7 +1224,8 @@ static void add_expression(DWARFExpressionInfo * info) { break; case OP_GNU_variable_value: /* case OP_address_class: */ - if (!strncmp(expr->object->mCompUnit->mProducer, name_synopsys, strlen(name_synopsys))) { + if (expr->object->mCompUnit->mProducer && + !strncmp(expr->object->mCompUnit->mProducer, name_synopsys, strlen(name_synopsys))) { /* Synopsys compiler for Xilinx AIE core uses 0xFD as a location expression * operation, which takes integer argument from top-of-stack of the location * expression stack and uses it as the address class for the location being diff --git a/agent/tcf/services/dwarfexpr.c b/agent/tcf/services/dwarfexpr.c index 5085faef..010f0a50 100644 --- a/agent/tcf/services/dwarfexpr.c +++ b/agent/tcf/services/dwarfexpr.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2016 Wind River Systems, Inc. and others. + * Copyright (c) 2008-2023 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. @@ -32,67 +32,184 @@ #include <tcf/services/elf-symbols.h> #include <tcf/services/vm.h> +static DWARFExpressionInfo * Last = NULL; + +static void add_entry(PropertyValue * Value, DWARFExpressionInfo ** List, U8_T RT_Addr, U8_T RT_Size, size_t Size) { + DWARFExpressionInfo * Info = (DWARFExpressionInfo *)tmp_alloc_zero(sizeof(DWARFExpressionInfo)); + Info->object = Value->mObject; + Info->code_addr = RT_Addr; + Info->code_size = RT_Size; + Info->section = dio_GetSection(); + Info->expr_addr = dio_GetDataPtr(); + Info->expr_size = Size; + Info->attr = Value->mAttr; + Info->form = Value->mForm; + if (Last == NULL) *List = Info; + else Last->next = Info; + Last = Info; +} + void dwarf_get_expression_list(PropertyValue * Value, DWARFExpressionInfo ** List) { CompUnit * Unit = Value->mObject->mCompUnit; + DWARFCache * Cache = (DWARFCache *)Unit->mFile->dwarf_dt_cache; + U8_T Offset = 0; + int LocSec = 0; - if (Value->mAddr == NULL || Value->mSize == 0) str_exception(ERR_INV_DWARF, "Invalid format of location expression"); - - if (Value->mForm == FORM_DATA4 || Value->mForm == FORM_DATA8 || Value->mForm == FORM_SEC_OFFSET) { - U8_T Base = 0; - U8_T Offset = 0; - U8_T AddrMax = ~(U8_T)0; - DWARFCache * Cache = (DWARFCache *)Unit->mFile->dwarf_dt_cache; - DWARFExpressionInfo * Last = NULL; + Last = NULL; + assert(Cache->magic == DWARF_CACHE_MAGIC); - assert(Cache->magic == DWARF_CACHE_MAGIC); - if (Cache->mDebugLoc == NULL) str_exception(ERR_INV_DWARF, "Missing .debug_loc section"); + if (Value->mForm == FORM_DATA1 || Value->mForm == FORM_DATA2 || Value->mForm == FORM_DATA4 || Value->mForm == FORM_DATA8) { + if (Value->mAddr == NULL || Value->mSize == 0) str_exception(ERR_INV_DWARF, "Invalid format of location expression"); dio_EnterSection(&Unit->mDesc, Unit->mDesc.mSection, Value->mAddr - (U1_T *)Unit->mDesc.mSection->data); Offset = dio_ReadAddressX(NULL, Value->mSize); dio_ExitSection(); + LocSec = 1; + } + else if (Value->mForm == FORM_SEC_OFFSET || Value->mForm == FORM_LOCLISTX) { + Offset = Value->mValue; + LocSec = 1; + } + + if (LocSec) { + U8_T Base = 0; + U8_T AddrMax = ~(U8_T)0; + Base = Unit->mObject->u.mCode.mLowPC; - if (Unit->mDesc.mAddressSize < 8) AddrMax = ((U8_T)1 << Unit->mDesc.mAddressSize * 8) - 1; - dio_EnterSection(&Unit->mDesc, Cache->mDebugLoc, Offset); - for (;;) { - ELF_Section * S0 = NULL; - ELF_Section * S1 = NULL; - U8_T Addr0 = dio_ReadAddress(&S0); - U8_T Addr1 = dio_ReadAddress(&S1); - if (Addr0 == AddrMax) { - Base = Addr1; - } - else if (Addr0 == 0 && Addr1 == 0) { - break; - } - else if (Addr0 > Addr1) { - str_exception(ERR_INV_DWARF, "Invalid .debug_loc section"); + if (Unit->mDesc.mVersion <= 4) { + if (Unit->mDesc.mAddressSize < 8) AddrMax = ((U8_T)1 << Unit->mDesc.mAddressSize * 8) - 1; + if (Cache->mDebugLoc == NULL) str_exception(ERR_INV_DWARF, "Missing .debug_loc section"); + dio_EnterSection(&Unit->mDesc, Cache->mDebugLoc, Offset); + for (;;) { + ELF_Section * S0 = NULL; + ELF_Section * S1 = NULL; + U8_T Addr0 = dio_ReadAddress(&S0); + U8_T Addr1 = dio_ReadAddress(&S1); + if (Addr0 == AddrMax) { + Base = Addr1; + } + else if (Addr0 == 0 && Addr1 == 0) { + break; + } + else if (Addr0 > Addr1) { + str_exception(ERR_INV_DWARF, "Invalid .debug_loc section"); + } + else { + U2_T Size = dio_ReadU2(); + U8_T RT_Addr = 0; + if (S0 == NULL) S0 = Unit->mTextSection; + RT_Addr = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, Base + Addr0); + if (!errno) add_entry(Value, List, RT_Addr, Addr1 - Addr0, Size); + dio_Skip(Size); + } } - else { - U2_T Size = dio_ReadU2(); - U8_T RT_Addr0 = 0; - if (S0 == NULL) S0 = Unit->mTextSection; - RT_Addr0 = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, Base + Addr0); - if (!errno) { - DWARFExpressionInfo * Info = (DWARFExpressionInfo *)tmp_alloc_zero(sizeof(DWARFExpressionInfo)); - Info->object = Value->mObject; - Info->code_addr = RT_Addr0; - Info->code_size = Addr1 - Addr0; - Info->section = Cache->mDebugLoc; - Info->expr_addr = dio_GetDataPtr(); - Info->expr_size = Size; - Info->attr = Value->mAttr; - Info->form = Value->mForm; - if (Last == NULL) *List = Info; - else Last->next = Info; - Last = Info; + dio_ExitSection(); + if (Last == NULL) str_exception(ERR_OTHER, "Object is not available at this location in the code"); + } + else { + ELF_Section * BaseSection = NULL; + if (Cache->mDebugLocLists == NULL) str_exception(ERR_INV_DWARF, "Missing .debug_loclists section"); + dio_EnterSection(&Unit->mDesc, Cache->mDebugLocLists, Offset); + for (;;) { + U1_T type = dio_ReadU1(); + if (type == DW_LLE_end_of_list) break; + switch (type) { + case DW_LLE_base_addressx: + Base = read_dwarf_addr_section(Unit, dio_ReadULEB128(), &BaseSection); + break; + case DW_LLE_startx_endx: + { + ELF_Section * S0 = NULL; + ELF_Section * S1 = NULL; + U8_T Addr0 = read_dwarf_addr_section(Unit, dio_ReadULEB128(), &S0); + U8_T Addr1 = read_dwarf_addr_section(Unit, dio_ReadULEB128(), &S1); + U4_T Size = dio_ReadULEB128(); + if (S0 == NULL) S0 = Unit->mTextSection; + if (Addr1 > Addr0) { + U8_T RT_Addr = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, Addr0); + if (!errno) add_entry(Value, List, RT_Addr, Addr1 - Addr0, Size); + } + dio_Skip(Size); + } + break; + case DW_LLE_startx_length: + { + ELF_Section * S0 = NULL; + U8_T Addr0 = read_dwarf_addr_section(Unit, dio_ReadULEB128(), &S0); + U8_T CSize = dio_ReadU8LEB128(); + U4_T Size = dio_ReadULEB128(); + if (S0 == NULL) S0 = Unit->mTextSection; + if (CSize != 0) { + U8_T RT_Addr = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, Addr0); + if (!errno) add_entry(Value, List, RT_Addr, CSize, Size); + } + dio_Skip(Size); + } + break; + case DW_LLE_offset_pair: + { + ELF_Section * S0 = BaseSection; + U8_T Offs0 = dio_ReadU8LEB128(); + U8_T Offs1 = dio_ReadU8LEB128(); + U4_T Size = dio_ReadULEB128(); + if (S0 == NULL) S0 = Unit->mTextSection; + if (Offs1 > Offs0) { + U8_T RT_Addr = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, Base + Offs0); + if (!errno) add_entry(Value, List, RT_Addr, Offs1 - Offs0, Size); + } + dio_Skip(Size); + } + break; + case DW_LLE_default_location: + { + U4_T Size = dio_ReadULEB128(); + add_entry(Value, List, 0, 0, Size); + dio_Skip(Size); + } + break; + case DW_LLE_base_address: + Base = dio_ReadAddress(&BaseSection); + break; + case DW_LLE_start_end: + { + ELF_Section * S0 = NULL; + ELF_Section * S1 = NULL; + U8_T Addr0 = dio_ReadAddress(&S0); + U8_T Addr1 = dio_ReadAddress(&S1); + U4_T Size = dio_ReadULEB128(); + if (S0 == NULL) S0 = Unit->mTextSection; + if (Addr1 > Addr0) { + U8_T RT_Addr = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, Addr0); + if (!errno) add_entry(Value, List, RT_Addr, Addr1 - Addr0, Size); + } + dio_Skip(Size); + } + break; + case DW_LLE_start_length: + { + ELF_Section * S0 = NULL; + U8_T Addr0 = dio_ReadAddress(&S0); + U8_T CSize = dio_ReadU8LEB128(); + U4_T Size = dio_ReadULEB128(); + if (S0 == NULL) S0 = Unit->mTextSection; + if (CSize != 0) { + U8_T RT_Addr = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, Addr0); + if (!errno) add_entry(Value, List, RT_Addr, CSize, Size); + } + dio_Skip(Size); + } + break; + default: + str_exception(ERR_OTHER, "Invalid .debug_loclists section"); + break; } - dio_Skip(Size); } + dio_ExitSection(); + if (Last == NULL) str_exception(ERR_OTHER, "Object is not available at this location in the code"); } - dio_ExitSection(); - if (Last == NULL) str_exception(ERR_OTHER, "Object is not available at this location in the code"); } else { DWARFExpressionInfo * Info = (DWARFExpressionInfo *)tmp_alloc_zero(sizeof(DWARFExpressionInfo)); + if (Value->mAddr == NULL || Value->mSize == 0) str_exception(ERR_INV_DWARF, "Invalid format of location expression"); Info->object = Value->mObject; Info->section = Unit->mDesc.mSection; Info->expr_addr = Value->mAddr; @@ -139,9 +256,6 @@ static void evaluate_expression(void * x) { State->stk[State->stk_pos++] = args[1]; State->stk[State->stk_pos++] = args[0]; } - if (Value->mPieces != NULL || Value->mAddr == NULL || Value->mSize == 0) { - str_exception(ERR_INV_DWARF, "Invalid DWARF expression reference"); - } dwarf_get_expression_list(Value, &Info); dwarf_transform_expression(Value->mContext, Value->mFrame, Info); State->code = Info->expr_addr; diff --git a/agent/tcf/services/dwarfframe.c b/agent/tcf/services/dwarfframe.c index a97ac06b..2ddb2897 100644 --- a/agent/tcf/services/dwarfframe.c +++ b/agent/tcf/services/dwarfframe.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2023 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. @@ -170,7 +170,7 @@ static RegisterRules * get_reg(StackFrameRegisters * regs, int reg) { } break; case EM_PPC: - min_reg_cnt = 64; + min_reg_cnt = 109; if (n == 1) { regs->regs[n].rule = RULE_VAL_OFFSET; } @@ -183,7 +183,7 @@ static RegisterRules * get_reg(StackFrameRegisters * regs, int reg) { } break; case EM_PPC64: - min_reg_cnt = 64; + min_reg_cnt = 66; if (n == 1) { regs->regs[n].rule = RULE_VAL_OFFSET; } @@ -297,6 +297,22 @@ static RegisterRules * get_reg(StackFrameRegisters * regs, int reg) { regs->regs[n].offset = 1; /* RA */ } break; + case EM_ARC_V2: + min_reg_cnt = 32; + if (n >= 16 && n <= 25) { /* Callee-saved registers */ + regs->regs[n].rule = RULE_SAME_VALUE; + } + else if (n == 27) { /* Frame pointer */ + regs->regs[n].rule = RULE_SAME_VALUE; + } + else if (n == 28) { /* Stack pointer */ + regs->regs[n].rule = RULE_VAL_OFFSET; + } + else if (n == rules.return_address_register) { + regs->regs[n].rule = RULE_REGISTER; + regs->regs[n].offset = 31; /* BLINK */ + } + break; } } return regs->regs + reg; @@ -908,7 +924,7 @@ static void generate_commands(void) { reg = get_reg(&frame_regs, rules.return_address_register); if (reg->rule != 0) { - reg_def = get_reg_by_id(rules.ctx, rules.return_address_register, &rules.reg_id_scope); + reg_def = get_reg_by_id(rules.ctx, reg->offset, &rules.reg_id_scope); generate_register_commands(reg, get_PC_definition(rules.ctx), reg_def); } for (i = 0; i < frame_regs.regs_cnt; i++) { @@ -1055,9 +1071,9 @@ static void read_frame_cie(U8_T fde_pos, U8_T pos) { " in FDE at %#" PRIx64, pos, fde_pos); } dio_SetPos(pos); - cie_length = dio_ReadU4(); + cie_length = dio_ReadAddressX(NULL, 4); if (cie_length == ~(U4_T)0) { - cie_length = dio_ReadU8(); + cie_length = dio_ReadAddressX(NULL, 8); cie_dwarf64 = 1; } cie_end = dio_GetPos() + cie_length; @@ -1140,15 +1156,15 @@ static void read_frame_fde(U8_T IP, U8_T fde_pos) { int fde_flag = 0; dio_EnterSection(NULL, rules.section, fde_pos); - fde_length = dio_ReadU4(); + fde_length = dio_ReadAddressX(NULL, 4); assert(fde_length > 0); if (fde_length == ~(U4_T)0) { - fde_length = dio_ReadU8(); + fde_length = dio_ReadAddressX(NULL, 8); fde_dwarf64 = 1; } ref_pos = dio_GetPos(); fde_end = ref_pos + fde_length; - cie_ref = fde_dwarf64 ? dio_ReadU8() : dio_ReadU4(); + cie_ref = dio_ReadAddressX(NULL, fde_dwarf64 ? 8 : 4); if (rules.eh_frame) fde_flag = cie_ref != 0; else if (fde_dwarf64) fde_flag = cie_ref != ~(U8_T)0; else fde_flag = cie_ref != ~(U4_T)0; @@ -1226,10 +1242,10 @@ static void create_search_index(DWARFCache * cache, FrameInfoIndex * index) { int fde_flag = 0; fde_pos = dio_GetPos(); - fde_length = dio_ReadU4(); + fde_length = dio_ReadAddressX(NULL, 4); if (fde_length == 0) continue; if (fde_length == ~(U4_T)0) { - fde_length = dio_ReadU8(); + fde_length = dio_ReadAddressX(NULL, 8); fde_dwarf64 = 1; } ref_pos = dio_GetPos(); @@ -1247,7 +1263,7 @@ static void create_search_index(DWARFCache * cache, FrameInfoIndex * index) { " in FDE at %#" PRIx64, fde_length, fde_pos); } } - cie_ref = fde_dwarf64 ? dio_ReadU8() : dio_ReadU4(); + cie_ref = dio_ReadAddressX(NULL, fde_dwarf64 ? 8 : 4); if (rules.eh_frame) fde_flag = cie_ref != 0; else if (fde_dwarf64) fde_flag = cie_ref != ~(U8_T)0; else fde_flag = cie_ref != ~(U4_T)0; diff --git a/agent/tcf/services/dwarfio.c b/agent/tcf/services/dwarfio.c index c097d964..4795b558 100644 --- a/agent/tcf/services/dwarfio.c +++ b/agent/tcf/services/dwarfio.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2006-2023 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. @@ -31,13 +31,19 @@ #include <tcf/services/dwarfreloc.h> #include <tcf/services/dwarf.h> -#define ABBREV_TABLE_SIZE (4 * MEM_USAGE_FACTOR - 1) +struct DIO_AbbreviationAttr { + U2_T mAttr; + U2_T mForm; + I8_T mValue; +}; + +typedef struct DIO_AbbreviationAttr DIO_AbbreviationAttr; struct DIO_Abbreviation { U2_T mTag; U1_T mChildren; U4_T mAttrLen; - U2_T mAttrs[2]; + DIO_AbbreviationAttr mAttrs[1]; }; typedef struct DIO_Abbreviation DIO_Abbreviation; @@ -55,8 +61,11 @@ struct DIO_Cache { U1_T * mStringTable; U8_T mStringTableAddr; U4_T mStringTableSize; - DIO_AbbrevSet ** mAbbrevTable; - U8_T mAbbrevSectionAddr; + U1_T * mLineStringTable; + U8_T mLineStringTableAddr; + U4_T mLineStringTableSize; + DIO_AbbrevSet * mAbbrevList; + ELF_Section * mAbbrevSection; }; typedef struct DIO_Cache DIO_Cache; @@ -72,30 +81,25 @@ static ELF_Section * sSection; static int sBigEndian; static int sAddressSize; static int sRefAddressSize; +static int sSectionRefSize; static U1_T * sData; static U8_T sDataPos; static U8_T sDataLen; static DIO_UnitDescriptor * sUnit; static void dio_CloseELF(ELF_File * File) { - U4_T n, m; DIO_Cache * Cache = (DIO_Cache *)File->dwarf_io_cache; if (Cache == NULL) return; - if (Cache->mAbbrevTable != NULL) { - for (n = 0; n < ABBREV_TABLE_SIZE; n++) { - DIO_AbbrevSet * Set = Cache->mAbbrevTable[n]; - while (Set != NULL) { - DIO_AbbrevSet * Next = Set->mNext; - for (m = 0; m < Set->mSize; m++) { - loc_free(Set->mTable[m]); - } - loc_free(Set->mTable); - loc_free(Set); - Set = Next; - } + while (Cache->mAbbrevList != NULL) { + U4_T m; + DIO_AbbrevSet * Set = Cache->mAbbrevList; + Cache->mAbbrevList = Set->mNext; + for (m = 0; m < Set->mSize; m++) { + loc_free(Set->mTable[m]); } - loc_free(Cache->mAbbrevTable); + loc_free(Set->mTable); + loc_free(Set); } loc_free(Cache); File->dwarf_io_cache = NULL; @@ -130,14 +134,17 @@ void dio_EnterSection(DIO_UnitDescriptor * Unit, ELF_Section * Section, U8_T Off sAddressSize = Unit->mAddressSize; if (Unit->mVersion < 3) sRefAddressSize = Unit->mAddressSize; else sRefAddressSize = Unit->m64bit ? 8 : 4; + sSectionRefSize = Unit->m64bit ? 8 : 4; } else if (Section->file->elf64) { sAddressSize = 8; sRefAddressSize = 8; + sSectionRefSize = 8; } else { sAddressSize = 4; sRefAddressSize = 4; + sSectionRefSize = 4; } sUnit = Unit; dio_gEntryPos = 0; @@ -161,6 +168,10 @@ U1_T * dio_GetDataPtr(void) { return sData + sDataPos; } +ELF_Section * dio_GetSection(void) { + return sSection; +} + void dio_Skip(I8_T Bytes) { if (sDataPos + Bytes > sDataLen) exception(ERR_EOF); sDataPos += Bytes; @@ -196,6 +207,15 @@ U2_T dio_ReadU2(void) { return sBigEndian ? (x0 << 8) | x1 : x0 | (x1 << 8); } +U4_T dio_ReadU3(void) { + U4_T x0, x1, x2; + if (sDataPos + 3 > sDataLen) exception(ERR_EOF); + x0 = sData[sDataPos++]; + x1 = sData[sDataPos++]; + x2 = sData[sDataPos++]; + return sBigEndian ? (x0 << 16) | (x1 << 8) | x2 : x0 | (x1 << 8) | (x2 << 16); +} + U4_T dio_ReadU4(void) { #if defined(__BYTE_ORDER__) U4_T x; @@ -283,27 +303,40 @@ I8_T dio_ReadS8LEB128(void) { } U8_T dio_ReadAddressX(ELF_Section ** s, int size) { - U8_T pos = sDataPos; - switch (size) { - case 2: { - U2_T x = dio_ReadU2(); - drl_relocate(sSection, pos, &x, sizeof(x), s); - return x; - } - case 4: { - U4_T x = dio_ReadU4(); - drl_relocate(sSection, pos, &x, sizeof(x), s); - return x; - } - case 8: { - U8_T x = dio_ReadU8(); - drl_relocate(sSection, pos, &x, sizeof(x), s); - return x; + if (sSection->relocate != NULL) { + U8_T pos = sDataPos; + switch (size) { + case 1: { + U1_T x = dio_ReadU1(); + drl_relocate(sSection, pos, &x, sizeof(x), s); + return x; + } + case 2: { + U2_T x = dio_ReadU2(); + drl_relocate(sSection, pos, &x, sizeof(x), s); + return x; + } + case 4: { + U4_T x = dio_ReadU4(); + drl_relocate(sSection, pos, &x, sizeof(x), s); + return x; + } + case 8: { + U8_T x = dio_ReadU8(); + drl_relocate(sSection, pos, &x, sizeof(x), s); + return x; + } + } } - default: - str_exception(ERR_INV_DWARF, "Invalid data size"); - return 0; + if (s != NULL) *s = NULL; + switch (size) { + case 1: return dio_ReadU1(); + case 2: return dio_ReadU2(); + case 4: return dio_ReadU4(); + case 8: return dio_ReadU8(); + default: str_exception(ERR_INV_DWARF, "Invalid data size"); } + return 0; } U8_T dio_ReadAddress(ELF_Section ** s) { @@ -318,26 +351,57 @@ char * dio_ReadString(void) { return Res; } -static U1_T * dio_LoadStringTable(ELF_File * File, U8_T * StringTableAddr, U4_T * StringTableSize) { - DIO_Cache * Cache = dio_GetCache(File); +void dio_ReadSectionPointer(U2_T Form, ELF_Section ** Section, U8_T * Offs, ELF_Section * DefSection) { + if (Form == FORM_ADDR || Form == FORM_SEC_OFFSET) { + *Offs = dio_gFormData; + *Section = dio_gFormSection; + } + else { + dio_ChkData(Form); + *Offs = dio_gFormData; + *Section = NULL; + } + if (*Section == NULL) { + *Section = DefSection; + } + if (*Section != NULL) { + *Offs -= (*Section)->addr; + } +} - if (Cache->mStringTable == NULL) { - U4_T ID; - ELF_Section * Section = NULL; +static void dio_FindSection(ELF_File * File, const char * Name, ELF_Section ** Res) { + ELF_Section * Section = NULL; + U4_T ID; - for (ID = 1; ID < File->section_cnt; ID++) { - if (strcmp(File->sections[ID].name, ".debug_str") == 0) { - if (Section != NULL) { - str_exception(ERR_INV_DWARF, "More then one .debug_str section in a file"); - } - Section = File->sections + ID; - assert(Section->file == File); + for (ID = 1; ID < File->section_cnt; ID++) { + if (strcmp(File->sections[ID].name, Name) == 0) { + if (Section != NULL) { + str_exception(ERR_INV_DWARF, "More than one .debug_str section in a file"); } + Section = File->sections + ID; + assert(Section->file == File); } + } - if (Section == NULL) { - str_exception(ERR_INV_DWARF, "Section .debug_str not found"); - } + if (Section == NULL) { + str_fmt_exception(ERR_INV_DWARF, "Section %s not found", Name); + } + + *Res = Section; +} + +static U1_T * dio_LoadStringTable(ELF_File * File, ELF_Section * Section, U8_T * StringTableAddr, U4_T * StringTableSize) { + DIO_Cache * Cache = dio_GetCache(File); + + if (Section != NULL) { + if (elf_load(Section) < 0) str_fmt_exception(errno, "Cannot read %s section", Section->name); + *StringTableAddr = Section->addr; + *StringTableSize = Section->size; + return (U1_T *)Section->data; + } + + if (Cache->mStringTable == NULL) { + dio_FindSection(File, ".debug_str", &Section); if (elf_load(Section) < 0) { str_exception(errno, "Cannot read .debug_str section"); @@ -353,9 +417,38 @@ static U1_T * dio_LoadStringTable(ELF_File * File, U8_T * StringTableAddr, U4_T return Cache->mStringTable; } -static U1_T * dio_LoadAltStringTable(ELF_File * File, U8_T * StringTableAddr, U4_T * StringTableSize) { +static U1_T * dio_LoadLineStringTable(ELF_File * File, ELF_Section * Section, U8_T * StringTableAddr, U4_T * StringTableSize) { + DIO_Cache * Cache = dio_GetCache(File); + + if (Section != NULL) { + if (elf_load(Section) < 0) str_fmt_exception(errno, "Cannot read %s section", Section->name); + *StringTableAddr = Section->addr; + *StringTableSize = Section->size; + return (U1_T *)Section->data; + } + + if (Cache->mLineStringTable == NULL) { + ELF_Section * Section = NULL; + + dio_FindSection(File, ".debug_line_str", &Section); + + if (elf_load(Section) < 0) { + str_exception(errno, "Cannot read .debug_line_str section"); + } + + Cache->mLineStringTableAddr = Section->addr; + Cache->mLineStringTableSize = (size_t)Section->size; + Cache->mLineStringTable = (U1_T *)Section->data; + } + + *StringTableAddr = Cache->mLineStringTableAddr; + *StringTableSize = Cache->mLineStringTableSize; + return Cache->mLineStringTable; +} + +static U1_T * dio_LoadAltStringTable(ELF_File * File, ELF_Section * Section, U8_T * StringTableAddr, U4_T * StringTableSize) { if (File->dwz_file == NULL) str_exception(errno, "Cannot open DWZ file"); - return dio_LoadStringTable(File->dwz_file, StringTableAddr, StringTableSize); + return dio_LoadStringTable(File->dwz_file, Section, StringTableAddr, StringTableSize); } static void dio_ReadFormAddr(void) { @@ -376,15 +469,19 @@ static void dio_ReadFormData(U1_T Size, U8_T Data) { dio_gFormDataSize = Size; } +static void dio_ReadFormDataNoAddr(U1_T Size, U8_T Data) { + dio_gFormData = Data; + dio_gFormDataSize = Size; +} + static void dio_ReadFormRef(void) { dio_gFormData = dio_ReadU4(); dio_gFormDataSize = 4; } static void dio_ReadFormAltRef(void) { - int size = sUnit->m64bit ? 8 : 4; - dio_gFormData = dio_ReadAddressX(&dio_gFormSection, size); - dio_gFormDataSize = size; + dio_gFormData = dio_ReadAddressX(&dio_gFormSection, sSectionRefSize); + dio_gFormDataSize = sSectionRefSize; dio_gFormData += sSection->addr; } @@ -417,8 +514,9 @@ static void dio_ReadFormString(void) { static void dio_ReadFormStringRef(void) { U8_T StringTableAddr = 0; U4_T StringTableSize = 0; - U1_T * StringTable = dio_LoadStringTable(sSection->file, &StringTableAddr, &StringTableSize); - U8_T Offset = dio_ReadAddressX(&dio_gFormSection, sUnit->m64bit ? 8 : 4) - StringTableAddr; + U8_T Offset = dio_ReadAddressX(&dio_gFormSection, sSectionRefSize); + U1_T * StringTable = dio_LoadStringTable(sSection->file, dio_gFormSection, &StringTableAddr, &StringTableSize); + Offset -= StringTableAddr; dio_gFormDataAddr = StringTable + Offset; dio_gFormDataSize = 1; for (;;) { @@ -430,11 +528,53 @@ static void dio_ReadFormStringRef(void) { } } +static void dio_ReadFormLineStringRef(void) { + U8_T StringTableAddr = 0; + U4_T StringTableSize = 0; + U8_T Offset = dio_ReadAddressX(&dio_gFormSection, sSectionRefSize); + U1_T * StringTable = dio_LoadLineStringTable(sSection->file, dio_gFormSection, &StringTableAddr, &StringTableSize); + Offset -= StringTableAddr; + dio_gFormDataAddr = StringTable + Offset; + dio_gFormDataSize = 1; + for (;;) { + if (Offset >= StringTableSize) { + str_exception(ERR_INV_DWARF, "Invalid FORM_LINE_STRP attribute"); + } + if (StringTable[Offset++] == 0) break; + dio_gFormDataSize++; + } +} + +static void dio_ReadFormStringIndex(U4_T index) { + U8_T Offset = 0; + U8_T Pos = sDataPos; + ELF_Section * Section = sSection; + U8_T StringTableAddr = 0; + U4_T StringTableSize = 0; + U1_T * StringTable = NULL; + if (sUnit->mStrOffsetsSection == NULL) str_exception(ERR_INV_DWARF, "Invalid FORM_STRX attribute"); + dio_EnterSection(sUnit, sUnit->mStrOffsetsSection, sUnit->mStrOffsetsOffs + index * sSectionRefSize); + Offset = dio_ReadAddressX(&dio_gFormSection, sSectionRefSize); + StringTable = dio_LoadStringTable(sSection->file, dio_gFormSection, &StringTableAddr, &StringTableSize); + Offset -= StringTableAddr; + dio_EnterSection(sUnit, Section, Pos); + dio_gFormDataAddr = StringTable + Offset; + dio_gFormDataSize = 1; + for (;;) { + if (Offset >= StringTableSize) { + str_exception(ERR_INV_DWARF, "Invalid FORM_STRX attribute"); + } + if (StringTable[Offset++] == 0) break; + dio_gFormDataSize++; + } +} + static void dio_ReadFormAltStringRef(void) { U8_T StringTableAddr = 0; U4_T StringTableSize = 0; - U1_T * StringTable = dio_LoadAltStringTable(sSection->file, &StringTableAddr, &StringTableSize); - U8_T Offset = dio_ReadAddressX(&dio_gFormSection, sUnit->m64bit ? 8 : 4) - StringTableAddr; + U8_T Offset = dio_ReadAddressX(&dio_gFormSection, sSectionRefSize); + U1_T * StringTable = dio_LoadAltStringTable(sSection->file, dio_gFormSection, &StringTableAddr, &StringTableSize); + Offset -= StringTableAddr; dio_gFormDataAddr = StringTable + Offset; dio_gFormDataSize = 1; for (;;) { @@ -446,25 +586,50 @@ static void dio_ReadFormAltStringRef(void) { } } +static void dio_ReadFormAddressIndex(U4_T index) { + U8_T Pos = sDataPos; + ELF_Section * Section = sSection; + if (sUnit->mAddrInfoSection == NULL) str_exception(ERR_INV_DWARF, "Invalid FORM_ADDRX attribute"); + dio_EnterSection(sUnit, sUnit->mAddrInfoSection, sUnit->mAddrInfoOffs + index * sAddressSize); + dio_ReadFormAddr(); + dio_EnterSection(sUnit, Section, Pos); +} + +static void dio_ReadFormLocIndex(U4_T index) { + U8_T Pos = sDataPos; + ELF_Section * Section = sSection; + if (sUnit->mLocListsSection == NULL) str_exception(ERR_INV_DWARF, "Invalid FORM_LOCLISTX attribute"); + if (index >= sUnit->mLocListsOffsetEntryCount) str_exception(ERR_INV_DWARF, "Invalid FORM_LOCLISTX attribute"); + dio_EnterSection(sUnit, sUnit->mLocListsSection, sUnit->mLocListsOffs + index * sSectionRefSize); + dio_gFormData = (sSectionRefSize > 4 ? dio_ReadU8() : dio_ReadU4()) + sUnit->mLocListsOffs; + dio_gFormDataSize = sSectionRefSize; + dio_EnterSection(sUnit, Section, Pos); +} + +static void dio_ReadFormRngIndex(U4_T index) { + U8_T Pos = sDataPos; + ELF_Section * Section = sSection; + if (sUnit->mRngListsSection == NULL) str_exception(ERR_INV_DWARF, "Invalid FORM_RNGLISTX attribute"); + if (index >= sUnit->mRngListsOffsetEntryCount) str_exception(ERR_INV_DWARF, "Invalid FORM_RNGLISTX attribute"); + dio_EnterSection(sUnit, sUnit->mRngListsSection, sUnit->mRngListsOffs + index * sSectionRefSize); + dio_gFormData = (sSectionRefSize > 4 ? dio_ReadU8() : dio_ReadU4()) + sUnit->mRngListsOffs; + dio_gFormDataSize = sSectionRefSize; + dio_EnterSection(sUnit, Section, Pos); +} + void dio_ReadAttribute(U2_T Attr, U2_T Form) { dio_gFormSection = NULL; dio_gFormDataAddr = NULL; dio_gFormDataSize = 0; dio_gFormData = 0; - if (sSection->relocate && - (Attr == AT_stmt_list || Attr == AT_ranges || - (Attr == AT_high_pc && Form != FORM_ADDR))) { - U4_T Size = 0; + if (sSection->relocate && (Attr == AT_stmt_list || Attr == AT_ranges || Attr == AT_high_pc)) { + /* Legacy special case: relocatable FORM_DATAn */ switch (Form) { - case FORM_DATA2 : Size = 2; break; - case FORM_DATA4 : Size = 4; break; - case FORM_DATA8 : Size = 8; break; - case FORM_SEC_OFFSET: Size = sUnit->m64bit ? 8 : 4; break; - default: str_exception(ERR_INV_DWARF, "FORM_DATA or FORM_SEC_OFFSET was expected"); + case FORM_DATA1 : dio_ReadFormData(1, dio_ReadAddressX(&dio_gFormSection, 1)); return; + case FORM_DATA2 : dio_ReadFormData(2, dio_ReadAddressX(&dio_gFormSection, 2)); return; + case FORM_DATA4 : dio_ReadFormData(4, dio_ReadAddressX(&dio_gFormSection, 4)); return; + case FORM_DATA8 : dio_ReadFormData(8, dio_ReadAddressX(&dio_gFormSection, 8)); return; } - dio_gFormData = dio_ReadAddressX(&dio_gFormSection, Size); - dio_gFormDataSize = Size; - return; } switch (Form) { case FORM_ADDR : dio_ReadFormAddr(); break; @@ -478,8 +643,9 @@ void dio_ReadAttribute(U2_T Attr, U2_T Form) { case FORM_DATA2 : dio_ReadFormData(2, dio_ReadU2()); break; case FORM_DATA4 : dio_ReadFormData(4, dio_ReadU4()); break; case FORM_DATA8 : dio_ReadFormData(8, dio_ReadU8()); break; - case FORM_SDATA : dio_ReadFormData(8, dio_ReadS8LEB128()); dio_gFormDataAddr = NULL; break; - case FORM_UDATA : dio_ReadFormData(8, dio_ReadU8LEB128()); dio_gFormDataAddr = NULL; break; + case FORM_DATA16 : dio_ReadFormBlock(16); break; + case FORM_SDATA : dio_ReadFormDataNoAddr(8, dio_ReadS8LEB128()); break; + case FORM_UDATA : dio_ReadFormDataNoAddr(8, dio_ReadU8LEB128()); break; case FORM_FLAG : dio_ReadFormData(1, dio_ReadU1()); break; case FORM_FLAG_PRESENT : dio_ReadFormData(0, 1); break; case FORM_STRING : dio_ReadFormString(); break; @@ -491,11 +657,22 @@ void dio_ReadAttribute(U2_T Attr, U2_T Form) { case FORM_REF4 : dio_ReadFormRelRef(Attr, dio_ReadU4()); break; case FORM_REF8 : dio_ReadFormRelRef(Attr, dio_ReadU8()); break; case FORM_REF_UDATA : dio_ReadFormRelRef(Attr, dio_ReadULEB128()); break; - case FORM_SEC_OFFSET: if (sUnit->m64bit) dio_ReadFormData(8, dio_ReadAddressX(&dio_gFormSection,8)); - else dio_ReadFormData(4, dio_ReadAddressX(&dio_gFormSection,4)); - break; + case FORM_SEC_OFFSET : dio_ReadFormData(sSectionRefSize, dio_ReadAddressX(&dio_gFormSection, sSectionRefSize)); break; case FORM_EXPRLOC : dio_ReadFormBlock(dio_ReadULEB128()); break; case FORM_REF_SIG8 : dio_ReadFormData(8, dio_ReadU8()); break; + case FORM_LINE_STRP : dio_ReadFormLineStringRef(); break; + case FORM_STRX : dio_ReadFormStringIndex(dio_ReadULEB128()); break; + case FORM_STRX1 : dio_ReadFormStringIndex(dio_ReadU1()); break; + case FORM_STRX2 : dio_ReadFormStringIndex(dio_ReadU2()); break; + case FORM_STRX3 : dio_ReadFormStringIndex(dio_ReadU3()); break; + case FORM_STRX4 : dio_ReadFormStringIndex(dio_ReadU4()); break; + case FORM_ADDRX : dio_ReadFormAddressIndex(dio_ReadULEB128()); break; + case FORM_ADDRX1 : dio_ReadFormAddressIndex(dio_ReadU1()); break; + case FORM_ADDRX2 : dio_ReadFormAddressIndex(dio_ReadU2()); break; + case FORM_ADDRX3 : dio_ReadFormAddressIndex(dio_ReadU3()); break; + case FORM_ADDRX4 : dio_ReadFormAddressIndex(dio_ReadU4()); break; + case FORM_LOCLISTX : dio_ReadFormLocIndex(dio_ReadULEB128()); break; + case FORM_RNGLISTX : dio_ReadFormRngIndex(dio_ReadULEB128()); break; default: str_fmt_exception(ERR_INV_DWARF, "Invalid FORM code 0x%04x", Form); } } @@ -531,6 +708,7 @@ int dio_ReadEntry(DIO_EntryCallBack CallBack, U2_T TargetAttr) { for (;;) { U2_T Attr = 0; U2_T Form = 0; + I8_T Value = 0; if (Init) { Form = DWARF_ENTRY_NO_CHILDREN; if (Abbr != NULL && Abbr->mChildren) Form = DWARF_ENTRY_HAS_CHILDREN; @@ -538,9 +716,11 @@ int dio_ReadEntry(DIO_EntryCallBack CallBack, U2_T TargetAttr) { } else if (Abbr != NULL) { if (AttrPos < Abbr->mAttrLen) { - Attr = Abbr->mAttrs[AttrPos++]; - Form = Abbr->mAttrs[AttrPos++]; + Attr = Abbr->mAttrs[AttrPos].mAttr; + Form = Abbr->mAttrs[AttrPos].mForm; + Value = Abbr->mAttrs[AttrPos].mValue; if (Form == FORM_INDIRECT) Form = (U2_T)dio_ReadULEB128(); + AttrPos++; } } else if (sDataPos <= dio_gEntryPos + EntrySize - 2) { @@ -567,10 +747,22 @@ int dio_ReadEntry(DIO_EntryCallBack CallBack, U2_T TargetAttr) { case AT_extension: break; default: + if (TargetAttr == AT_read_base_offsets) { + int ok = 0; + switch (Attr) { + case AT_addr_base: + case AT_str_offsets_base: + case AT_rnglists_base: + case AT_loclists_base: + ok = 1; + break; + } + if (ok) break; + } switch (Form) { case FORM_ADDR : sDataPos += sAddressSize; continue; case FORM_REF : sDataPos += 4; continue; - case FORM_GNU_REF_ALT : sDataPos += (sUnit->m64bit ? 8 : 4); continue; + case FORM_GNU_REF_ALT : sDataPos += sSectionRefSize; continue; case FORM_BLOCK1 : sDataPos += dio_ReadU1F(); continue; case FORM_BLOCK2 : sDataPos += dio_ReadU2(); continue; case FORM_BLOCK4 : sDataPos += dio_ReadU4(); continue; @@ -579,26 +771,51 @@ int dio_ReadEntry(DIO_EntryCallBack CallBack, U2_T TargetAttr) { case FORM_DATA2 : sDataPos += 2; continue; case FORM_DATA4 : sDataPos += 4; continue; case FORM_DATA8 : sDataPos += 8; continue; + case FORM_DATA16 : sDataPos += 16; continue; case FORM_SDATA : dio_ReadS8LEB128(); continue; case FORM_UDATA : dio_ReadU8LEB128(); continue; case FORM_FLAG : sDataPos++; continue; case FORM_FLAG_PRESENT : continue; case FORM_STRING : dio_ReadFormString(); continue; - case FORM_STRP : sDataPos += (sUnit->m64bit ? 8 : 4); continue; - case FORM_GNU_STRP_ALT : sDataPos += (sUnit->m64bit ? 8 : 4); continue; + case FORM_STRP : sDataPos += sSectionRefSize; continue; + case FORM_LINE_STRP : sDataPos += sSectionRefSize; continue; + case FORM_GNU_STRP_ALT : sDataPos += sSectionRefSize; continue; case FORM_REF_ADDR : sDataPos += sRefAddressSize; continue; case FORM_REF1 : sDataPos++; continue; case FORM_REF2 : sDataPos += 2; continue; case FORM_REF4 : sDataPos += 4; continue; case FORM_REF8 : sDataPos += 8; continue; case FORM_REF_UDATA : dio_ReadULEB128(); continue; - case FORM_SEC_OFFSET : sDataPos += (sUnit->m64bit ? 8 : 4); continue; + case FORM_SEC_OFFSET : sDataPos += sSectionRefSize; continue; case FORM_EXPRLOC : sDataPos += dio_ReadULEB128(); continue; case FORM_REF_SIG8 : sDataPos += 8; continue; + case FORM_IMPLICIT_CONST: continue; + case FORM_STRX : dio_ReadULEB128(); continue; + case FORM_STRX1 : sDataPos++; continue; + case FORM_STRX2 : sDataPos += 2; continue; + case FORM_STRX3 : sDataPos += 3; continue; + case FORM_STRX4 : sDataPos += 4; continue; + case FORM_ADDRX : dio_ReadULEB128(); continue; + case FORM_ADDRX1 : sDataPos++; continue; + case FORM_ADDRX2 : sDataPos += 2; continue; + case FORM_ADDRX3 : sDataPos += 3; continue; + case FORM_ADDRX4 : sDataPos += 4; continue; + case FORM_LOCLISTX : dio_ReadULEB128(); continue; + case FORM_RNGLISTX : dio_ReadULEB128(); continue; } } } - if (Attr != 0 && Form != 0) dio_ReadAttribute(Attr, Form); + if (Attr != 0 && Form != 0) { + if (Form == FORM_IMPLICIT_CONST) { + dio_gFormSection = NULL; + dio_gFormDataAddr = NULL; + dio_gFormDataSize = 0; + dio_gFormData = Value; + } + else { + dio_ReadAttribute(Attr, Form); + } + } if (Tag == TAG_compile_unit || Tag == TAG_partial_unit || Tag == TAG_type_unit) { if (Attr == AT_sibling && sUnit->mUnitSize == 0) { dio_ChkRef(Form); @@ -617,76 +834,20 @@ int dio_ReadEntry(DIO_EntryCallBack CallBack, U2_T TargetAttr) { return 1; } -static void dio_FindAbbrevTable(void); - -void dio_ReadUnit(DIO_UnitDescriptor * Unit, DIO_EntryCallBack CallBack) { - memset(Unit, 0, sizeof(DIO_UnitDescriptor)); - sUnit = Unit; - sUnit->mSection = sSection; - sUnit->mUnitOffs = sDataPos; - sUnit->m64bit = 0; - if (strcmp(sSection->name, ".debug") != 0) { - ELF_Section * Sect = NULL; - DIO_Cache * Cache = dio_GetCache(sSection->file); - sUnit->mUnitSize = dio_ReadU4(); - if (sUnit->mUnitSize == 0xffffffffu) { - sUnit->m64bit = 1; - sUnit->mUnitSize = dio_ReadU8(); - sUnit->mUnitSize += 12; - } - else { - sUnit->mUnitSize += 4; - } - sUnit->mVersion = dio_ReadU2(); - sUnit->mAbbrevTableOffs = dio_ReadAddressX(&Sect, sUnit->m64bit ? 8 : 4); - sUnit->mAbbrevTableOffs -= Cache->mAbbrevSectionAddr; - sUnit->mAddressSize = dio_ReadU1(); - if (strcmp(sSection->name, ".debug_types") == 0) { - sUnit->mTypeSignature = dio_ReadU8(); - sUnit->mTypeOffset = sUnit->m64bit ? dio_ReadU8() : dio_ReadU4(); - } - dio_FindAbbrevTable(); - } - else { - sUnit->mVersion = 1; - sUnit->mAddressSize = 4; - } - sAddressSize = sUnit->mAddressSize; - if (sUnit->mVersion < 3) sRefAddressSize = sUnit->mAddressSize; - else sRefAddressSize = sUnit->m64bit ? 8 : 4; - while (sUnit->mUnitSize == 0 || sDataPos < sUnit->mUnitOffs + sUnit->mUnitSize) { - dio_ReadEntry(CallBack, 0); - } - sUnit = NULL; -} - -#define dio_AbbrevTableHash(Offset) (((unsigned)(Offset)) / 16 % ABBREV_TABLE_SIZE) - -void dio_LoadAbbrevTable(ELF_File * File) { - U8_T TableOffset = 0; - ELF_Section * Section = NULL; - static U2_T * AttrBuf = NULL; +static void dio_LoadAbbrevTable(DIO_UnitDescriptor * Unit) { + ELF_File * File = Unit->mSection->file; + DIO_Cache * Cache = dio_GetCache(File); + static DIO_AbbreviationAttr * AttrBuf = NULL; static U4_T AttrBufSize = 0; static DIO_Abbreviation ** AbbrevBuf = NULL; static U4_T AbbrevBufSize = 0; U4_T AbbrevBufPos = 0; - DIO_Cache * Cache = dio_GetCache(File); - unsigned i; - if (Cache->mAbbrevTable != NULL) return; - Cache->mAbbrevTable = (DIO_AbbrevSet **)loc_alloc_zero(sizeof(DIO_AbbrevSet *) * ABBREV_TABLE_SIZE); - - for (i = 1; i < File->section_cnt; i++) { - if (strcmp(File->sections[i].name, ".debug_abbrev") == 0) { - if (Section != NULL) { - str_exception(ERR_INV_DWARF, "More then one .debug_abbrev section in a file"); - } - Section = File->sections + i; - } + if (Cache->mAbbrevSection == NULL) { + dio_FindSection(File, ".debug_abbrev", &Cache->mAbbrevSection); } - if (Section == NULL) return; - Cache->mAbbrevSectionAddr = Section->addr; - dio_EnterSection(NULL, Section, 0); + + dio_EnterSection(Unit, Cache->mAbbrevSection, Unit->mAbbrevTableAddr - Cache->mAbbrevSection->addr); for (;;) { U4_T AttrPos = 0; U2_T Tag = 0; @@ -694,19 +855,17 @@ void dio_LoadAbbrevTable(ELF_File * File) { U4_T ID = dio_ReadULEB128(); if (ID == 0) { /* End of compilation unit */ - U4_T Hash = dio_AbbrevTableHash(TableOffset); DIO_AbbrevSet * AbbrevSet = (DIO_AbbrevSet *)loc_alloc_zero(sizeof(DIO_AbbrevSet)); - AbbrevSet->mOffset = TableOffset; + AbbrevSet->mOffset = Unit->mAbbrevTableAddr - Cache->mAbbrevSection->addr; AbbrevSet->mTable = (DIO_Abbreviation **)loc_alloc(sizeof(DIO_Abbreviation *) * AbbrevBufPos); AbbrevSet->mSize = AbbrevBufPos; - AbbrevSet->mNext = Cache->mAbbrevTable[Hash]; - Cache->mAbbrevTable[Hash] = AbbrevSet; + AbbrevSet->mNext = Cache->mAbbrevList; + Cache->mAbbrevList = AbbrevSet; memcpy(AbbrevSet->mTable, AbbrevBuf, sizeof(DIO_Abbreviation *) * AbbrevBufPos); memset(AbbrevBuf, 0, sizeof(DIO_Abbreviation *) * AbbrevBufPos); - AbbrevBufPos = 0; - if (sDataPos >= Section->size) break; - TableOffset = sDataPos; - continue; + Unit->mAbbrevTable = AbbrevSet->mTable; + Unit->mAbbrevTableSize = AbbrevSet->mSize; + break; } if (ID >= 0x1000000) str_exception(ERR_INV_DWARF, "Invalid abbreviation table"); if (ID >= AbbrevBufPos) { @@ -733,43 +892,116 @@ void dio_LoadAbbrevTable(ELF_File * File) { if (Attr == 0 && Form == 0) { DIO_Abbreviation * Abbr; if (AbbrevBuf[ID] != NULL) str_exception(ERR_INV_DWARF, "Invalid abbreviation table"); - Abbr = (DIO_Abbreviation *)loc_alloc_zero(sizeof(DIO_Abbreviation) - sizeof(U2_T) * 2 + sizeof(U2_T) * AttrPos); + Abbr = (DIO_Abbreviation *)loc_alloc_zero(sizeof(DIO_Abbreviation) - sizeof(DIO_AbbreviationAttr) + sizeof(DIO_AbbreviationAttr) * AttrPos); Abbr->mTag = Tag; Abbr->mChildren = Children; Abbr->mAttrLen = AttrPos; - memcpy(Abbr->mAttrs, AttrBuf, sizeof(U2_T) * AttrPos); + memcpy(Abbr->mAttrs, AttrBuf, sizeof(DIO_AbbreviationAttr) * AttrPos); AbbrevBuf[ID] = Abbr; break; } - if (AttrBufSize < AttrPos + 2) { + if (AttrBufSize <= AttrPos) { AttrBufSize = AttrPos + 256; - AttrBuf = (U2_T *)loc_realloc(AttrBuf, sizeof(U2_T) * AttrBufSize); + AttrBuf = (DIO_AbbreviationAttr *)loc_realloc(AttrBuf, sizeof(DIO_AbbreviationAttr) * AttrBufSize); } - AttrBuf[AttrPos++] = (U2_T)Attr; - AttrBuf[AttrPos++] = (U2_T)Form; + AttrBuf[AttrPos].mAttr = (U2_T)Attr; + AttrBuf[AttrPos].mForm = (U2_T)Form; + AttrBuf[AttrPos].mValue = Form == FORM_IMPLICIT_CONST ? dio_ReadS8LEB128() : 0; + AttrPos++; } } - assert(AbbrevBufPos == 0); dio_ExitSection(); } -static void dio_FindAbbrevTable(void) { - DIO_Cache * Cache = dio_GetCache(sSection->file); - if (Cache->mAbbrevTable != NULL) { - U4_T Hash = dio_AbbrevTableHash(sUnit->mAbbrevTableOffs); - DIO_AbbrevSet * AbbrevSet = Cache->mAbbrevTable[Hash]; - while (AbbrevSet != NULL) { - if (AbbrevSet->mOffset == sUnit->mAbbrevTableOffs) { - sUnit->mAbbrevTable = AbbrevSet->mTable; - sUnit->mAbbrevTableSize = AbbrevSet->mSize; - return; +static void dio_ReadUnitBaseOffsets(U2_T Tag, U2_T Attr, U2_T Form) { + ELF_Section * Section = NULL; + ELF_File * File = sSection->file; + + switch (Attr) { + case AT_addr_base: + dio_FindSection(File, ".debug_addr", &Section); + dio_ReadSectionPointer(Form, &sUnit->mAddrInfoSection, &sUnit->mAddrInfoOffs, Section); + break; + case AT_str_offsets_base: + dio_FindSection(File, ".debug_str_offsets", &Section); + dio_ReadSectionPointer(Form, &sUnit->mStrOffsetsSection, &sUnit->mStrOffsetsOffs, Section); + break; + case AT_rnglists_base: + dio_FindSection(File, ".debug_rnglists", &Section); + dio_ReadSectionPointer(Form, &sUnit->mRngListsSection, &sUnit->mRngListsOffs, Section); + break; + case AT_loclists_base: + dio_FindSection(File, ".debug_loclists", &Section); + dio_ReadSectionPointer(Form, &sUnit->mLocListsSection, &sUnit->mLocListsOffs, Section); + break; + } +} + +void dio_ReadUnit(DIO_UnitDescriptor * Unit, DIO_EntryCallBack CallBack) { + memset(Unit, 0, sizeof(DIO_UnitDescriptor)); + sUnit = Unit; + sUnit->mSection = sSection; + sUnit->mUnitOffs = sDataPos; + sUnit->m64bit = 0; + if (strcmp(sSection->name, ".debug") == 0) { + sUnit->mVersion = 1; + sUnit->mAddressSize = 4; + } + else { + ELF_Section * Sect = NULL; + U8_T DataPos = 0; + sUnit->mUnitSize = dio_ReadAddressX(&Sect, 4); + if (sUnit->mUnitSize == 0xffffffff) { + sUnit->m64bit = 1; + sUnit->mUnitSize = dio_ReadU8(); + sUnit->mUnitSize += 12; + } + else { + sUnit->mUnitSize += 4; + } + sUnit->mVersion = dio_ReadU2(); + if (sUnit->mVersion < 5) { + sUnit->mAbbrevTableAddr = dio_ReadAddressX(&Sect, sUnit->m64bit ? 8 : 4); + sUnit->mAddressSize = dio_ReadU1(); + if (strcmp(sSection->name, ".debug_types") == 0) { + sUnit->mTypeSignature = dio_ReadU8(); + sUnit->mTypeOffset = sUnit->m64bit ? dio_ReadU8() : dio_ReadU4(); + } + } + else { + sUnit->mUnitType = dio_ReadU1(); + sUnit->mAddressSize = dio_ReadU1(); + sUnit->mAbbrevTableAddr = dio_ReadAddressX(&Sect, sUnit->m64bit ? 8 : 4); + switch (sUnit->mUnitType) { + case DW_UT_skeleton: + case DW_UT_split_compile: + sUnit->mCompUnitID = dio_ReadU8(); + break; + case DW_UT_type: + case DW_UT_split_type: + sUnit->mTypeSignature = dio_ReadU8(); + sUnit->mTypeOffset = sUnit->m64bit ? dio_ReadU8() : dio_ReadU4(); + break; } - AbbrevSet = AbbrevSet->mNext; } + DataPos = sDataPos; + dio_ExitSection(); + dio_LoadAbbrevTable(Unit); + dio_EnterSection(Unit, Unit->mSection, DataPos); } - sUnit->mAbbrevTable = NULL; - sUnit->mAbbrevTableSize = 0; - str_exception(ERR_INV_DWARF, "Invalid abbreviation table offset"); + sAddressSize = sUnit->mAddressSize; + if (sUnit->mVersion < 3) sRefAddressSize = sUnit->mAddressSize; + else sRefAddressSize = sUnit->m64bit ? 8 : 4; + sSectionRefSize = sUnit->m64bit ? 8 : 4; + if (sUnit->mVersion >= 5) { + U8_T DataPos = sDataPos; + dio_ReadEntry(dio_ReadUnitBaseOffsets, AT_read_base_offsets); + sDataPos = DataPos; + } + while (sUnit->mUnitSize == 0 || sDataPos < sUnit->mUnitOffs + sUnit->mUnitSize) { + dio_ReadEntry(CallBack, 0); + } + sUnit = NULL; } void dio_ChkFlag(U2_T Form) { @@ -799,6 +1031,11 @@ void dio_ChkRef(U2_T Form) { void dio_ChkAddr(U2_T Form) { switch (Form) { case FORM_ADDR : + case FORM_ADDRX : + case FORM_ADDRX1 : + case FORM_ADDRX2 : + case FORM_ADDRX3 : + case FORM_ADDRX4 : return; } str_exception(ERR_INV_DWARF, "FORM_ADDR expected"); @@ -813,6 +1050,7 @@ void dio_ChkData(U2_T Form) { case FORM_SDATA : case FORM_UDATA : case FORM_SEC_OFFSET: + case FORM_IMPLICIT_CONST: return; } str_exception(ERR_INV_DWARF, "FORM_DATA expected"); @@ -828,6 +1066,7 @@ void dio_ChkBlock(U2_T Form, U1_T ** Buf, size_t * Size) { case FORM_DATA2 : case FORM_DATA4 : case FORM_DATA8 : + case FORM_DATA16 : case FORM_EXPRLOC : case FORM_SEC_OFFSET: assert(dio_gFormDataAddr >= sSection->data); @@ -841,9 +1080,18 @@ void dio_ChkBlock(U2_T Form, U1_T ** Buf, size_t * Size) { } void dio_ChkString(U2_T Form) { - if (Form == FORM_STRING) return; - if (Form == FORM_STRP) return; - if (Form == FORM_GNU_STRP_ALT) return; + switch (Form) { + case FORM_STRING: + case FORM_STRP: + case FORM_LINE_STRP: + case FORM_GNU_STRP_ALT: + case FORM_STRX: + case FORM_STRX1: + case FORM_STRX2: + case FORM_STRX3: + case FORM_STRX4: + return; + } str_exception(ERR_INV_DWARF, "FORM_STRING expected"); } diff --git a/agent/tcf/services/dwarfio.h b/agent/tcf/services/dwarfio.h index 60fd13b5..69654d28 100644 --- a/agent/tcf/services/dwarfio.h +++ b/agent/tcf/services/dwarfio.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2014 Wind River Systems, Inc. and others. + * Copyright (c) 2006-2023 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. @@ -31,14 +31,31 @@ typedef struct DIO_UnitDescriptor { ELF_Section * mSection; U2_T mVersion; U1_T m64bit; + U1_T mUnitType; U1_T mAddressSize; U8_T mUnitOffs; U8_T mUnitSize; - U8_T mAbbrevTableOffs; + U8_T mAbbrevTableAddr; + U8_T mCompUnitID; U8_T mTypeSignature; U8_T mTypeOffset; + struct DIO_Abbreviation ** mAbbrevTable; U4_T mAbbrevTableSize; + + ELF_Section * mStrOffsetsSection; + U8_T mStrOffsetsOffs; + + ELF_Section * mAddrInfoSection; + U8_T mAddrInfoOffs; + + ELF_Section * mLocListsSection; + U8_T mLocListsOffs; + U4_T mLocListsOffsetEntryCount; + + ELF_Section * mRngListsSection; + U8_T mRngListsOffs; + U4_T mRngListsOffsetEntryCount; } DIO_UnitDescriptor; extern U8_T dio_gEntryPos; @@ -56,9 +73,11 @@ extern void dio_SetPos(U8_T Pos); extern void dio_Read(U1_T * Buf, U4_T Size); extern U8_T dio_GetPos(void); /* Offset in the section */ extern U1_T * dio_GetDataPtr(void); +extern ELF_Section * dio_GetSection(void); extern U1_T dio_ReadU1(void); extern U2_T dio_ReadU2(void); +extern U4_T dio_ReadU3(void); extern U4_T dio_ReadU4(void); extern U8_T dio_ReadU8(void); @@ -77,6 +96,8 @@ extern U8_T dio_ReadAddress(ELF_Section ** s); extern char * dio_ReadString(void); +extern void dio_ReadSectionPointer(U2_T Form, ELF_Section ** Section, U8_T * Offs, ELF_Section * DefSection); + extern void dio_ReadAttribute(U2_T Attr, U2_T Form); typedef void (*DIO_EntryCallBack)(U2_T /* Tag */, U2_T /* Attr */, U2_T /* Form */); @@ -93,8 +114,6 @@ extern int dio_ReadEntry(DIO_EntryCallBack CallBack, U2_T Attr); #define DWARF_ENTRY_NO_CHILDREN 2 #define DWARF_ENTRY_HAS_CHILDREN 3 -extern void dio_LoadAbbrevTable(ELF_File * File); - extern void dio_ChkFlag(U2_T Form); extern void dio_ChkRef(U2_T Form); extern void dio_ChkAddr(U2_T Form); diff --git a/agent/tcf/services/elf-symbols.h b/agent/tcf/services/elf-symbols.h index 989e09cb..a199a4a6 100644 --- a/agent/tcf/services/elf-symbols.h +++ b/agent/tcf/services/elf-symbols.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2014 Wind River Systems, Inc. and others. + * Copyright (c) 2012-2021 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. @@ -49,7 +49,7 @@ extern int elf_enumerate_symbols(Context * ctx, const char * file_name, Enumerat * On error returns -1 and sets errno. * On success returns 0. */ -extern int elf_symbol_info(Symbol * sym, ELF_SymbolInfo * elf_sym); +extern int elf_symbol_info(const Symbol * sym, ELF_SymbolInfo * elf_sym); /* * Get the TCF Symbol from ELF symbol info. diff --git a/agent/tcf/services/expressions.c b/agent/tcf/services/expressions.c index 4bc96d71..61561d20 100644 --- a/agent/tcf/services/expressions.c +++ b/agent/tcf/services/expressions.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -169,7 +169,7 @@ static void ini_value(Value * v) { v->ctx = expression_context; } -void set_value(Value * v, void * data, size_t size, int be) { +static void set_no_value(Value * v) { v->sym = NULL; v->reg = NULL; v->loc = NULL; @@ -179,11 +179,18 @@ void set_value(Value * v, void * data, size_t size, int be) { v->func_cb = NULL; v->field_cb = NULL; v->sym_list = NULL; - v->size = (ContextAddress)size; - v->big_endian = be; + v->size = 0; + v->big_endian = 0; v->binary_scale = 0; v->decimal_scale = 0; v->bit_stride = 0; + v->value = NULL; +} + +void set_value(Value * v, void * data, size_t size, int be) { + set_no_value(v); + v->big_endian = be; + v->size = (ContextAddress)size; v->value = tmp_alloc(size); if (data == NULL) memset(v->value, 0, size); else memcpy(v->value, data, size); @@ -202,7 +209,7 @@ static void set_int_value(Value * v, size_t size, uint64_t n) { case 2: buf.u16 = (uint16_t)n; break; case 4: buf.u32 = (uint32_t)n; break; case 8: buf.u64 = n; break; - default: assert(0); + default: buf.u64 = 0; assert(0); } set_value(v, &buf, size, big_endian); } @@ -215,7 +222,7 @@ static void set_fp_value(Value * v, size_t size, double n) { switch (size) { case 4: buf.f = (float)n; break; case 8: buf.d = n; break; - default: assert(0); + default: buf.d = 0; assert(0); } set_value(v, &buf, size, big_endian); } @@ -1075,9 +1082,14 @@ static int sym2value(int mode, Symbol * sym, Value * v) { v->remote = 1; } else { - if (state->pieces_cnt == 1 && state->pieces->implicit_pointer == 0 && - state->pieces->reg != NULL && state->pieces->reg->size == state->pieces->size) { - v->reg = state->pieces->reg; + if (state->pieces_cnt == 1 && state->pieces->implicit_pointer == 0) { + LocationPiece * p = state->pieces; + if (p->value != NULL) { + set_value(v, p->value, p->size, loc_info->big_endian); + } + if (p->reg != NULL && p->reg->size == p->size && state->ctx == v->ctx) { + v->reg = p->reg; + } } v->loc = state; } @@ -1122,9 +1134,14 @@ static int sym2value(int mode, Symbol * sym, Value * v) { v->remote = 1; } else { - if (state->pieces_cnt == 1 && state->pieces->implicit_pointer == 0 && - state->pieces->reg != NULL && state->pieces->reg->size == state->pieces->size) { - v->reg = state->pieces->reg; + if (state->pieces_cnt == 1 && state->pieces->implicit_pointer == 0) { + LocationPiece * p = state->pieces; + if (p->value != NULL) { + set_value(v, p->value, p->size, loc_info->big_endian); + } + if (p->reg != NULL && p->reg->size == p->size) { + v->reg = p->reg; + } } v->loc = state; } @@ -1228,7 +1245,7 @@ static int builtin_identifier(int mode, char * name, Value * v) { next_sy(); ini_value(v); if (mode != MODE_NORMAL) { - set_ctx_word_value(v, addr); + set_ctx_word_value(v, (ContextAddress)addr); v->type_class = TYPE_CLASS_POINTER; return SYM_CLASS_VALUE; } @@ -1467,7 +1484,6 @@ static int type_name(int mode, Symbol ** type) { char * name = NULL; int sym_class; SYM_FLAGS sym_flags = 0; - int name_cnt = 0; while (text_sy == SY_NAME) { if (strcmp((const char *)(text_val.value), "const") == 0) { @@ -1510,7 +1526,6 @@ static int type_name(int mode, Symbol ** type) { name = tmp_strdup2(name, " "); name = tmp_strdup2(name, (char *)text_val.value); } - name_cnt++; next_sy(); } while (text_sy == SY_NAME); @@ -1766,7 +1781,7 @@ static int64_t to_int_fixed_point(int mode, Value * v) { } static uint64_t to_uns_fixed_point(int mode, Value * v) { - if (v->size == 0 || mode != MODE_NORMAL) { + if ((v->remote && v->size == 0) || mode != MODE_NORMAL) { if (v->remote) { v->value = tmp_alloc_zero((size_t)v->size); v->remote = 0; @@ -2306,7 +2321,7 @@ static void evaluate_symbol_location(Symbol * sym, ContextAddress obj_addr, ContextAddress index, LocationExpressionState ** loc, int * be) { LocationInfo * loc_info = NULL; StackFrame * frame_info = NULL; - uint64_t args[2]; + uint64_t * args = (uint64_t *)tmp_alloc(sizeof(uint64_t) * 2); args[0] = obj_addr; args[1] = index; if (get_location_info(sym, &loc_info) < 0) { @@ -2387,16 +2402,11 @@ static void op_field(int mode, Value * v) { int sym_class = 0; LocationExpressionState * loc = NULL; int be = 0; - void * struct_value = NULL; - ContextAddress struct_size = 0; if (v->remote) { find_field(mode, v->type, v->address, name, id, &sym, &loc, &be); } else { - load_value(v); - struct_value = v->value; - struct_size = v->size; find_field(mode, v->type, 0, name, id, &sym, &loc, &be); } if (sym == NULL) { @@ -2426,6 +2436,17 @@ static void op_field(int mode, Value * v) { v->sym = sym; } else { + SYM_FLAGS flags = 0; + void * struct_value = NULL; + size_t struct_size = 0; + if (get_symbol_flags(sym, &flags) < 0) { + error(errno, "Cannot retrieve symbol flags"); + } + if (!v->remote && (flags & SYM_FLAG_MEMBER) != 0) { + load_value(v); + struct_value = v->value; + struct_size = (size_t)v->size; + } if (get_symbol_type_class(sym, &v->type_class) < 0) { error(errno, "Cannot retrieve symbol type class"); } @@ -2433,21 +2454,20 @@ static void op_field(int mode, Value * v) { error(errno, "Cannot retrieve field size"); } if (mode == MODE_NORMAL) { - if (struct_value == NULL && loc->pieces_cnt > 0) { + if (loc->pieces_cnt > 0) { size_t size = 0; void * value = NULL; StackFrame * frame_info = NULL; if (expression_frame != STACK_NO_FRAME && get_frame_info(expression_context, expression_frame, &frame_info) < 0) { error(errno, "Cannot get stack frame info"); } - read_location_pieces(expression_context, frame_info, - loc->pieces, loc->pieces_cnt, be, &value, &size); + read_location_pieces_local(expression_context, frame_info, + struct_value, struct_size, loc->pieces, loc->pieces_cnt, be, &value, &size); if (size > v->size) size = (size_t)v->size; set_value(v, value, size, be); sign_extend(v, loc); } - else { - if (loc->stk_pos != 1) error(ERR_OTHER, "Invalid location expression"); + else if (loc->stk_pos == 1) { if (struct_value != NULL) { if (loc->stk[0] + v->size > struct_size) error(ERR_OTHER, "Invalid location expression"); v->value = (uint8_t *)struct_value + (size_t)loc->stk[0]; @@ -2455,10 +2475,14 @@ static void op_field(int mode, Value * v) { } else { v->address = (ContextAddress)loc->stk[0]; - assert(v->remote); + assert(v->remote || (flags & SYM_FLAG_MEMBER) == 0); + v->remote = 1; } set_value_endianness(v, sym, v->type); } + else { + error(ERR_OTHER, "Invalid location expression"); + } } } v->loc = loc; @@ -2616,23 +2640,27 @@ static void op_index(int mode, Value * v) { } static void op_addr(int mode, Value * v) { +#if ENABLE_Symbols + Symbol * type = v->type; +#endif if (mode == MODE_SKIP) return; if (v->function) { assert(v->type_class == TYPE_CLASS_POINTER); +#if ENABLE_Symbols + type = NULL; +#endif + } + else if (mode == MODE_TYPE) { + set_no_value(v); + v->type_class = TYPE_CLASS_POINTER; + v->constant = 0; + v->type = NULL; } else if (v->remote) { set_ctx_word_value(v, v->address); v->type_class = TYPE_CLASS_POINTER; v->constant = 0; -#if ENABLE_Symbols - if (v->type != NULL) { - if (get_array_symbol(v->type, 0, &v->type)) { - error(errno, "Cannot get pointer type"); - } - } -#else v->type = NULL; -#endif } else if (v->reg != NULL && v->reg->memory_context != NULL) { Context * ctx = id2ctx(v->reg->memory_context); @@ -2647,19 +2675,28 @@ static void op_addr(int mode, Value * v) { v->loc->pieces_cnt = v->loc->pieces_max = 1; v->loc->pieces->value = v->value; v->loc->pieces->size = (size_t)v->size; + v->value = NULL; } + v->type = NULL; } - else if (v->loc != NULL && v->loc->pieces_cnt == 1 && - v->loc->pieces->implicit_pointer == 0 && v->loc->pieces->optimized_away == 0 && - v->loc->pieces->reg == NULL && v->loc->pieces->value == NULL && v->loc->pieces->bit_offs == 0) { - set_ctx_word_value(v, v->loc->pieces->addr); + else if (v->loc != NULL) { + unsigned i; + LocationExpressionState * loc = v->loc; + for (i = 0; i < loc->pieces_cnt; i++) loc->pieces[i].implicit_pointer++; + set_no_value(v); v->type_class = TYPE_CLASS_POINTER; v->constant = 0; v->type = NULL; + v->loc = loc; } else { error(ERR_INV_EXPRESSION, "Invalid '&': the value has no address"); } +#if ENABLE_Symbols + if (type != NULL && get_array_symbol(type, 0, &v->type) < 0) { + error(errno, "Cannot get pointer type"); + } +#endif } static void unary_expression(int mode, Value * v); @@ -3230,6 +3267,9 @@ static void lazy_unary_expression(int mode, Value * v) { if (get_symbol_size(type, &type_size) < 0) { error(errno, "Cannot retrieve symbol size"); } + if (type_class == TYPE_CLASS_POINTER && type_size == 0) { + error(ERR_OTHER, "Context does not support memory access"); + } if (v->remote && v->size == type_size) { /* A type cast can be an l-value expression as long as the size does not change */ int ok = 0; diff --git a/agent/tcf/services/filesystem.c b/agent/tcf/services/filesystem.c index e8bcc71f..dc484fb7 100644 --- a/agent/tcf/services/filesystem.c +++ b/agent/tcf/services/filesystem.c @@ -32,7 +32,7 @@ # include <ctype.h> #endif #if defined(_WIN32) || defined(__CYGWIN__) -# include <Windows.h> +# include <windows.h> #endif #if defined(_WRS_KERNEL) # include <ioLib.h> diff --git a/agent/tcf/services/linenumbers_elf.c b/agent/tcf/services/linenumbers_elf.c index 9d08bb8a..e10cca4f 100644 --- a/agent/tcf/services/linenumbers_elf.c +++ b/agent/tcf/services/linenumbers_elf.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -49,7 +49,6 @@ static int compare_path(Channel * chnl, Context * ctx, const char * file, const char * pwd, const char * dir, const char * name) { int i, j; - char buf[FILE_PATH_SIZE]; char * full_name = NULL; if (file == NULL) return 0; @@ -66,13 +65,13 @@ static int compare_path(Channel * chnl, Context * ctx, const char * file, const full_name = (char *)name; } else if (dir != NULL && is_absolute_path(dir)) { - snprintf(full_name = buf, sizeof(buf), "%s/%s", dir, name); + full_name = tmp_printf("%s/%s", dir, name); } else if (dir != NULL && pwd != NULL) { - snprintf(full_name = buf, sizeof(buf), "%s/%s/%s", pwd, dir, name); + full_name = tmp_printf("%s/%s/%s", pwd, dir, name); } else if (pwd != NULL) { - snprintf(full_name = buf, sizeof(buf), "%s/%s", pwd, name); + full_name = tmp_printf("%s/%s", pwd, name); } else { full_name = (char *)name; @@ -81,10 +80,13 @@ static int compare_path(Channel * chnl, Context * ctx, const char * file, const j = strlen(full_name); if (i <= j && strcmp(file, full_name + j - i) == 0) return 1; #if SERVICE_PathMap - { - char * s = apply_path_map(chnl, ctx, full_name, PATH_MAP_TO_CLIENT); - if (s != full_name) { - full_name = canonic_path_map_file_name(s); + if (apply_path_map(chnl, ctx, full_name, PATH_MAP_TO_CLIENT) != full_name) { + unsigned n = 0; + unsigned cnt = 0; + char ** buf = NULL; + get_apply_path_map_results(&cnt, &buf); + for (n = 0; n < cnt; n++) { + full_name = canonic_path_map_file_name(buf[n]); j = strlen(full_name); if (i <= j && strcmp(file, full_name + j - i) == 0) return 1; } @@ -175,9 +177,7 @@ static void call_client(Context * ctx, CompUnit * unit, LineNumbersState * state area.file = file_info->mName; } else { - char buf[FILE_PATH_SIZE]; - snprintf(buf, sizeof(buf), "%s/%s", file_info->mDir, file_info->mName); - area.file = state->mFileName = loc_strdup(buf); + area.file = state->mFileName = loc_printf("%s/%s", file_info->mDir, file_info->mName); } area.file_mtime = file_info->mModTime; @@ -336,7 +336,7 @@ int line_to_address(Context * ctx, const char * file_name, int line, int column, } else { err = trap.error; - trace(LOG_ALWAYS, "Cannot load DWARF line numbers section: %s", errno_to_str(err)); + trace(LOG_ALWAYS, "Cannot read line numbers from '%s': %s", file->name, errno_to_str(err)); break; } } diff --git a/agent/tcf/services/pathmap.c b/agent/tcf/services/pathmap.c index 4018c121..9fda711e 100644 --- a/agent/tcf/services/pathmap.c +++ b/agent/tcf/services/pathmap.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Wind River Systems, Inc. and others. + * Copyright (c) 2010-2021 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. @@ -34,7 +34,7 @@ #endif static int is_separator(const char c) { - return ((c == '/') || (c == '\\')); + return c == '/' || c == '\\'; } char * canonic_path_map_file_name(const char * fnm) { @@ -80,11 +80,25 @@ char * canonic_path_map_file_name(const char * fnm) { } int is_absolute_path(const char * fnm) { - if (fnm[0] == '/') return 1; - if (fnm[0] == '\\') return 1; + if (is_separator(fnm[0])) return 1; if (fnm[0] != 0 && fnm[1] == ':') { - if (fnm[2] == '/') return 1; - if (fnm[2] == '\\') return 1; + /* Windows absolute path like C:/ */ + if (is_separator(fnm[2])) return 1; + } + if (fnm[0] == '%') { + /* Synopsys compiler uses macros like %PROCDIR% as directory names */ + /* Such name needs to be treated as an absolute path */ + unsigned i = 1; + for (;;) { + char ch = fnm[i++]; + if (ch == 0) break; + if (is_separator(ch)) break; + if (ch == '%') { + if (fnm[i] == 0) return 1; + if (is_separator(fnm[i])) return 1; + break; + } + } } return 0; } @@ -134,6 +148,10 @@ static unsigned listener_max = 0; static TCFBroadcastGroup * broadcast_group = NULL; +static unsigned fnm_max = 0; +static unsigned fnm_cnt = 0; +static char ** fnm_buf = NULL; + static void event_path_map_changed(void) { OutputStream * out = &broadcast_group->out; @@ -332,7 +350,7 @@ static int update_rule(PathMapRule * r, PathMapRuleAttribute * new_attrs) { return diff; } -static char * map_file_name(Context * ctx, PathMap * m, char * fnm, int mode) { +static void map_file_name(Context * ctx, PathMap * m, char * fnm, int mode) { unsigned i, k; for (i = 0; i < m->rules_cnt; i++) { @@ -400,20 +418,26 @@ static char * map_file_name(Context * ctx, PathMap * m, char * fnm, int mode) { buf = tmp_strdup2(r->dst, fnm + k); } - if (mode != PATH_MAP_TO_LOCAL || stat(buf, &st) == 0) return buf; + if (mode != PATH_MAP_TO_LOCAL || stat(buf, &st) == 0) { + if (fnm_max <= fnm_cnt) { + fnm_max += 16; + fnm_buf = (char **)tmp_realloc(fnm_buf, fnm_max * sizeof(char *)); + } + fnm_buf[fnm_cnt++] = buf; + } } - - return fnm; } char * apply_path_map(Channel * c, Context * ctx, char * fnm, int mode) { char * cnm = canonic_path_map_file_name(fnm); + fnm_cnt = 0; + fnm_max = 0; + fnm_buf = NULL; if (c == NULL) { LINK * l = maps.next; while (l != &maps) { PathMap * m = maps2map(l); - char * lnm = map_file_name(ctx, m, cnm, mode); - if (lnm != cnm) return lnm; + map_file_name(ctx, m, cnm, mode); l = l->next; } } @@ -423,21 +447,21 @@ char * apply_path_map(Channel * c, Context * ctx, char * fnm, int mode) { Channel * h = proxy_get_host_channel(c); if (h != NULL) { m = find_map(h); - if (m != NULL) { - char * lnm = map_file_name(ctx, m, cnm, mode); - if (lnm != cnm) return lnm; - } + if (m != NULL) map_file_name(ctx, m, cnm, mode); } #endif m = find_map(c); - if (m != NULL) { - char * lnm = map_file_name(ctx, m, cnm, mode); - if (lnm != cnm) return lnm; - } + if (m != NULL) map_file_name(ctx, m, cnm, mode); } + if (fnm_cnt > 0) return fnm_buf[0]; return fnm; } +void get_apply_path_map_results(unsigned * cnt, char *** buf) { + *cnt = fnm_cnt; + *buf = fnm_buf; +} + void iterate_path_map_rules(Channel * channel, IteratePathMapsCallBack * callback, void * args) { PathMap * m = find_map(channel); if (m != NULL) { diff --git a/agent/tcf/services/pathmap.h b/agent/tcf/services/pathmap.h index cac67313..4c155e36 100644 --- a/agent/tcf/services/pathmap.h +++ b/agent/tcf/services/pathmap.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Wind River Systems, Inc. and others. + * Copyright (c) 2010-2021 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. @@ -122,8 +122,13 @@ extern void delete_all_path_mappings(void); * Translate debug file name to local or target file name using file path mapping table of given channel. * If channel = NULL, search all maps until translation is found. * Return pointer to tmp_alloc()-ed buffer that contains translated file name. + * + * In certain cases multiple path mapping match the file name. + * The function returns first match. + * The rest of translated file names can be retrieved with get_apply_path_map_results(). */ extern char * apply_path_map(Channel * channel, Context * ctx, char * file_name, int mode); +extern void get_apply_path_map_results(unsigned * cnt, char *** buf); /* * Read new path map from the given input stream. diff --git a/agent/tcf/services/processes.c b/agent/tcf/services/processes.c index 94a9dcb6..32f46d3d 100644 --- a/agent/tcf/services/processes.c +++ b/agent/tcf/services/processes.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -100,7 +100,7 @@ typedef struct AttachDoneArgs { struct ChildProcess { LINK link; - int pid; + pid_t pid; int tty; int got_output; TCFBroadcastGroup * bcg; @@ -149,7 +149,7 @@ static LINK prs_list = TCF_LIST_INIT(prs_list); static SEM_ID prs_list_lock = NULL; #endif -static ChildProcess * find_process(int pid) { +static ChildProcess * find_process(pid_t pid) { LINK * qhp = &prs_list; LINK * qp = qhp->next; @@ -1528,7 +1528,7 @@ static int start_process_imp(Channel * c, char ** envp, const char * dir, const #endif -static void waitpid_listener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { +static void waitpid_listener(pid_t pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { if (exited) { ChildProcess * prs = find_process(pid); if (prs) { diff --git a/agent/tcf/services/registers.c b/agent/tcf/services/registers.c index 9afd7a6b..c7f0eb73 100644 --- a/agent/tcf/services/registers.c +++ b/agent/tcf/services/registers.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -442,6 +442,7 @@ void send_event_register_changed(const char * id) { } void send_event_register_definitions_changed(void) { + invalidate_register_ids(); notify_definitions_changed = 1; /* Delay notifications until cache transaction is committed */ if (cache_transaction_id() == 0) flush_notifications(); @@ -643,10 +644,10 @@ static void check_location_list(Location * locs, unsigned cnt, int setm) { if (id2register(loc->id, &loc->ctx, &loc->frame, &loc->reg_def) < 0) exception(errno); if (loc->ctx->exited) exception(ERR_ALREADY_EXITED); - if ((loc->ctx->reg_access & setm ? REG_ACCESS_WR_STOP : REG_ACCESS_RD_STOP) != 0) { + if ((loc->ctx->reg_access & (setm ? REG_ACCESS_WR_STOP : REG_ACCESS_RD_STOP)) != 0) { check_all_stopped(loc->ctx); } - if ((loc->ctx->reg_access & setm ? REG_ACCESS_WR_RUNNING : REG_ACCESS_RD_RUNNING) == 0) { + if ((loc->ctx->reg_access & (setm ? REG_ACCESS_WR_RUNNING : REG_ACCESS_RD_RUNNING)) == 0) { if (context_has_state(loc->ctx) && !is_ctx_stopped(loc->ctx)) str_fmt_exception(errno, "Cannot %s register if not stopped", setm ? "write" : "read"); } diff --git a/agent/tcf/services/runctrl.c b/agent/tcf/services/runctrl.c index 5820467f..9f86c62b 100644 --- a/agent/tcf/services/runctrl.c +++ b/agent/tcf/services/runctrl.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -94,6 +94,7 @@ typedef struct ContextExtensionRC { char * step_func_id_out; int step_inlined; int step_set_frame_level; + int step_range_hidden; CodeArea * step_code_area; ErrorReport * step_error; const char * step_done; @@ -436,21 +437,27 @@ static const char * get_suspend_reason(Context * ctx) { return REASON_USER_REQUEST; } -static void write_context_state(OutputStream * out, Context * ctx) { +static void write_context_state(OutputStream * out, Context * ctx, int min) { int fst = 1; ContextExtensionRC * ext = EXT(ctx); assert(!ctx->exited); if (!ext->intercepted) { - write_stringz(out, "0"); + if (!min) { + /* Zero as Program Counter */ + write_stringz(out, "0"); + } + + /* Reason */ write_stringz(out, "null"); } else { - - /* Number: PC */ - json_write_uint64(out, ext->pc); - write_stream(out, 0); + if (!min) { + /* Number: PC */ + json_write_uint64(out, ext->pc); + write_stream(out, 0); + } /* String: Reason */ json_write_string(out, get_suspend_reason(ctx)); @@ -493,7 +500,7 @@ static void write_context_state(OutputStream * out, Context * ctx) { write_stream(out, ']'); fst = 0; } - if (ext->pc_error) { + if (!min && ext->pc_error) { if (!fst) write_stream(out, ','); json_write_string(out, "PCError"); write_stream(out, ':'); @@ -629,6 +636,7 @@ static void command_get_children(char * token, Channel * c) { typedef struct CommandGetStateArgs { char token[256]; char id[256]; + int min; /* Non-zero for the getMinState. */ } CommandGetStateArgs; static void command_get_state_cache_client(void * x) { @@ -644,7 +652,9 @@ static void command_get_state_cache_client(void * x) { if (ctx == NULL || !context_has_state(ctx)) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; - if (!err && ext != NULL && ext->intercepted) get_current_pc(ctx); + /* Do not retrieve the PC in the "minimal" variant. */ + if (!err && ext != NULL && ext->intercepted && !args->min) + get_current_pc(ctx); cache_exit(); @@ -657,12 +667,12 @@ static void command_get_state_cache_client(void * x) { write_stream(&c->out, 0); if (err) { - write_stringz(&c->out, "0"); + if (!args->min) write_stringz(&c->out, "0"); write_stringz(&c->out, "null"); write_stringz(&c->out, "null"); } else { - write_context_state(&c->out, ctx); + write_context_state(&c->out, ctx, args->min); } write_stream(&c->out, MARKER_EOM); @@ -677,6 +687,20 @@ static void command_get_state(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOM); strlcpy(args.token, token, sizeof(args.token)); + args.min = 0; + cache_enter(command_get_state_cache_client, c, &args, sizeof(args)); +} + +static void command_get_min_state(char * token, Channel * c) { + CommandGetStateArgs args; + + memset(&args, 0, sizeof(args)); + json_read_string(&c->inp, args.id, sizeof(args.id)); + json_test_char(&c->inp, MARKER_EOA); + json_test_char(&c->inp, MARKER_EOM); + + strlcpy(args.token, token, sizeof(args.token)); + args.min = 1; cache_enter(command_get_state_cache_client, c, &args, sizeof(args)); } @@ -846,6 +870,7 @@ static void cancel_step_mode(Context * ctx) { ext->step_line_cnt = 0; ext->step_repeat_cnt = 0; ext->step_into_hidden = 0; + ext->step_range_hidden = 0; ext->step_range_start = 0; ext->step_range_end = 0; ext->step_frame_fp = 0; @@ -877,6 +902,7 @@ static void start_step_mode(Context * ctx, Channel * c, int mode, int cnt, Conte ext->step_range_end = range_end; ext->step_repeat_cnt = cnt; ext->step_into_hidden = 0; + ext->step_range_hidden = 0; } int get_stepping_mode(Context * ctx) { @@ -1279,22 +1305,50 @@ static void send_event_context_removed(Context * ctx) { write_stream(out, MARKER_EOM); } -static void send_event_context_suspended(void) { - LINK p0; /* List of contexts intercepted by breakpoint or exception */ - LINK p1; /* List of all other intercepted contexts */ - LINK p2; /* List for notify_context_intercepted() */ +static LINK p0; /* List of contexts intercepted by breakpoint or exception */ +static LINK p1; /* List of all other intercepted contexts */ +static LINK p2; /* List for notify_context_intercepted() */ + +static void get_intercepted_contexts() { LINK * l = context_root.next; - unsigned i; list_init(&p0); list_init(&p1); + + while (l != &context_root) { + Context * ctx = ctxl2ctxp(l); + if (!ctx) continue; + l = l->next; + if (ctx->pending_intercept && ctx->stopped) { + LINK * n; + ContextExtensionRC * ext = EXT(ctx); + if (strcmp(get_suspend_reason(ctx), REASON_USER_REQUEST)) { + /* lazily fetch PC */ + if (ext->pc == 0 && ext->pc_error == ERR_OTHER) + get_current_pc(ctx); + n = &p0; + } + else { + /* lazily fetch PC of first child of container only */ + if (list_is_empty(&p1) && ext->pc == 0 && ext->pc_error == ERR_OTHER) + get_current_pc(ctx); + n = &p1; + } + list_add_last(&ext->link, n); + } + } +} + +static void send_event_context_suspended(void) { + LINK * l = context_root.next; + unsigned i; + list_init(&p2); while (l != &context_root) { Context * ctx = ctxl2ctxp(l); l = l->next; if (ctx->pending_intercept && ctx->stopped) { - LINK * n = &p1; ContextExtensionRC * ext = EXT(ctx); assert(!ctx->exited); assert(!ext->intercepted); @@ -1303,8 +1357,6 @@ static void send_event_context_suspended(void) { assert(!ext->intercepted); ext->intercepted = 1; ctx->pending_intercept = 0; - if (strcmp(get_suspend_reason(ctx), REASON_USER_REQUEST)) n = &p0; - list_add_last(&ext->link, n); } } @@ -1324,7 +1376,7 @@ static void send_event_context_suspended(void) { json_write_string(out, ctx->id); write_stream(out, 0); - write_context_state(out, ctx); + write_context_state(out, ctx, 0); if (container) { write_stream(out, '['); @@ -1633,7 +1685,7 @@ static BreakpointInfo * create_step_machine_breakpoint(ContextAddress addr, Cont static int update_step_machine_state(Context * ctx) { ContextExtensionRC * ext = EXT(ctx); - ContextAddress addr = ext->pc; + ContextAddress addr; int do_reverse = 0; if (!context_has_state(ctx) || ctx->exited || ctx->pending_intercept) { @@ -1654,6 +1706,11 @@ static int update_step_machine_state(Context * ctx) { break; } + // lazily fetch PC + if (ext->pc == 0 && ext->pc_error == ERR_OTHER) + get_current_pc(ctx); + addr = ext->pc; + if (ext->pc_error) { if (ctx->stopped && get_error_code(ext->pc_error) == ERR_NOT_ACTIVE) { if (!do_reverse) { @@ -1712,6 +1769,19 @@ static int update_step_machine_state(Context * ctx) { ext->step_frame_fp = info->fp; ext->step_set_frame_level = 1; } + else if (ext->step_range_hidden && addr >= ext->step_range_start && addr < ext->step_range_end) { + n = get_prev_frame(ctx, n); + if (n < 0 && cache_miss_count() > 0) return -1; + if (n >= 0) { + uint64_t pc = 0; + if (get_frame_info(ctx, n, &info) < 0) return -1; + if (read_reg_value(info, get_PC_definition(ctx), &pc) < 0) return -1; + if (pc >= ext->step_range_start && pc < ext->step_range_end) { + /* Function call inside a hidden stepping range - need to step out */ + step_bp_addr = (ContextAddress)pc; + } + } + } break; case RM_STEP_OVER: case RM_STEP_OVER_RANGE: @@ -2016,6 +2086,7 @@ static int update_step_machine_state(Context * ctx) { } if (hidden_function) { /* Don't stop in a function that should be hidden during source level stepping */ + ext->step_range_hidden = 1; break; } } @@ -2033,6 +2104,7 @@ static int update_step_machine_state(Context * ctx) { ext->step_code_area = area; ext->step_range_start = addr; ext->step_range_end = addr + 1; + ext->step_range_hidden = 1; break; } else if (errno) { @@ -2467,9 +2539,6 @@ static void sync_run_state(void) { err_cnt++; } } - if (ctx->pending_intercept && ctx->stopped) { - if (ext->pc_error == ERR_OTHER) get_current_pc(ctx); - } } /* Resume contexts with resume mode other then RM_RESUME */ @@ -2496,6 +2565,7 @@ static void sync_run_state(void) { static void sync_run_state_cache_client(void * args) { sync_run_state(); + get_intercepted_contexts(); cache_exit(); assert(sync_run_state_event_posted > 0); sync_run_state_event_posted--; @@ -2553,6 +2623,7 @@ static void run_safe_events(void * arg) { i = safe_event_list; while (i != NULL) { Context * grp = EXT(i->ctx)->stop_group_ctx; + /* Note: grp is NULL if the context is not added to the context_root list, e.g. "hidden" context */ if (grp != NULL) EXT(grp)->stop_group_mark = 1; i = i->next; } @@ -2562,6 +2633,7 @@ static void run_safe_events(void * arg) { ContextExtensionRC * ext = EXT(ctx); l = l->next; ext->pending_safe_event = 0; + assert(!ext->stop_group_mark || EXT(ext->stop_group_ctx)->stop_group_mark); ext->stop_group_mark = EXT(ext->stop_group_ctx)->stop_group_mark; if (ctx->exited || ctx->exiting || ext->cannot_stop) continue; if (!ext->safe_single_step && !ext->stop_group_mark) continue; @@ -3020,6 +3092,7 @@ void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg) { add_command_handler(proto, RUN_CONTROL, "getContext", command_get_context); add_command_handler(proto, RUN_CONTROL, "getChildren", command_get_children); add_command_handler(proto, RUN_CONTROL, "getState", command_get_state); + add_command_handler(proto, RUN_CONTROL, "getMinState", command_get_min_state); #if ENABLE_ContextISA add_command_handler(proto, RUN_CONTROL, "getISA", command_get_isa); #endif diff --git a/agent/tcf/services/stacktrace-ext.h b/agent/tcf/services/stacktrace-ext.h index 44254645..fa1c0073 100644 --- a/agent/tcf/services/stacktrace-ext.h +++ b/agent/tcf/services/stacktrace-ext.h @@ -1,3 +1,18 @@ +/******************************************************************************* +* Copyright (c) 2013-2022 Wind River, 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 - initial API and implementation +*******************************************************************************/ + /* * Extension point definitions for stacktrace.c. * diff --git a/agent/tcf/services/stacktrace.c b/agent/tcf/services/stacktrace.c index 4a03a340..cac913e8 100644 --- a/agent/tcf/services/stacktrace.c +++ b/agent/tcf/services/stacktrace.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2020 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -80,13 +80,8 @@ static void free_frame(StackFrame * frame) { } #if ENABLE_Symbols -static int get_frame_debug_info(StackFrame * frame, StackTracingInfo ** info) { - uint64_t ip = 0; +static int get_frame_debug_info(StackFrame * frame, StackTracingInfo ** info, uint64_t ip) { Context * ctx = frame->ctx; - if (read_reg_value(frame, get_PC_definition(ctx), &ip) < 0) { - if (frame->is_top_frame) return -1; - return 0; - } if (ip > 0 && !frame->is_top_frame) { StackTrace * stk = EXT(ctx); if (frame->frame > stk->frame_cnt) { @@ -119,22 +114,52 @@ static int get_frame_debug_info(StackFrame * frame, StackTracingInfo ** info) { } #endif +static void read_saved_reg(StackFrame * frame, StackFrameRegisterLocation * info, uint8_t ** buf, size_t * size) { + Trap trap; + if (set_trap(&trap)) { + /* If a saved register value cannot be evaluated - ignore it */ + LocationExpressionState * state = evaluate_location_expression(frame->ctx, frame, info->cmds, info->cmds_cnt, NULL, 0); + if (state->stk_pos == 1) { + unsigned j; + uint64_t v = state->stk[0]; + RegisterDefinition * reg_def = info->reg; + *buf = (uint8_t *)tmp_alloc_zero(reg_def->size); + for (j = 0; j < reg_def->size; j++) { + (*buf)[reg_def->big_endian ? reg_def->size - j - 1 : j] = (uint8_t)v; + v = v >> 8; + } + *size = reg_def->size; + } + else if (state->stk_pos == 0 && state->pieces_cnt > 0) { + read_location_pieces(state->ctx, state->stack_frame, + state->pieces, state->pieces_cnt, state->reg_id_scope.big_endian, (void **)buf, size); + } + clear_trap(&trap); + } +} + int get_next_stack_frame(StackFrame * frame, StackFrame * down) { #if ENABLE_Symbols int error = 0; Context * ctx = frame->ctx; + StackTrace * stk = EXT(ctx); + int frame_cnt = stk->frame_cnt; StackTracingInfo * info = NULL; int frame_idx = frame->frame; + uint64_t ip = 0; memset(down, 0, sizeof(StackFrame)); - if (get_frame_debug_info(frame, &info) < 0) { + if (read_reg_value(frame, get_PC_definition(ctx), &ip) < 0) { + if (frame->is_top_frame) error = errno; + } + else if (get_frame_debug_info(frame, &info, ip) < 0) { error = errno; } else if (info != NULL) { Trap trap; if (set_trap(&trap)) { - int i; + unsigned i; LocationExpressionState * state; state = evaluate_location_expression(ctx, frame, info->fp->cmds, info->fp->cmds_cnt, NULL, 0); if (state->stk_pos != 1) str_exception(ERR_OTHER, "Invalid stack trace expression"); @@ -142,7 +167,6 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) { if (info->sub_cnt > 0) { size_t buf_size = 8; uint8_t * buf = (uint8_t *)tmp_alloc(buf_size); - StackTrace * stk = EXT(ctx); #if ENABLE_StackRegisterLocations LocationExpressionCommand cmd; memset(&cmd, 0, sizeof(cmd)); @@ -186,41 +210,39 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) { } down->ctx = ctx; for (i = 0; i < info->reg_cnt; i++) { - RegisterDefinition * reg_def = info->regs[i]->reg; + StackFrameRegisterLocation * loc = info->regs[i]; uint8_t * buf = NULL; size_t size = 0; - Trap trap_reg; #if ENABLE_StackRegisterLocations - if (write_reg_location(down, reg_def, info->regs[i]->cmds, info->regs[i]->cmds_cnt) == 0) { + if (write_reg_location(down, loc->reg, loc->cmds, loc->cmds_cnt) == 0) { down->has_reg_data = 1; continue; } #endif - if (set_trap(&trap_reg)) { - /* If a saved register value cannot be evaluated - ignore it */ - state = evaluate_location_expression(ctx, frame, info->regs[i]->cmds, info->regs[i]->cmds_cnt, NULL, 0); - if (state->stk_pos == 1) { - unsigned j; - uint64_t v = state->stk[0]; - buf = (uint8_t *)tmp_alloc_zero(reg_def->size); - for (j = 0; j < reg_def->size; j++) { - buf[reg_def->big_endian ? reg_def->size - j - 1 : j] = (uint8_t)v; - v = v >> 8; - } - size = reg_def->size; - } - else if (state->stk_pos == 0 && state->pieces_cnt > 0) { - read_location_pieces(state->ctx, state->stack_frame, - state->pieces, state->pieces_cnt, state->reg_id_scope.big_endian, (void **)&buf, &size); - } - clear_trap(&trap_reg); - } + read_saved_reg(frame, loc, &buf, &size); if (buf != NULL && size > 0) { + RegisterDefinition * reg_def = loc->reg; if (size > reg_def->size) size = reg_def->size; if (write_reg_bytes(down, reg_def, 0, size, buf) < 0) exception(errno); down->has_reg_data = 1; } } + if (!frame->is_top_frame) { + for (i = 0; i < info->call_cnt; i++) { + if (info->calls[i]->addr == ip) { + StackFrameRegisterLocation * loc = &info->calls[i]->reg; + uint8_t * buf = NULL; + size_t size = 0; + read_saved_reg(frame, loc, &buf, &size); + if (buf != NULL && size > 0) { + RegisterDefinition * reg_def = loc->reg; + if (size > reg_def->size) size = reg_def->size; + if (write_reg_bytes(frame, reg_def, 0, size, buf) < 0) exception(errno); + frame->has_reg_data = 1; + } + } + } + } /* Cache miss on register access should not be ignored, abort trace */ if (cache_miss_count() > 0) exception(ERR_CACHE_MISS); clear_trap(&trap); @@ -233,6 +255,10 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) { } if (error) { free_frame(down); + /* Free up any additional frames added to the stack */ + while (frame_cnt < stk->frame_cnt) { + free_frame(stk->frames + --stk->frame_cnt); + } errno = error; return -1; } @@ -310,15 +336,13 @@ static void trace_stack(Context * ctx, StackTrace * stack, int max_frames) { uint8_t * buf1 = (uint8_t *)tmp_alloc(buf_size); RegisterDefinition * def; for (def = get_reg_definitions(ctx); def && def->name; def++) { - int f0, f1; if (buf_size < def->size) { buf_size = def->size; buf0 = (uint8_t *)tmp_realloc(buf0, buf_size); buf1 = (uint8_t *)tmp_realloc(buf1, buf_size); } - f0 = read_reg_bytes(frame, def, 0, def->size, buf0) == 0; - f1 = read_reg_bytes(&down, def, 0, def->size, buf1) == 0; - if (f0 != f1 || (f0 && memcmp(buf0, buf1, def->size) != 0)) { + if (read_reg_bytes(&down, def, 0, def->size, buf1) < 0) continue; + if (read_reg_bytes(frame, def, 0, def->size, buf0) < 0 || memcmp(buf0, buf1, def->size) != 0) { equ = 0; break; } diff --git a/agent/tcf/services/symbols.c b/agent/tcf/services/symbols.c index ce5b8efb..2030cd2d 100644 --- a/agent/tcf/services/symbols.c +++ b/agent/tcf/services/symbols.c @@ -974,7 +974,7 @@ static void command_find_frame_props_cache_client(void * x) { } if (info != NULL && info->regs != NULL) { - int i; + unsigned i; if (cnt++ > 0) write_stream(&c->out, ','); json_write_string(&c->out, "Regs"); write_stream(&c->out, ':'); @@ -988,8 +988,37 @@ static void command_find_frame_props_cache_client(void * x) { write_stream(&c->out, '}'); } + if (info != NULL && info->calls != NULL) { + unsigned i; + if (cnt++ > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "Calls"); + write_stream(&c->out, ':'); + write_stream(&c->out, '['); + for (i = 0; i < info->call_cnt; i++) { + if (i > 0) write_stream(&c->out, ','); + write_stream(&c->out, '{'); + json_write_string(&c->out, "CodeAddr"); + write_stream(&c->out, ':'); + json_write_uint64(&c->out, info->calls[i]->addr); + write_stream(&c->out, ','); + json_write_string(&c->out, "CodeSize"); + write_stream(&c->out, ':'); + json_write_uint64(&c->out, info->calls[i]->size); + write_stream(&c->out, ','); + json_write_string(&c->out, "Reg"); + write_stream(&c->out, ':'); + json_write_string(&c->out, register2id(ctx, STACK_NO_FRAME, info->calls[i]->reg.reg)); + write_stream(&c->out, ','); + json_write_string(&c->out, "Value"); + write_stream(&c->out, ':'); + write_commands(&c->out, ctx, info->calls[i]->reg.cmds, info->calls[i]->reg.cmds_cnt); + write_stream(&c->out, '}'); + } + write_stream(&c->out, ']'); + } + if (info != NULL && info->subs != NULL) { - int i; + unsigned i; if (cnt++ > 0) write_stream(&c->out, ','); json_write_string(&c->out, "Inlined"); write_stream(&c->out, ':'); @@ -1017,7 +1046,7 @@ static void command_find_frame_props_cache_client(void * x) { write_stream(&c->out, 0); if (info != NULL && info->regs != NULL) { - int i; + unsigned i; write_stream(&c->out, '{'); for (i = 0; i < info->reg_cnt; i++) { if (i > 0) write_stream(&c->out, ','); diff --git a/agent/tcf/services/symbols.h b/agent/tcf/services/symbols.h index c09ca367..10222cb7 100644 --- a/agent/tcf/services/symbols.h +++ b/agent/tcf/services/symbols.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -86,6 +86,7 @@ typedef uint32_t SYM_FLAGS; #define SYM_FLAG_BOOL_TYPE 0x04000000 #define SYM_FLAG_INDIRECT 0x08000000 #define SYM_FLAG_RVALUE 0x10000000 +#define SYM_FLAG_MEMBER 0x20000000 /* Additional (uncommon) symbol properties */ typedef struct SymbolProperties { @@ -138,15 +139,23 @@ typedef struct StackFrameInlinedSubroutine { CodeArea area; } StackFrameInlinedSubroutine; +typedef struct StackFrameCallSiteParameter { + ContextAddress addr; + ContextAddress size; + StackFrameRegisterLocation reg; +} StackFrameCallSiteParameter; + /* Complete stack tracing info for a range of instruction addresses */ typedef struct StackTracingInfo { ContextAddress addr; ContextAddress size; StackFrameRegisterLocation * fp; StackFrameRegisterLocation ** regs; - int reg_cnt; + unsigned reg_cnt; + StackFrameCallSiteParameter ** calls; + unsigned call_cnt; StackFrameInlinedSubroutine ** subs; - int sub_cnt; + unsigned sub_cnt; } StackTracingInfo; typedef struct SymbolFileInfo { diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c index 1de69793..d98f3931 100644 --- a/agent/tcf/services/symbols_elf.c +++ b/agent/tcf/services/symbols_elf.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2023 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. @@ -160,6 +160,19 @@ static struct BaseTypeAlias { { "signed long long int", "long long int" }, { "unsigned long long", "unsigned long long int" }, { "unsigned long long", "long long unsigned int" }, + /* LLVM 15 doesn't add 'int' in DWARF type names */ + { "short int", "short" }, + { "signed short", "short" }, + { "signed short int", "short" }, + { "unsigned short int", "unsigned short" }, + { "long int", "long" }, + { "signed long", "long" }, + { "signed long int", "long" }, + { "unsigned long int", "unsigned long" }, + { "long long int", "long long" }, + { "signed long long", "long long" }, + { "signed long long int", "long long" }, + { "unsigned long long int", "unsigned long long" }, { NULL, NULL } }; @@ -350,7 +363,7 @@ int elf_tcf_symbol(Context * ctx, ELF_SymbolInfo * sym_info, Symbol ** symbol) { return 0; } -int elf_symbol_info(Symbol * sym, ELF_SymbolInfo * elf_sym) { +int elf_symbol_info(const Symbol * sym, ELF_SymbolInfo * elf_sym) { Trap trap; assert (sym != NULL && sym->magic == SYMBOL_MAGIC && sym->tbl != NULL); @@ -428,6 +441,8 @@ static int is_frame_based_object(Symbol * sym) { case TAG_structure_type: case TAG_class_type: case TAG_union_type: + if (obj->mCompUnit->mLanguage == LANG_C11) return 0; + if (obj->mCompUnit->mLanguage == LANG_C99) return 0; if (obj->mCompUnit->mLanguage == LANG_C89) return 0; if (obj->mCompUnit->mLanguage == LANG_C) return 0; break; @@ -460,6 +475,8 @@ static int is_thread_based_object(Symbol * sym) { case TAG_structure_type: case TAG_class_type: case TAG_union_type: + if (obj->mCompUnit->mLanguage == LANG_C11) return 0; + if (obj->mCompUnit->mLanguage == LANG_C99) return 0; if (obj->mCompUnit->mLanguage == LANG_C89) break; if (obj->mCompUnit->mLanguage == LANG_C) break; return 1; @@ -1743,33 +1760,46 @@ int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, const char } } - if (error == 0 && should_continue_pub_names_search()) { - /* Search in pub names of all other files */ - ELF_File * file = elf_list_first(sym_ctx, 0, ~(ContextAddress)0); - if (file == NULL) error = errno; - while (error == 0 && file != NULL) { - if (file != curr_file) { - Trap trap; - if (set_trap(&trap)) { - DWARFCache * cache = get_dwarf_cache(get_dwarf_file(file)); - if (strncmp(name, "$relocate:", 10) == 0) { - find_relocate(file, name + 10); + if (error == 0) { + /* Some compilers optimize away declaration info for dynamic symbols, + * and expect debugger to search for definition in shared libraries */ + int dynsym = 0; + Symbol * sym = find_symbol_list; + while (sym != NULL) { + if (sym->dynsym) { + dynsym = 1; + break; + } + sym = sym->next; + } + if (dynsym || should_continue_pub_names_search()) { + /* Search in pub names of all other files */ + ELF_File * file = elf_list_first(sym_ctx, 0, ~(ContextAddress)0); + if (file == NULL) error = errno; + while (error == 0 && file != NULL) { + if (file != curr_file) { + Trap trap; + if (set_trap(&trap)) { + DWARFCache * cache = get_dwarf_cache(get_dwarf_file(file)); + if (strncmp(name, "$relocate:", 10) == 0) { + find_relocate(file, name + 10); + } + else { + find_by_name_in_pub_names(cache, name); + find_by_name_in_sym_table(file, name, 0); + } + clear_trap(&trap); } else { - find_by_name_in_pub_names(cache, name); - find_by_name_in_sym_table(file, name, 0); + error = trap.error; + break; } - clear_trap(&trap); - } - else { - error = trap.error; - break; } + file = elf_list_next(sym_ctx); + if (file == NULL) error = errno; } - file = elf_list_next(sym_ctx); - if (file == NULL) error = errno; + elf_list_done(sym_ctx); } - elf_list_done(sym_ctx); } if (error == 0 && find_symbol_list == NULL) { @@ -1929,6 +1959,7 @@ static int find_by_addr_in_unit(ObjectInfo * parent, int level, UnitAddress * ad case TAG_unspecified_parameters: case TAG_local_variable: if (sym_frame == STACK_NO_FRAME) break; + // fall through case TAG_variable: if (in_range && (obj->mFlags & DOIF_location) != 0) { U8_T lc = 0; @@ -2436,11 +2467,65 @@ int id2symbol(const char * id, Symbol ** res) { ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { ELF_File * file = NULL; ELF_Section * sec = NULL; - ContextAddress res = elf_map_to_link_time_address(ctx, addr, 0, &file, &sec); - if (res == 0 || sec == NULL) return 0; + ContextAddress lt_addr = elf_map_to_link_time_address(ctx, addr, 0, &file, &sec); + if (lt_addr == 0 || sec == NULL) return 0; if (sec->name == NULL) return 0; - if (strcmp(sec->name, ".plt") != 0) return 0; - return (ContextAddress)sec->addr + (addr - res); + if (strcmp(sec->name, ".plt") == 0) return (ContextAddress)sec->addr + (addr - lt_addr); + if (sec != NULL && file->machine == EM_PPC) { + /* + Check for a symbol that marks plt call stubs. + For non - PIC code the sym is xxxxxxxx.plt_call32.<callee>, + for - fpic code, the sym is xxxxxxxx.plt_pic32.<callee>, + and for - fPIC xxxxxxxx.got2.plt_pic32.<callee>, + where xxxxxxxx is a hex number specifying the addend on the plt relocation. + */ + ELF_SymbolInfo sym_info; + elf_find_symbol_by_address(sec, lt_addr, &sym_info); + if (sym_info.section == sec && sym_info.name != NULL) { + unsigned i = 0; + if (strcmp(sym_info.name, "__glink") == 0 || + strcmp(sym_info.name, "__glink_PLTresolve") == 0) + return (ContextAddress)sec->addr + (addr - lt_addr); + for (;;) { + char ch = sym_info.name[i]; + if (ch >= '0' && ch <= '9') i++; + else if (ch >= 'A' && ch <= 'F') i++; + else if (ch >= 'a' && ch <= 'f') i++; + else break; + } + if (i == 8 && sym_info.name[i] == '.') { + unsigned n; + static const char * const names[] = { ".plt_call32.", ".plt_pic32.", ".got2.plt_call32.", ".got2.plt_pic32.", NULL }; + for (n = 0; names[n] != NULL; n++) { + if (strncmp(sym_info.name + i, names[n], strlen(names[n])) == 0) + return (ContextAddress)sec->addr + (addr - lt_addr); + } + } + } + } + if (sec != NULL && file->machine == EM_PPC64) { + ELF_SymbolInfo sym_info; + elf_find_symbol_by_address(sec, lt_addr, &sym_info); + if (sym_info.section == sec && sym_info.name != NULL) { + unsigned i = 0; + for (;;) { + char ch = sym_info.name[i]; + if (ch >= '0' && ch <= '9') i++; + else if (ch >= 'A' && ch <= 'F') i++; + else if (ch >= 'a' && ch <= 'f') i++; + else break; + } + if (i == 8 && sym_info.name[i] == '.') { + unsigned n; + static const char * const names[] = { ".long_branch.", ".long_branch_r2off.", ".plt_branch.", ".plt_branch_r2off.", ".plt_call." }; + for (n = 0; names[n] != NULL; n++) { + if (strncmp(sym_info.name + i, names[n], strlen(names[n])) == 0) + return (ContextAddress)sec->addr + (addr - lt_addr); + } + } + } + } + return 0; } int get_context_isa(Context * ctx, ContextAddress ip, const char ** isa, @@ -2469,6 +2554,7 @@ int get_context_isa(Context * ctx, ContextAddress ip, const char ** isa, assert(sym_info.section == sec); if (sym_info.name != NULL && *sym_info.name == '$') { if (strcmp(sym_info.name, "$a") == 0) *isa = "ARM"; + else if (strncmp(sym_info.name, "$a.", 3) == 0) *isa = "ARM"; /* clang-12 */ else if (strcmp(sym_info.name, "$t") == 0) *isa = "Thumb"; else if (strcmp(sym_info.name, "$t.x") == 0) *isa = "ThumbEE"; else if (strcmp(sym_info.name, "$d") == 0) *isa = "Data"; @@ -2479,6 +2565,7 @@ int get_context_isa(Context * ctx, ContextAddress ip, const char ** isa, for (;;) { elf_next_symbol_by_address(&sym_info); if (sym_info.sym_section == NULL) { + assert(sec->addr + sec->size > lt_addr); *range_size = (ContextAddress)(sec->addr + sec->size) - *range_addr; *range_addr += ip - lt_addr; return 0; @@ -2486,6 +2573,12 @@ int get_context_isa(Context * ctx, ContextAddress ip, const char ** isa, if (sym_info.name != NULL && *sym_info.name == '$') { ContextAddress sym_addr = (ContextAddress)sym_info.value; if (file->type == ET_REL) sym_addr += (ContextAddress)sec->addr; + if (sym_addr <= lt_addr) { + *isa = NULL; + *range_addr = ip; + *range_size = 1; + return 0; + } *range_size = sym_addr - *range_addr; *range_addr += ip - lt_addr; return 0; @@ -2551,7 +2644,7 @@ int get_context_isa(Context * ctx, ContextAddress ip, const char ** isa, return 0; } -static int buf_sub_max = 0; +static unsigned buf_sub_max = 0; static void add_inlined_subroutine(ObjectInfo * o, CompUnit * unit, ContextAddress addr0, ContextAddress addr1, StackTracingInfo * buf) { StackFrameInlinedSubroutine * sub = (StackFrameInlinedSubroutine *)tmp_alloc(sizeof(StackFrameInlinedSubroutine)); @@ -2620,84 +2713,119 @@ static void search_inlined_subroutine(Context * ctx, ObjectInfo * obj, UnitAddre case TAG_subroutine: case TAG_subprogram: case TAG_inlined_subroutine: - if (o->mFlags & DOIF_ranges) { - DWARFCache * cache = get_dwarf_cache(addr->file); - ELF_Section * debug_ranges = cache->mDebugRanges; - if (debug_ranges != NULL) { - CompUnit * unit = addr->unit; - ContextAddress base = unit->mObject->u.mCode.mLowPC; - dio_EnterSection(&unit->mDesc, debug_ranges, o->u.mCode.mHighPC.mRanges); - for (;;) { - ELF_Section * x_sec = NULL; - ELF_Section * y_sec = NULL; - U8_T x = dio_ReadAddress(&x_sec); - U8_T y = dio_ReadAddress(&y_sec); - if (x == 0 && y == 0) break; - if (x == ((U8_T)1 << unit->mDesc.mAddressSize * 8) - 1) { - base = (ContextAddress)y; + { + ObjectAddressRange range; + start_dwarf_addr_ranges(o, &range); + while (read_dwarf_addr_range(&range)) { + ContextAddress addr0 = range.mAddr - addr->lt_addr + addr->rt_addr; + ContextAddress addr1 = range.mAddr + range.mSize - addr->lt_addr + addr->rt_addr; + if (addr0 <= addr->rt_addr && addr1 > addr->rt_addr) { + U8_T pos = dio_GetPos(); + dio_ExitSection(); + if (buf->addr < addr0) { + assert(buf->addr + buf->size > addr0); + buf->size = buf->addr + buf->size - addr0; + buf->addr = addr0; } - else { - if (x_sec == NULL) x_sec = unit->mTextSection; - if (y_sec == NULL) y_sec = unit->mTextSection; - if (x_sec == addr->section && y_sec == addr->section && x < y) { - ContextAddress addr0 = base + x - addr->lt_addr + addr->rt_addr; - ContextAddress addr1 = base + y - addr->lt_addr + addr->rt_addr; - if (addr0 <= addr->rt_addr && addr1 > addr->rt_addr) { - U8_T pos = dio_GetPos(); - dio_ExitSection(); - if (buf->addr < addr0) { - assert(buf->addr + buf->size > addr0); - buf->size = buf->addr + buf->size - addr0; - buf->addr = addr0; + if (buf->addr + buf->size > addr1) { + assert(addr1 > buf->addr); + buf->size = addr1 - buf->addr; + } + if (o->mTag == TAG_inlined_subroutine) add_inlined_subroutine(o, range.mUnit, addr0, addr1, buf); + search_inlined_subroutine(ctx, o, addr, buf); + if (range.mRngSection) dio_EnterSection(&range.mUnit->mDesc, range.mRngSection, pos); + } + else if (addr1 <= addr->rt_addr && addr1 > buf->addr) { + buf->size = buf->addr + buf->size - addr1; + buf->addr = addr1; + } + else if (addr0 > addr->rt_addr && addr0 < buf->addr + buf->size) { + buf->size = addr0 - buf->addr; + } + } + } + break; + } + o = o->mSibling; + } +} + +static unsigned call_site_max = 0; +static void add_dwarf_location_command(LocationInfo * l, PropertyValue * v); + +static void search_stack_tracing_call_sites(Context * ctx, ObjectInfo * obj, UnitAddress * addr, StackTracingInfo * buf) { + obj = get_dwarf_children(obj); + while (obj != NULL) { + switch (obj->mTag) { + case TAG_compile_unit: + case TAG_partial_unit: + case TAG_module: + case TAG_global_subroutine: + case TAG_lexical_block: + case TAG_with_stmt: + case TAG_try_block: + case TAG_catch_block: + case TAG_subprogram: + case TAG_subroutine: + case TAG_inlined_subroutine: + case TAG_GNU_call_site: + { + ObjectAddressRange range; + start_dwarf_addr_ranges(obj, &range); + while (read_dwarf_addr_range(&range)) { + ContextAddress addr0 = range.mAddr - addr->lt_addr + addr->rt_addr; + ContextAddress addr1 = range.mAddr + range.mSize - addr->lt_addr + addr->rt_addr; + /* Note: need to use buf->size + 1, see stack trace logic */ + if (addr0 <= buf->addr + buf->size && addr1 > buf->addr) { + dio_ExitSection(); + if (obj->mTag == TAG_GNU_call_site) { + ObjectInfo * args = get_dwarf_children(obj); + while (args != NULL) { + PropertyValue pv; + if (args->mTag == TAG_GNU_call_site_parameter && (args->mFlags & DOIF_location)) { + RegisterDefinition * reg_def = NULL; + read_dwarf_object_property(ctx, STACK_NO_FRAME, args, AT_location, &pv); + if (pv.mAddr != NULL && pv.mSize == 1 && *pv.mAddr >= OP_reg0 && *pv.mAddr <= OP_reg31) { + reg_def = get_reg_by_id(ctx, *pv.mAddr - OP_reg0, &obj->mCompUnit->mRegIdScope); } - if (buf->addr + buf->size > addr1) { - assert(addr1 > buf->addr); - buf->size = addr1 - buf->addr; + if (reg_def != NULL) { + Trap trap; + if (set_trap(&trap)) { + LocationInfo info; + memset(&info, 0, sizeof(LocationInfo)); + read_dwarf_object_property(ctx, STACK_NO_FRAME, args, AT_GNU_call_site_value, &pv); + add_dwarf_location_command(&info, &pv); + if (info.value_cmds.cnt) { + StackFrameCallSiteParameter * c = NULL; + if (buf->call_cnt >= call_site_max) { + call_site_max += 32; + buf->calls = (StackFrameCallSiteParameter **)tmp_realloc(buf->calls, sizeof(StackFrameCallSiteParameter *) * call_site_max); + } + c = buf->calls[buf->call_cnt++] = (StackFrameCallSiteParameter *)tmp_alloc_zero(sizeof(StackFrameCallSiteParameter) + sizeof(LocationExpressionCommand) * (info.value_cmds.cnt - 1)); + c->addr = obj->u.mCode.mLowPC - addr->lt_addr + addr->rt_addr; + c->size = 1; + c->reg.reg = reg_def; + c->reg.cmds_cnt = info.value_cmds.cnt; + c->reg.cmds_max = info.value_cmds.cnt; + memcpy(c->reg.cmds, info.value_cmds.cmds, sizeof(LocationExpressionCommand) * info.value_cmds.cnt); + } + clear_trap(&trap); + } } - if (o->mTag == TAG_inlined_subroutine) add_inlined_subroutine(o, unit, addr0, addr1, buf); - search_inlined_subroutine(ctx, o, addr, buf); - dio_EnterSection(&unit->mDesc, debug_ranges, pos); - } - else if (addr1 <= addr->rt_addr && addr1 > buf->addr) { - buf->size = buf->addr + buf->size - addr1; - buf->addr = addr1; - } - else if (addr0 > addr->rt_addr && addr0 < buf->addr + buf->size) { - buf->size = addr0 - buf->addr; } + args = args->mSibling; } } + else { + search_stack_tracing_call_sites(ctx, obj, addr, buf); + } + break; } - dio_ExitSection(); - } - } - else if ((o->mFlags & DOIF_low_pc) && o->u.mCode.mHighPC.mAddr > o->u.mCode.mLowPC && o->u.mCode.mSection == addr->section) { - ContextAddress addr0 = o->u.mCode.mLowPC - addr->lt_addr + addr->rt_addr; - ContextAddress addr1 = o->u.mCode.mHighPC.mAddr - addr->lt_addr + addr->rt_addr; - if (addr0 <= addr->rt_addr && addr1 > addr->rt_addr) { - if (buf->addr < addr0) { - assert(buf->addr + buf->size > addr0); - buf->size = buf->addr + buf->size - addr0; - buf->addr = addr0; - } - if (buf->addr + buf->size > addr1) { - assert(addr1 > buf->addr); - buf->size = addr1 - buf->addr; - } - if (o->mTag == TAG_inlined_subroutine) add_inlined_subroutine(o, addr->unit, addr0, addr1, buf); - search_inlined_subroutine(ctx, o, addr, buf); - } - else if (addr1 <= addr->rt_addr && addr1 > buf->addr) { - buf->size = buf->addr + buf->size - addr1; - buf->addr = addr1; - } - else if (addr0 > addr->rt_addr && addr0 < buf->addr + buf->size) { - buf->size = addr0 - buf->addr; } } break; } - o = o->mSibling; + obj = obj->mSibling; } } @@ -2716,6 +2844,7 @@ int get_stack_tracing_info(Context * ctx, ContextAddress rt_addr, StackTracingIn if (dwarf_stack_trace_fp->cmds_cnt > 0) { static StackTracingInfo buf; memset(&buf, 0, sizeof(buf)); + assert(dwarf_stack_trace_size > 0); assert(dwarf_stack_trace_addr <= lt_addr); assert(dwarf_stack_trace_addr + dwarf_stack_trace_size > lt_addr); buf.addr = (ContextAddress)dwarf_stack_trace_addr - lt_addr + rt_addr; @@ -2724,16 +2853,18 @@ int get_stack_tracing_info(Context * ctx, ContextAddress rt_addr, StackTracingIn buf.reg_cnt = dwarf_stack_trace_regs_cnt; buf.fp = dwarf_stack_trace_fp; if (get_sym_context(ctx, STACK_NO_FRAME, rt_addr) == 0) { - /* Search inlined functions info. + /* Search inlined functions and call sites. * Note: when debug info is a separate file, * 'lt_addr' is not same as 'unit.lt_addr' */ UnitAddress unit; find_unit(ctx, rt_addr, &unit); if (unit.unit != NULL) { buf_sub_max = 0; + call_site_max = 0; assert(buf.addr <= unit.rt_addr); assert(buf.addr + buf.size == 0 || buf.addr + buf.size > unit.rt_addr); search_inlined_subroutine(ctx, unit.unit->mObject, &unit, &buf); + search_stack_tracing_call_sites(ctx, unit.unit->mObject, &unit, &buf); } } *info = &buf; @@ -2767,6 +2898,9 @@ int get_symbol_file_info(Context * ctx, ContextAddress addr, SymbolFileInfo ** i if (l > 6 && strncmp(fnm, "ld-", 3) == 0 && strcmp(fnm + l - 3, ".so") == 0) { (*info)->dyn_loader = 1; } + else if (l > 6 && strncmp(fnm, "ld.so.", 6) == 0) { + (*info)->dyn_loader = 1; + } } elf_list_done(ctx); return 0; @@ -2814,8 +2948,13 @@ static int unpack(const Symbol * sym) { assert(!is_array_type_pseudo_symbol(sym)); assert(!is_std_type_pseudo_symbol(sym)); assert(!is_constant_pseudo_symbol(sym)); - assert(sym->obj == NULL || sym->obj->mTag != 0); - assert(sym->obj == NULL || sym->obj->mCompUnit->mFile->dwarf_dt_cache != NULL); + if (sym->obj != NULL) { + assert(sym->obj->mCompUnit->mFile->dwarf_dt_cache != NULL); + if (sym->obj->mTag == 0 || (sym->obj->mFlags & DOIF_inv_reference) != 0) { + set_fmt_errno(ERR_INV_DWARF, "Invalid debug info entry at 0x%" PRIx64, (uint64_t)sym->obj->mID); + return -1; + } + } return get_sym_context(sym->ctx, sym->frame, 0); } @@ -3064,7 +3203,7 @@ static U8_T read_string_length(ObjectInfo * obj) { clear_trap(&trap); return len; } - else if (trap.error != ERR_SYM_NOT_FOUND) { + else if (get_error_code(trap.error) != ERR_SYM_NOT_FOUND) { exception(trap.error); } if (get_num_prop(obj, AT_byte_size, &len)) return len; @@ -3282,7 +3421,7 @@ int get_symbol_type_class(const Symbol * sym, int * type_class) { *type_class = TYPE_CLASS_FUNCTION; return 0; } - unpack_elf_symbol_info(sym->tbl, sym->index, &info); + if (elf_symbol_info(sym, &info) < 0) return -1; if (info.type == STT_FUNC || info.type == STT_GNU_IFUNC) { *type_class = TYPE_CLASS_FUNCTION; return 0; @@ -3320,7 +3459,7 @@ int get_symbol_name(const Symbol * sym, char ** name) { else if (sym->tbl != NULL) { ELF_SymbolInfo sym_info; if (sym->dimension == 0) { - unpack_elf_symbol_info(sym->tbl, sym->index, &sym_info); + if (elf_symbol_info(sym, &sym_info) < 0) return -1; if (sym_info.name != NULL) { size_t i; for (i = 0;; i++) { @@ -3449,7 +3588,7 @@ int get_symbol_size(const Symbol * sym, ContextAddress * size) { else if (sym->tbl != NULL) { if (sym->dimension == 0) { ELF_SymbolInfo info; - unpack_elf_symbol_info(sym->tbl, sym->index, &info); + if (elf_symbol_info(sym, &info) < 0) return -1; if (IS_PPC64_FUNC_OPD(sym->tbl->file, &info) && info.name != NULL) { /* * For PPC64, the size of an ELF symbol is either the size @@ -3880,31 +4019,65 @@ static void add_dwarf_location_command(LocationInfo * l, PropertyValue * v) { static void add_member_location_command(LocationInfo * info, ObjectInfo * obj) { U8_T bit_size = 0; U8_T bit_offs = 0; - PropertyValue v; - read_dwarf_object_property(sym_ctx, sym_frame, obj, AT_data_member_location, &v); - switch (v.mForm) { - case FORM_DATA1 : - case FORM_DATA2 : - case FORM_DATA4 : - case FORM_DATA8 : - case FORM_SDATA : - case FORM_UDATA : + Trap trap; + if (get_num_prop(obj, AT_data_bit_offset, &bit_offs)) { + U8_T byte_size = 0; + U8_T type_byte_size = 0; + U8_T type_bit_size = 0; + LocationExpressionCommand * cmd; add_location_command(info, SFT_CMD_ARG)->args.arg_no = 0; - add_location_command(info, SFT_CMD_NUMBER)->args.num = get_numeric_property_value(&v); - add_location_command(info, SFT_CMD_ADD); - break; - case FORM_BLOCK1 : - case FORM_BLOCK2 : - case FORM_BLOCK4 : - case FORM_BLOCK : - case FORM_EXPRLOC : - case FORM_SEC_OFFSET: + cmd = add_location_command(info, SFT_CMD_PIECE); + cmd->args.piece.bit_offs = (unsigned)bit_offs; + if (get_num_prop(obj, AT_bit_size, &bit_size)) { + cmd->args.piece.bit_size = (unsigned)bit_size; + } + else if (get_num_prop(obj, AT_byte_size, &byte_size)) { + cmd->args.piece.bit_size = (unsigned)(byte_size * 8); + } + else if (obj->mType != NULL && get_object_size(obj, obj->mType, 0, &type_byte_size, &type_bit_size)) { + cmd->args.piece.bit_size = (unsigned)type_bit_size; + } + else { + str_exception(ERR_INV_DWARF, "Unknown field size"); + } + return; + } + if (set_trap(&trap)) { + PropertyValue v; + read_dwarf_object_property(sym_ctx, sym_frame, obj, AT_data_member_location, &v); + switch (v.mForm) { + case FORM_DATA1: + case FORM_DATA2: + case FORM_DATA4: + case FORM_DATA8: + case FORM_SDATA: + case FORM_UDATA: + case FORM_IMPLICIT_CONST: + add_location_command(info, SFT_CMD_ARG)->args.arg_no = 0; + add_location_command(info, SFT_CMD_NUMBER)->args.num = get_numeric_property_value(&v); + add_location_command(info, SFT_CMD_ADD); + break; + case FORM_BLOCK1: + case FORM_BLOCK2: + case FORM_BLOCK4: + case FORM_BLOCK: + case FORM_EXPRLOC: + case FORM_SEC_OFFSET: + case FORM_LOCLISTX: + add_location_command(info, SFT_CMD_ARG)->args.arg_no = 0; + add_dwarf_location_command(info, &v); + break; + default: + str_fmt_exception(ERR_OTHER, "Invalid AT_data_member_location form 0x%04x", v.mForm); + break; + } + clear_trap(&trap); + } + else if (get_error_code(errno) != ERR_SYM_NOT_FOUND) { + str_exception(errno, "Cannot read AT_data_member_location"); + } + else { add_location_command(info, SFT_CMD_ARG)->args.arg_no = 0; - add_dwarf_location_command(info, &v); - break; - default: - str_fmt_exception(ERR_OTHER, "Invalid AT_data_member_location form 0x%04x", v.mForm); - break; } if (get_num_prop(obj, AT_bit_size, &bit_size)) { LocationExpressionCommand * cmd = add_location_command(info, SFT_CMD_PIECE); @@ -3961,7 +4134,7 @@ static int read_discriminant_values(ObjectInfo * obj, LocationInfo * info) { info->discr_lst->x = value; info->discr_lst->y = value; } - else if (errno != ERR_SYM_NOT_FOUND) { + else if (get_error_code(errno) != ERR_SYM_NOT_FOUND) { set_errno(errno, "Cannot read discriminant value"); return -1; } @@ -4013,7 +4186,7 @@ static int read_discriminant_values(ObjectInfo * obj, LocationInfo * info) { dio_ExitSection(); clear_trap(&trap); } - else if (errno != ERR_SYM_NOT_FOUND) { + else if (get_error_code(errno) != ERR_SYM_NOT_FOUND) { set_errno(errno, "Cannot read discriminant list"); return -1; } @@ -4097,7 +4270,7 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { LocationExpressionCommand * cmd = NULL; ObjectInfo * type = get_original_type(sym->var); if (!set_trap(&trap)) { - if (errno == ERR_SYM_NOT_FOUND) set_errno(ERR_OTHER, "Location attribute not found"); + if (get_error_code(errno) == ERR_SYM_NOT_FOUND) set_errno(ERR_OTHER, "Location attribute not found"); set_errno(errno, "Cannot evaluate location of 'this' pointer"); return -1; } @@ -4123,7 +4296,7 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { clear_trap(&trap); return 0; } - else if (errno != ERR_SYM_NOT_FOUND) { + else if (get_error_code(errno) != ERR_SYM_NOT_FOUND) { set_errno(errno, "Cannot read member location expression"); return -1; } @@ -4200,12 +4373,12 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { return 0; } else { - if (errno != ERR_SYM_NOT_FOUND) set_errno(errno, "Cannot read member location expression"); + if (get_error_code(errno) != ERR_SYM_NOT_FOUND) set_errno(errno, "Cannot read member location expression"); else set_errno(ERR_OTHER, "Member location info not available"); return -1; } } - if (obj->mTag == TAG_label && (obj->mFlags & DOIF_ranges) == 0 && (obj->mFlags & DOIF_low_pc) != 0) { + if (obj->mTag == TAG_label && !(obj->mFlags & DOIF_ranges) && (obj->mFlags & DOIF_low_pc)) { ContextAddress addr = elf_map_to_run_time_address(sym_ctx, obj->mCompUnit->mFile, obj->u.mCode.mSection, obj->u.mCode.mLowPC); if (errno) return -1; add_location_command(info, SFT_CMD_NUMBER)->args.num = addr; @@ -4226,8 +4399,11 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { if (tbl->sym_names_hash == NULL) continue; n = tbl->sym_names_hash[h % tbl->sym_names_hash_size]; while (n) { + Trap trap; ELF_SymbolInfo sym_info; + if (!set_trap(&trap)) continue; unpack_elf_symbol_info(tbl, n, &sym_info); + clear_trap(&trap); n = tbl->sym_names_next[n]; if (sym_info.bind != STB_GLOBAL || sym_info.type != STT_OBJECT) continue; if (sym_info.section == NULL || sym_info.section->name == NULL) continue; @@ -4346,7 +4522,7 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { add_location_command(info, SFT_CMD_NUMBER)->args.num = address; return 0; } - unpack_elf_symbol_info(sym->tbl, sym->index, &elf_sym_info); + if (elf_symbol_info(sym, &elf_sym_info) < 0) return -1; if (elf_sym_info.type == STT_GNU_IFUNC && elf_sym_info.name != NULL) { int error = 0; int found = 0; @@ -4425,12 +4601,9 @@ int get_symbol_flags(const Symbol * sym, SYM_FLAGS * flags) { } if (unpack(sym) < 0) return -1; if (sym->tbl != NULL && sym->dimension == 0) { - Trap trap; ELF_SymbolInfo info; - if (!set_trap(&trap)) return -1; - unpack_elf_symbol_info(sym->tbl, sym->index, &info); + if (elf_symbol_info(sym, &info) < 0) return -1; if (info.bind == STB_GLOBAL || info.bind == STB_WEAK) *flags |= SYM_FLAG_EXTERNAL; - clear_trap(&trap); } if (obj != NULL) { if (obj->mFlags & DOIF_external) *flags |= SYM_FLAG_EXTERNAL; @@ -4516,6 +4689,9 @@ int get_symbol_flags(const Symbol * sym, SYM_FLAGS * flags) { case TAG_inheritance: *flags |= SYM_FLAG_INHERITANCE; break; + case TAG_member: + *flags |= SYM_FLAG_MEMBER; + break; } } if (obj != NULL && !(*flags & (SYM_FLAG_BIG_ENDIAN|SYM_FLAG_LITTLE_ENDIAN))) { diff --git a/agent/tcf/services/symbols_proxy.c b/agent/tcf/services/symbols_proxy.c index c82fe3de..a10428f9 100644 --- a/agent/tcf/services/symbols_proxy.c +++ b/agent/tcf/services/symbols_proxy.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2022 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. @@ -475,13 +475,19 @@ static void free_stack_frame_cache(StackFrameCache * c) { c->disposed = 1; } if (c->pending == NULL) { - int i; + unsigned i; c->magic = 0; cache_dispose(&c->cache); release_error_report(c->error); context_unlock(c->ctx); - for (i = 0; i < c->sti.reg_cnt; i++) free_sft_sequence(c->sti.regs[i]); free_sft_sequence(c->sti.fp); + for (i = 0; i < c->sti.reg_cnt; i++) free_sft_sequence(c->sti.regs[i]); + for (i = 0; i < c->sti.call_cnt; i++) { + unsigned j = 0; + StackFrameCallSiteParameter * info = c->sti.calls[i]; + while (j < info->reg.cmds_cnt) free_location_command_args(info->reg.cmds + j++); + loc_free(info); + } for (i = 0; i < c->sti.sub_cnt; i++) { StackFrameInlinedSubroutine * info = c->sti.subs[i]; loc_free(info->area.directory); @@ -489,8 +495,9 @@ static void free_stack_frame_cache(StackFrameCache * c) { loc_free(info->func_id); loc_free(info); } - loc_free(c->sti.subs); loc_free(c->sti.regs); + loc_free(c->sti.calls); + loc_free(c->sti.subs); loc_free(c); } } @@ -1573,6 +1580,10 @@ static unsigned trace_regs_cnt = 0; static unsigned trace_regs_max = 0; static StackFrameRegisterLocation ** trace_regs = NULL; +static unsigned trace_calls_cnt = 0; +static unsigned trace_calls_max = 0; +static StackFrameCallSiteParameter ** trace_calls = NULL; + static unsigned trace_subs_cnt = 0; static unsigned trace_subs_max = 0; static StackFrameInlinedSubroutine ** trace_subs = NULL; @@ -1836,6 +1847,44 @@ static void read_stack_trace_register(InputStream * inp, const char * id, void * } } +static void read_stack_trace_call_props(InputStream * inp, const char * name, void * args) { + StackFrameCallSiteParameter * s = (StackFrameCallSiteParameter *)args; + if (strcmp(name, "CodeAddr") == 0) s->addr = (ContextAddress)json_read_uint64(inp); + else if (strcmp(name, "CodeSize") == 0) s->size = (ContextAddress)json_read_uint64(inp); + else if (strcmp(name, "Reg") == 0) { + Context * ctx = NULL; + int frame = STACK_NO_FRAME; + char id[256]; + json_read_string(inp, id, sizeof(id)); + if (id2register(id, &ctx, &frame, &s->reg.reg) < 0) { + id2register_error = errno; + } + } + else if (strcmp(name, "Value") == 0) { + location_cmds.cnt = 0; + json_read_array(inp, read_location_command, NULL); + } + else json_skip_object(inp); +} + +static void read_stack_trace_call_param(InputStream * inp, void * args) { + StackFrameCallSiteParameter buf; + StackFrameCallSiteParameter * param = NULL; + location_cmds.cnt = 0; + memset(&buf, 0, sizeof(StackFrameCallSiteParameter)); + json_read_struct(inp, read_stack_trace_call_props, &buf); + param = (StackFrameCallSiteParameter *)loc_alloc(sizeof(StackFrameCallSiteParameter) + (location_cmds.cnt - 1) * sizeof(LocationExpressionCommand)); + memcpy(param, &buf, sizeof(StackFrameCallSiteParameter)); + param->reg.cmds_cnt = location_cmds.cnt; + param->reg.cmds_max = location_cmds.cnt; + memcpy(param->reg.cmds, location_cmds.cmds, location_cmds.cnt * sizeof(LocationExpressionCommand)); + if (trace_calls_cnt >= trace_calls_max) { + trace_calls_max += 16; + trace_calls = (StackFrameCallSiteParameter **)loc_realloc(trace_calls, trace_calls_max * sizeof(StackFrameCallSiteParameter *)); + } + trace_calls[trace_calls_cnt++] = param; +} + static void read_inlined_subroutine_props(InputStream * inp, const char * name, void * args) { StackFrameInlinedSubroutine * s = (StackFrameInlinedSubroutine *)args; if (strcmp(name, "ID") == 0) s->func_id = json_read_alloc_string(inp); @@ -1866,13 +1915,22 @@ static void read_stack_frame_fp(InputStream * inp, StackFrameCache * f) { static void read_stack_frame_regs(InputStream * inp, StackFrameCache * f) { trace_regs_cnt = 0; - if (json_read_struct(inp, read_stack_trace_register, NULL)) { + if (json_read_struct(inp, read_stack_trace_register, NULL) && trace_regs_cnt > 0) { f->sti.reg_cnt = trace_regs_cnt; f->sti.regs = (StackFrameRegisterLocation **)loc_alloc(trace_regs_cnt * sizeof(StackFrameRegisterLocation *)); memcpy(f->sti.regs, trace_regs, trace_regs_cnt * sizeof(StackFrameRegisterLocation *)); } } +static void read_stack_frame_calls(InputStream * inp, StackFrameCache * f) { + trace_calls_cnt = 0; + if (json_read_array(inp, read_stack_trace_call_param, NULL)) { + f->sti.call_cnt = trace_calls_cnt; + f->sti.calls = (StackFrameCallSiteParameter **)loc_alloc(trace_calls_cnt * sizeof(StackFrameCallSiteParameter *)); + memcpy(f->sti.calls, trace_calls, trace_calls_cnt * sizeof(StackFrameCallSiteParameter *)); + } +} + static void read_stack_frame_inlined(InputStream * inp, StackFrameCache * f) { trace_subs_cnt = 0; if (json_read_array(inp, read_inlined_subroutine, NULL)) { @@ -1888,6 +1946,7 @@ static void read_stack_frame_props(InputStream * inp, const char * name, void * else if (strcmp(name, "CodeSize") == 0) f->sti.size = (ContextAddress)json_read_uint64(inp); else if (strcmp(name, "FP") == 0) read_stack_frame_fp(inp, f); else if (strcmp(name, "Regs") == 0) read_stack_frame_regs(inp, f); + else if (strcmp(name, "Calls") == 0) read_stack_frame_calls(inp, f); else if (strcmp(name, "Inlined") == 0) read_stack_frame_inlined(inp, f); else json_skip_object(inp); } diff --git a/agent/tcf/services/sysmon.c b/agent/tcf/services/sysmon.c index 18902f38..adeebf7d 100644 --- a/agent/tcf/services/sysmon.c +++ b/agent/tcf/services/sysmon.c @@ -730,7 +730,7 @@ static void command_get_children(char * token, Channel * c) { DWORD * prs_ids = NULL; int prs_cnt = 0; if (EnumProcessesProc == NULL) { - HINSTANCE psapi = LoadLibrary("PSAPI.DLL"); + HINSTANCE psapi = LoadLibrarySystem32("PSAPI.DLL"); if (psapi == NULL) { err = set_win32_errno(GetLastError()); } diff --git a/agent/tcf/services/tcf_elf.c b/agent/tcf/services/tcf_elf.c index ce73c470..1b3900ec 100644 --- a/agent/tcf/services/tcf_elf.c +++ b/agent/tcf/services/tcf_elf.c @@ -1799,20 +1799,43 @@ ContextAddress elf_run_time_address_in_region(Context * ctx, MemoryRegion * r, E /* Note: when debug info is in a separate file, debug file link-time addresses are not same as exec file link-time addresses, * because Linux has a habbit of re-linking execs after extracting debug info */ unsigned i; + int same_file = 0; + ELF_File * mem_file = file; errno = 0; + if (r->dev == 0) { + same_file = file_name_equ(file, r->file_name); + } + else { + ino_t ino = r->ino; + if (ino == 0) ino = elf_ino(r->file_name); + same_file = file->ino == ino && file->dev == r->dev; + } + if (!same_file) { + /* Check if the memory map entry has a separate debug info file */ + if (!file->debug_info_file) mem_file = NULL; + else mem_file = elf_open_memory_region_file(r, NULL); + if (mem_file != NULL && get_dwarf_file(mem_file) != file) mem_file = NULL; + if (mem_file == NULL) { + errno = ERR_INV_ADDRESS; + return 0; + } + } if (r->sect_name == NULL) { ContextAddress rt = 0; if (r->size == 0) { errno = ERR_INV_ADDRESS; return 0; } - for (i = 0; i < file->pheader_cnt; i++) { - ELF_PHeader * p = file->pheaders + i; - if (!is_p_header_region(file, p, r)) continue; - if (addr < p->address || addr >= p->address + p->mem_size) continue; - rt = (ContextAddress)(addr - p->address + p->offset - r->file_offs + r->addr); - if (rt < r->addr || rt > r->addr + r->size - 1) continue; - return rt; + for (i = 0; i < mem_file->pheader_cnt; i++) { + ELF_PHeader * p = mem_file->pheaders + i; + if (p->type == PT_LOAD) { + U8_T p_addr = i < file->pheader_cnt ? file->pheaders[i].address : p->address; + if (addr < p_addr || addr >= p_addr + p->mem_size) continue; + if (!is_p_header_region(mem_file, p, r)) continue; + rt = (ContextAddress)(addr - p_addr + p->offset - r->file_offs + r->addr); + if (rt < r->addr || rt > r->addr + r->size - 1) continue; + return rt; + } } } else if (sec != NULL) { @@ -1820,9 +1843,9 @@ ContextAddress elf_run_time_address_in_region(Context * ctx, MemoryRegion * r, E return (ContextAddress)(addr - sec->addr + r->addr); } } - else if (file->type == ET_EXEC || file->type == ET_DYN) { - for (i = 1; i < file->section_cnt; i++) { - ELF_Section * s = file->sections + i; + else if (mem_file->type == ET_EXEC || mem_file->type == ET_DYN) { + for (i = 1; i < mem_file->section_cnt; i++) { + ELF_Section * s = mem_file->sections + i; if (s->addr <= addr && s->addr + s->size > addr && s->name != NULL && strcmp(s->name, r->sect_name) == 0) { return (ContextAddress)(addr - s->addr + r->addr); @@ -1842,25 +1865,7 @@ ContextAddress elf_map_to_run_time_address(Context * ctx, ELF_File * file, ELF_S if (elf_get_map(ctx, 0, ~(ContextAddress)0, &elf_map) < 0) return 0; for (i = 0; i < elf_map.region_cnt; i++) { MemoryRegion * r = elf_map.regions + i; - ContextAddress a = 0; - int same_file = 0; - if (r->dev == 0) { - same_file = file_name_equ(file, r->file_name); - } - else { - ino_t ino = r->ino; - if (ino == 0) ino = elf_ino(r->file_name); - same_file = file->ino == ino && file->dev == r->dev; - } - if (!same_file) { - /* Check if the memory map entry has a separate debug info file */ - ELF_File * exec = NULL; - if (!file->debug_info_file) continue; - exec = elf_open_memory_region_file(r, NULL); - if (exec == NULL) continue; - if (get_dwarf_file(exec) != file) continue; - } - a = elf_run_time_address_in_region(ctx, r, file, sec, addr); + ContextAddress a = elf_run_time_address_in_region(ctx, r, file, sec, addr); if (errno == 0) { rt = a; cnt++; diff --git a/agent/tcf/services/tcf_elf.h b/agent/tcf/services/tcf_elf.h index 530dae8a..a827d2dd 100644 --- a/agent/tcf/services/tcf_elf.h +++ b/agent/tcf/services/tcf_elf.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2021 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. @@ -29,10 +29,6 @@ #endif #include <tcf/framework/context.h> -#ifndef EM_RISCV -# define EM_RISCV 243 /* RISC-V */ -#endif - #if !defined(INCLUDE_NATIVE_ELF_H) #define EI_MAG0 0 @@ -85,6 +81,7 @@ #define EM_V850 87 /* NEC/Renesas RH850 */ #define EM_AARCH64 183 /* ARM 64-bit architecture */ #define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ +#define EM_ARC_V2 195 /* Synopsys ARC ARCv2 */ #define ET_NONE 0 #define ET_REL 1 @@ -398,6 +395,13 @@ typedef struct { #ifndef EM_TRICORE #define EM_TRICORE 44 /* Siemens Tricore */ #endif +#ifndef EM_ARC_V2 +#define EM_ARC_V2 195 /* Synopsys ARC ARCv2 */ +#endif +#ifndef EM_RISCV +#define EM_RISCV 243 /* RISC-V */ +#endif + #ifndef STT_GNU_IFUNC #define STT_GNU_IFUNC 10 #endif diff --git a/agent/tcf/services/vm.c b/agent/tcf/services/vm.c index 4b69c41e..df375ab7 100644 --- a/agent/tcf/services/vm.c +++ b/agent/tcf/services/vm.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2011-2022 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. @@ -30,7 +30,7 @@ #include <tcf/services/dwarf.h> #include <tcf/services/vm.h> -#define check_e_stack(n) { if (state->stk_pos < n) inv_dwarf("Invalid location expression stack"); } +#define check_e_stack(n) { if (state->stk_pos < (unsigned)(n)) inv_dwarf("Invalid location expression stack"); } static LocationExpressionState * state = NULL; static RegisterDefinition * reg_def = NULL; @@ -138,6 +138,38 @@ static uint64_t read_ua(void) { return 0; } +static void f32_to_f64(void) { + union { float f; uint32_t u; } f32; + union { double f; uint64_t u; } f64; + f32.u = (uint32_t)state->type_stk[state->stk_pos - 1]; + f64.f = (double)f32.f; + state->type_stk[state->stk_pos - 1] = f64.u; +} + +static void f64_to_u64(void) { + union { double f; uint64_t u; } f64; + f64.u = state->type_stk[state->stk_pos - 1]; + state->type_stk[state->stk_pos - 1] = (uint64_t)f64.f; +} + +static void f64_to_i64(void) { + union { double f; uint64_t u; } f64; + f64.u = state->type_stk[state->stk_pos - 1]; + state->type_stk[state->stk_pos - 1] = (int64_t)f64.f; +} + +static void i64_to_f64(void) { + union { double f; uint64_t u; } f64; + f64.f = (double)(int64_t)state->type_stk[state->stk_pos - 1]; + state->type_stk[state->stk_pos - 1] = f64.u; +} + +static void u64_to_f64(void) { + union { double f; uint64_t u; } f64; + f64.f = (double)(uint64_t)state->type_stk[state->stk_pos - 1]; + state->type_stk[state->stk_pos - 1] = f64.u; +} + static LocationPiece * add_piece(void) { LocationPiece * piece = NULL; if (state->pieces_cnt >= state->pieces_max) { @@ -642,6 +674,10 @@ static void evaluate_expression(void) { piece = add_piece(); piece->bit_size = read_u4leb128(); piece->bit_offs = read_u4leb128(); + if (piece->reg == NULL && piece->value == NULL && piece->optimized_away == 0) { + piece->addr += piece->bit_offs / 8; + piece->bit_offs %= 8; + } break; case OP_implicit_value: value_size = read_u4leb128(); @@ -666,68 +702,158 @@ static void evaluate_expression(void) { } if (!is_end_of_loc_expr()) inv_dwarf("OP_stack_value must be last instruction"); break; + case OP_const_type: case OP_GNU_const_type: - inv_dwarf("Unsupported type in OP_GNU_const_type"); + { + uint32_t fund_type = read_u4leb128(); + uint32_t type_size = read_u4leb128(); + uint64_t size = read_u8leb128(); + if (type_size == size) { + switch (fund_type) { + case ATE_address: + case ATE_unsigned: + case ATE_unsigned_char: + case ATE_unsigned_fixed: + case ATE_UTF: + case ATE_boolean: + switch (size) { + case 1: + state->stk[state->stk_pos++] = (uint8_t)read_u1(); + break; + case 2: + state->stk[state->stk_pos++] = (uint16_t)read_u2(); + break; + case 4: + state->stk[state->stk_pos++] = (uint32_t)read_u4(); + break; + case 8: + state->stk[state->stk_pos++] = read_u8(); + break; + default: + inv_dwarf("Unsupported type in OP_const_type"); + break; + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; + break; + case ATE_signed: + case ATE_signed_char: + case ATE_signed_fixed: + switch (size) { + case 1: + state->stk[state->stk_pos++] = (int8_t)read_u1(); + break; + case 2: + state->stk[state->stk_pos++] = (int16_t)read_u2(); + break; + case 4: + state->stk[state->stk_pos++] = (int32_t)read_u4(); + break; + case 8: + state->stk[state->stk_pos++] = read_u8(); + break; + default: + inv_dwarf("Unsupported type in OP_const_type"); + break; + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER; + break; + case ATE_float: + case ATE_imaginary_float: + switch (size) { + case 4: + state->stk[state->stk_pos++] = read_u4(); + f32_to_f64(); + break; + case 8: + state->stk[state->stk_pos++] = read_u8(); + break; + default: + inv_dwarf("Unsupported type in OP_const_type"); + break; + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_REAL; + break; + default: + inv_dwarf("Unsupported type in OP_const_type"); + break; + } + } + else { + inv_dwarf("Unsupported type in OP_const_type"); + } + } break; + case OP_regval_type: case OP_GNU_regval_type: - inv_dwarf("Unsupported type in OP_GNU_regval_type"); - break; - case OP_GNU_deref_type: - check_e_stack(1); { - size_t mem_size = (size_t)read_u8leb128(); + unsigned reg = (unsigned)read_u8leb128(); uint32_t fund_type = read_u4leb128(); uint32_t type_size = read_u4leb128(); + RegisterDefinition * def = get_reg_by_id(state->ctx, reg, &state->reg_id_scope); + if (def == NULL) exception(errno); + if (read_reg_value(state->stack_frame, def, state->stk + state->stk_pos++) < 0) exception(errno); switch (fund_type) { case ATE_address: case ATE_unsigned: case ATE_unsigned_char: case ATE_unsigned_fixed: case ATE_UTF: - if (mem_size > type_size) mem_size = (size_t)type_size; - state->stk[state->stk_pos - 1] = read_memory(state->stk[state->stk_pos - 1], mem_size); - state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; - break; case ATE_boolean: - if (mem_size > type_size) mem_size = (size_t)type_size; - state->stk[state->stk_pos - 1] = read_memory(state->stk[state->stk_pos - 1], mem_size); - if (state->stk[state->stk_pos - 1] != 0) state->stk[state->stk_pos - 1] = 1; + if (type_size < 8) { + uint64_t mask = ((uint64_t)1 << (type_size * 8)) - 1; + state->stk[state->stk_pos - 1] |= ~mask; + } state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; break; case ATE_signed: case ATE_signed_char: case ATE_signed_fixed: - if (mem_size > type_size) mem_size = (size_t)type_size; - state->stk[state->stk_pos - 1] = read_memory(state->stk[state->stk_pos - 1], mem_size); - if (mem_size < 8) { - uint64_t sign = (uint64_t)1 << (mem_size * 8 - 1); + if (type_size < 8) { + uint64_t sign = (uint64_t)1 << (type_size * 8 - 1); if (state->stk[state->stk_pos - 1] & sign) { state->stk[state->stk_pos - 1] |= ~(sign - 1); } } state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER; break; + case ATE_float: + case ATE_imaginary_float: + switch (type_size) { + case 4: + f32_to_f64(); + break; + case 8: + break; + default: + inv_dwarf("Unsupported type in OP_regval_type"); + break; + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_REAL; + break; default: - inv_dwarf("Unsupported type in OP_GNU_deref_type"); + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; break; } } break; - case OP_GNU_convert: - check_e_stack(1); + case OP_deref_type: + case OP_xderef_type: + case OP_GNU_deref_type: + check_e_stack(op == OP_xderef_type ? 2 : 1); { + size_t mem_size = (size_t)read_u8leb128(); uint32_t fund_type = read_u4leb128(); uint32_t type_size = read_u4leb128(); + uint64_t addr = state->stk[state->stk_pos - 1]; + if (op == OP_xderef_type) state->stk_pos--; + if (mem_size > type_size) mem_size = (size_t)type_size; + state->stk[state->stk_pos - 1] = read_memory(addr, mem_size); switch (fund_type) { case ATE_address: case ATE_unsigned: case ATE_unsigned_char: case ATE_unsigned_fixed: case ATE_UTF: - if (type_size < 8) { - uint64_t sign = (uint64_t)1 << (type_size * 8 - 1); - state->stk[state->stk_pos - 1] &= sign - 1; - } state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; break; case ATE_boolean: @@ -737,19 +863,121 @@ static void evaluate_expression(void) { case ATE_signed: case ATE_signed_char: case ATE_signed_fixed: - if (type_size < 8) { - uint64_t sign = (uint64_t)1 << (type_size * 8 - 1); + if (mem_size < 8) { + uint64_t sign = (uint64_t)1 << (mem_size * 8 - 1); if (state->stk[state->stk_pos - 1] & sign) { state->stk[state->stk_pos - 1] |= ~(sign - 1); } - else { + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER; + break; + case ATE_float: + case ATE_imaginary_float: + switch (type_size) { + case 4: + f32_to_f64(); + break; + case 8: + break; + default: + inv_dwarf("Unsupported type in OP_regval_type"); + break; + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_REAL; + break; + default: + inv_dwarf("Unsupported type in OP_deref_type"); + break; + } + } + break; + case OP_convert: + case OP_GNU_convert: + check_e_stack(1); + { + uint32_t fund_type = read_u4leb128(); + uint32_t type_size = read_u4leb128(); + switch (state->type_stk[state->stk_pos - 1]) { + case TYPE_CLASS_POINTER: + case TYPE_CLASS_CARDINAL: + case TYPE_CLASS_INTEGER: + case TYPE_CLASS_ENUMERATION: + switch (fund_type) { + case ATE_address: + case ATE_unsigned: + case ATE_unsigned_char: + case ATE_unsigned_fixed: + case ATE_UTF: + if (type_size < 8) { + uint64_t sign = (uint64_t)1 << (type_size * 8 - 1); state->stk[state->stk_pos - 1] &= sign - 1; } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; + break; + case ATE_boolean: + if (state->stk[state->stk_pos - 1] != 0) state->stk[state->stk_pos - 1] = 1; + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; + break; + case ATE_signed: + case ATE_signed_char: + case ATE_signed_fixed: + if (type_size < 8) { + uint64_t sign = (uint64_t)1 << (type_size * 8 - 1); + if (state->stk[state->stk_pos - 1] & sign) { + state->stk[state->stk_pos - 1] |= ~(sign - 1); + } + else { + state->stk[state->stk_pos - 1] &= sign - 1; + } + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER; + break; + case ATE_float: + case ATE_imaginary_float: + if (state->type_stk[state->stk_pos - 1] == TYPE_CLASS_INTEGER) { + i64_to_f64(); + } + else { + u64_to_f64(); + } + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_REAL; + break; + default: + inv_dwarf("Unsupported type in OP_convert"); + break; + } + break; + case TYPE_CLASS_REAL: + switch (fund_type) { + case ATE_address: + case ATE_unsigned: + case ATE_unsigned_char: + case ATE_unsigned_fixed: + case ATE_UTF: + f64_to_u64(); + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; + break; + case ATE_boolean: + f64_to_u64(); + if (state->stk[state->stk_pos - 1] != 0) state->stk[state->stk_pos - 1] = 1; + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL; + break; + case ATE_signed: + case ATE_signed_char: + case ATE_signed_fixed: + f64_to_i64(); + state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER; + break; + case ATE_float: + case ATE_imaginary_float: + break; + default: + inv_dwarf("Unsupported type in OP_convert"); + break; } - state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER; break; default: - inv_dwarf("Unsupported type in OP_GNU_convert"); + inv_dwarf("Unsupported type in OP_convert"); break; } } @@ -851,6 +1079,7 @@ static void evaluate_expression(void) { implicit_pointer++; } break; + case OP_entry_value: case OP_GNU_entry_value: { #if SERVICE_StackTrace || ENABLE_ContextProxy |