diff options
158 files changed, 13842 insertions, 3280 deletions
diff --git a/README.md b/README.md new file mode 100644 index 00000000..ad21a372 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +Target Communication Framework +============================== +[TCF] is a vendor-neutral, lightweight, extensible network protocol +mainly for communicating with embedded systems (targets). On top of the +protocol specification, which is the core of TCF, the project includes +a plain-C implementation of a lightweight extendable target agent, Java +client API (usable stand-alone or on top of Eclipse), [Python] and +[Lua] client APIs, complete debugger UI implementation in Eclipse, +integration with [CDT], Target Explorer, documentation and usage examples. + +Contents +-------- + +[agent](agent) +: The reference agent, implementing debug related [services] e.g. +Memory, RunControl, Registers, Stacktrace, Breakpoints, Symbols, LineNumbers, +Expressions. + +[docker](docker/README.md) +: Dockerfile image for host and cross builds of the debug agent. + +[examples](agent) +: Implementation of a daytime service. + +[server](server) +: A proxy server sitting between the client on the host and an agent +running/embedded on the target as part of the firmware or RTOS. It +implements Symbols and LineNumbers [services]. + +[tests](tests) +: Standalone tools for testing (e.g dwarf, extended commandline client) + +Links +----- + + * [Getting started](https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Getting%20Started.html) + * [TCF Specification](https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Specification.html) + * [Mailinglist](https://dev.eclipse.org/mailman/listinfo/tcf-dev) + * [Bugzilla](https://bugs.eclipse.org/bugs/buglist.cgi?query_format=advanced;classification=Tools;product=TCF) + +[TCF]: https://wiki.eclipse.org/TCF (Landing page) +[Python]: https://git.eclipse.org/c/tcf/org.eclipse.tcf.git/tree/python (Python client repository) +[Lua]: https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Lua%20Integration.html (Lua guide) +[CDT]: https://git.eclipse.org/c/tcf/org.eclipse.tcf.git (CDT/Java repository) +[services]: https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Services.html diff --git a/agent/Makefile b/agent/Makefile index 251d34d6..34587153 100644 --- a/agent/Makefile +++ b/agent/Makefile @@ -82,6 +82,10 @@ $(BINDIR)/tcf/main/test$(EXTOBJ): tcf/main/test.c $(CCDEPS) @$(call MKDIR,$(dir $@)) $(CC) $(filter-out -O%,$(CFLAGS)) -O0 $(OUT_OBJ_F)$@ $(NO_LINK_F) $< +$(BINDIR)/machine/riscv64/%$(EXTOBJ): machine/riscv64/%.c $(wildcard machine/riscv/tcf/*.c) $(CCDEPS) + @$(call MKDIR,$(dir $@)) + $(CC) $(CFLAGS) $(OUT_OBJ_F)$@ $(NO_LINK_F) $< + $(BINDIR)/%$(EXTOBJ): %.c $(CCDEPS) @$(call MKDIR,$(dir $@)) $(CC) $(CFLAGS) $(OUT_OBJ_F)$@ $(NO_LINK_F) $< diff --git a/agent/Makefile.inc b/agent/Makefile.inc index 8aa0c6bb..1161049f 100644 --- a/agent/Makefile.inc +++ b/agent/Makefile.inc @@ -27,10 +27,10 @@ SRCDIRS = . system/$(OPSYS)/tcf machine/$(MACHINE)/tcf tcf tcf/framework tcf/ser BINDIR = obj/$(OPSYS)/$(MACHINE)/$(CONF) ifndef MKDIR -MKDIR = mkdir -p $(1) + MKDIR = mkdir -p $(1) endif ifndef RMDIR -RMDIR = rm -rf $(1) + RMDIR = rm -rf $(1) endif ifeq ($(CONF),Debug) @@ -104,20 +104,20 @@ endif # Compiler flags definition -CC ?= gcc -OUT_OBJ_F ?= -o # with a trailing space -NO_LINK_F ?= -c +CC ?= gcc +OUT_OBJ_F ?= -o # with a trailing space +NO_LINK_F ?= -c # Linker definition and flags -LINK ?= $(CC) -LINK_FLAGS ?= $(CFLAGS) -LINK_OUT_F ?= $(OUT_OBJ_F) +LINK ?= $(CC) +LINK_FLAGS ?= $(CFLAGS) +LINK_OUT_F ?= $(OUT_OBJ_F) # Archiver definition and flags -AR ?= ar -AR_FLAGS ?= -rc +AR ?= ar +AR_FLAGS ?= -rc EXTOBJ ?= .o EXTLIB ?= .a @@ -150,10 +150,13 @@ ifdef OpenSSL LIBS += $(LIBSSL) $(LIBCRYPTO) endif -ifeq ($(OPSYS),MinGW) - VERSION := 1.7.0 +SPEC_FILE := $(wildcard $(TCF_AGENT_DIR)/tcf/main/tcf-agent.spec) +ifeq (,$(SPEC_FILE)) + VERSION := 1.8.0 +else ifeq ($(OPSYS),MinGW) + VERSION := 1.8.0 else - VERSION := $(shell grep "%define version " $(TCF_AGENT_DIR)/tcf/main/tcf-agent.spec | sed -e "s/%define version //") + VERSION := $(shell grep "%define version " $(SPEC_FILE) | sed -e "s/%define version //") endif INSTALLROOT ?= /tmp @@ -181,6 +184,12 @@ ifeq ($(OPSYS),MinGW) CFILES += system/Windows/tcf/context-win32.c endif +ifeq ($(MACHINE),a64) + CFILES += machine/arm/tcf/stack-crawl-arm.c + CFILES += machine/arm/tcf/disassembler-arm.c + CFILES += machine/arm/tcf/disassembler-thumb.c +endif + ifdef SERVICES OPTS += $(shell $(TCF_AGENT_DIR)/bin/services-to-cflags $(SERVICES)) endif diff --git a/agent/bin/create-agent-project b/agent/bin/create-agent-project new file mode 100755 index 00000000..b467933e --- /dev/null +++ b/agent/bin/create-agent-project @@ -0,0 +1,328 @@ +#!/bin/bash +set -e + +while getopts n:f name ; do + case $name in + f) + FORCE=y + ;; + n) + OPSYS=$OPTARG + ;; + esac +done + +cd `dirname $0`/../../.. + +echo "This script creates a git repository for a customized TCF agent." +echo "The repository will contain minimal amount of code" +echo "to start porting the agent to a new OS." +echo + +if [ -z "$OPSYS" ] ; then + read -p 'Target OS name: ' OPSYS +fi + +if [ -z "$OPSYS" ] ; then + exit 0 +fi + +REPO=tcf.agent.$OPSYS + +if [ -z "$FORCE" ] ; then + if [ -d $REPO ] ; then + echo "Directory $REPO already exists" + exit 1 + fi +else + rm -rf $REPO +fi + +mkdir $REPO +cd $REPO + +mkdir -p system/$OPSYS/tcf + +cat >system/$OPSYS/tcf/context-`echo "$OPSYS" | tr '[:upper:]' '[:lower:]'`.c <<EOF +#include <tcf/config.h> + +#include <tcf/framework/myalloc.h> +#include <tcf/framework/events.h> +#include <tcf/framework/context.h> + +Context * context_find_from_pid(pid_t pid, int thread) { + return NULL; +} + +int context_attach_self(void) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_attach(pid_t pid, ContextAttachCallBack * done, void * client_data, int mode) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_has_state(Context * ctx) { + return 0; +} + +#if ENABLE_ContextMemoryProperties +int context_get_memory_properties(Context * ctx, const char *** names, const char *** values, int * cnt) { + return 0; +} +#endif + +#if ENABLE_ContextExtraProperties +int context_get_extra_properties(Context * ctx, const char *** names, const char *** values, int * cnt) { + return 0; +} +#endif + +#if ENABLE_ContextStateProperties +int context_get_state_properties(Context * ctx, const char *** names, const char *** values, int * cnt) { + return 0; +} +#endif + +int context_stop(Context * ctx) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_can_resume(Context * ctx, int mode) { + return 0; +} + +int context_continue(Context * ctx) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_single_step(Context * ctx) { + errno = ERR_UNSUPPORTED; + return -1; +} + +const char * context_suspend_reason(Context * ctx) { + return NULL; +} + +int context_get_memory_map(Context * ctx, MemoryMap * map) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { + errno = ERR_UNSUPPORTED; + return -1; +} + +#if ENABLE_ExtendedMemoryErrorReports +int context_get_mem_error_info(MemoryErrorInfo * info) { + errno = ERR_UNSUPPORTED; + return -1; +} +#endif + +#if ENABLE_MemoryAccessModes +int context_write_mem_ext(Context * ctx, MemoryAccessMode * mode, ContextAddress address, void * buf, size_t size) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_read_mem_ext(Context * ctx, MemoryAccessMode * mode, ContextAddress address, void * buf, size_t size) { + errno = ERR_UNSUPPORTED; + return -1; +} +#endif + +int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { + errno = ERR_UNSUPPORTED; + return -1; +} + +unsigned context_word_size(Context * ctx) { + return 8; +} + +int context_get_canonical_addr(Context * ctx, ContextAddress addr, + Context ** canonical_ctx, ContextAddress * canonical_addr, + ContextAddress * block_addr, ContextAddress * block_size) { + errno = ERR_UNSUPPORTED; + return -1; +} + +Context * context_get_group(Context * ctx, int group) { + return ctx; +} + +int context_get_supported_bp_access_types(Context * ctx) { + return 0; +} + +int context_plant_breakpoint(ContextBreakpoint * bp) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int context_unplant_breakpoint(ContextBreakpoint * bp) { + errno = ERR_UNSUPPORTED; + return -1; +} + +#if ENABLE_ContextBreakpointCapabilities +int context_get_breakpoint_capabilities(Context * ctx, const char *** names, const char *** values, int * cnt) { + *cnt = 0; + return 0; +} +#endif + +#if ENABLE_ExtendedBreakpointStatus +int context_get_breakpoint_status(ContextBreakpoint * bp, const char *** names, const char *** values, int * cnt) { + *cnt = 0; + return 0; +} +#endif + +#if ENABLE_ContextISA +int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { + errno = ERR_UNSUPPORTED; + return -1; +} +#endif + +RegisterDefinition * get_reg_definitions(Context * ctx) { + return NULL; +} + +RegisterDefinition * get_PC_definition(Context * ctx) { + return NULL; +} + +RegisterDefinition * get_reg_by_id(Context * ctx, unsigned id, RegisterIdScope * scope) { + return NULL; +} + +int read_reg_bytes(StackFrame * frame, RegisterDefinition * reg_def, unsigned offs, unsigned size, uint8_t * buf) { + errno = ERR_UNSUPPORTED; + return -1; +} + +int write_reg_bytes(StackFrame * frame, RegisterDefinition * reg_def, unsigned offs, unsigned size, uint8_t * buf) { + errno = ERR_UNSUPPORTED; + return -1; +} + +uint8_t * get_break_instruction(Context * ctx, size_t * size) { + return NULL; +} + +int crawl_stack_frame(StackFrame * frame, StackFrame * down) { + errno = ERR_UNSUPPORTED; + return -1; +} + +void init_contexts_sys_dep(void) { +} +EOF + +cat >system/$OPSYS/tcf/regset.h <<EOF +#include <tcf/config.h> +EOF + +cat >Makefile <<EOF +OPSYS = $OPSYS +MACHINE = x86_64 +LIBS = -lpthread -lrt +TCF_AGENT_DIR=../org.eclipse.tcf.agent/agent + +include \$(TCF_AGENT_DIR)/Makefile.inc + +override CFLAGS += \$(foreach dir,\$(INCDIRS),-I\$(dir)) \$(OPTS) + +HFILES := \$(foreach dir,\$(SRCDIRS),\$(wildcard \$(dir)/*.h)) \$(HFILES) +CFILES := \$(sort \$(foreach dir,\$(SRCDIRS),\$(wildcard \$(dir)/*.c)) \$(CFILES)) + +all: \$(addprefix \$(BINDIR)/,agent\$(EXTEXE)) + +\$(BINDIR)/libtcf\$(EXTLIB) : \$(OFILES) + \$(AR) \$(AR_FLAGS) \$(AR_OUT_F)\$@ \$^ + \$(RANLIB) + +\$(BINDIR)/agent\$(EXTEXE): \$(BINDIR)/tcf/main/main\$(EXTOBJ) \$(BINDIR)/libtcf\$(EXTLIB) + \$(LINK) \$(LINK_FLAGS) \$(LINK_OUT_F)\$@ \$(BINDIR)/tcf/main/main\$(EXTOBJ) \$(BINDIR)/libtcf\$(EXTLIB) \$(LIBS) + +\$(BINDIR)/%\$(EXTOBJ): %.c \$(HFILES) Makefile + @\$(call MKDIR,\$(dir \$@)) + \$(CC) \$(CFLAGS) -c -o \$@ \$< + +\$(BINDIR)/%\$(EXTOBJ): \$(TCF_AGENT_DIR)/%.c \$(HFILES) Makefile + @\$(call MKDIR,\$(dir \$@)) + \$(CC) \$(CFLAGS) -c -o \$@ \$< + +clean: + \$(call RMDIR,\$(BINDIR)) +EOF + +mkdir -p tcf + +cat >tcf/config.h <<EOF +#ifndef D_config +#define D_config + +#define ENABLE_SSL 0 +#define ENABLE_ELF 0 +#define ENABLE_LineNumbersProxy 1 +#define ENABLE_SymbolsProxy 1 +#define ENABLE_ContextProxy 1 + +#define ENABLE_ContextIdHashTable 1 +#define ENABLE_ContextMemoryProperties 0 +#define ENABLE_ContextExtraProperties 0 +#define ENABLE_ContextStateProperties 0 +#define ENABLE_ContextBreakpointCapabilities 0 +#define ENABLE_ExtendedBreakpointStatus 0 +#define ENABLE_ExtendedMemoryErrorReports 0 +#define ENABLE_MemoryAccessModes 0 +#define ENABLE_ContextISA 1 + +#define USE_uuid_generate 0 + +#define SERVICE_Symbols 0 +#define SERVICE_LineNumbers 0 +#define SERVICE_SysMonitor 0 +#define SERVICE_Terminals 0 + +#include <tcf/framework/config.h> + +#endif /* D_config */ +EOF + +cat >.gitignore <<EOF +/obj +EOF + +git init +git add .gitignore Makefile +git add tcf/* system/$OPSYS/tcf/* +git commit -am "Initial version" + +echo "Successfully created repository:" +echo " $(pwd)" diff --git a/agent/machine/a64/tcf/cpudefs-mdep.c b/agent/machine/a64/tcf/cpudefs-mdep.c index 8dd7a14d..5d0cca86 100644 --- a/agent/machine/a64/tcf/cpudefs-mdep.c +++ b/agent/machine/a64/tcf/cpudefs-mdep.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015-2017 Xilinx, Inc. and others. + * Copyright (c) 2015-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. @@ -28,7 +28,9 @@ #include <tcf/framework/trace.h> #include <tcf/services/symbols.h> #include <tcf/services/runctrl.h> +#include <machine/arm/tcf/disassembler-arm.h> #include <machine/a64/tcf/disassembler-a64.h> +#include <machine/arm/tcf/stack-crawl-arm.h> #include <machine/a64/tcf/stack-crawl-a64.h> #if ENABLE_ContextMux #include <tcf/framework/cpudefs-mdep-mux.h> @@ -37,36 +39,135 @@ #define REG_OFFSET(name) offsetof(REG_SET, name) -RegisterDefinition regs_def[] = { +static RegisterDefinition regs_def64[] = { { "x0", REG_OFFSET(gp.regs[0]), 8, 0, 0 }, { "sp", REG_OFFSET(gp.sp), 8, 31, 31 }, { "pc", REG_OFFSET(gp.pc), 8, 33, 33 }, { "cpsr", REG_OFFSET(gp.pstate), 8, -1, -1 }, { "orig_x0", REG_OFFSET(gp.orig_x0), 8, -1, -1 }, + { "tls", REG_OFFSET(other.tls), 8, -1, -1, 0, 0, 0, 1 }, { "vfp", 0, 0, -1, -1, 0, 0, 1, 1 }, { NULL }, }; +static RegisterDefinition regs_def32[] = { + { "r0", REG_OFFSET(other.gp32.regs[0]), 4, 0, 0 }, + { "fp", REG_OFFSET(other.gp32.regs[11]), 4, 11, 11 }, + { "ip", REG_OFFSET(other.gp32.regs[12]), 4, 12, 12 }, + { "sp", REG_OFFSET(other.gp32.regs[13]), 4, 13, 13 }, + { "lr", REG_OFFSET(other.gp32.regs[14]), 4, 14, 14 }, + { "pc", REG_OFFSET(other.gp32.regs[15]), 4, 15, 15 }, + { "cpsr", REG_OFFSET(other.gp32.cpsr), 4, 128, 128 }, + { "orig_r0", REG_OFFSET(other.gp32.orig_r0), 4, -1, -1 }, + { "tls", REG_OFFSET(other.tls), 8, -1, -1, 0, 0, 0, 1 }, + { NULL, 0, 0, 0, 0 }, +}; + +typedef struct BitFieldInfo { + const char * name; + const char * desc; + int bits[10]; +} BitFieldInfo; + +static BitFieldInfo psr_defs[] = { + { "n", "Negative condition code flag", { 31, -1 } }, + { "z", "Zero condition code flag", { 30, -1 } }, + { "c", "Carry condition code flag", { 29, -1 } }, + { "v", "Overflow condition code flag", { 28, -1 } }, + { "q", "Cumulative saturation flag", { 27, -1 } }, + { "it", "If-Then execution state bits", { 25, 26, 10, 11, 12, 13, 14, 15, -1 } }, + { "j", "Jazelle bit", { 24, -1 } }, + { "il", "Illegal Execution State bit", { 20, -1 } }, + { "ge", "SIMD Greater than or Equal flags", { 16, 17, 18, 19, -1 } }, + { "e", "Endianness execution state bit", { 9, -1 } }, + { "a", "Asynchronous abort disable bit", { 8, -1 } }, + { "i", "Interrupt disable bit", { 7, -1 } }, + { "f", "Fast interrupt disable bit", { 6, -1 } }, + { "t", "Thumb execution state bit", { 5, -1 } }, + { "m", "Mode field", { 0, 1, 2, 3, 4, -1 } }, + { NULL, NULL } +}; + RegisterDefinition * regs_index = NULL; +static RegisterDefinition * regs_index_a32 = NULL; static unsigned regs_cnt = 0; static unsigned regs_max = 0; unsigned char BREAK_INST[] = { 0x00, 0x00, 0x20, 0xd4 }; static RegisterDefinition * pc_def = NULL; +static RegisterDefinition * pc_def_a32 = NULL; + +typedef struct ContextExtensionA64 { + int is_a32_prs; +} ContextExtensionA64; + +static size_t context_extension_offset = 0; +#define EXT(ctx) ((ContextExtensionA64 *)((char *)(ctx) + context_extension_offset)) + +#ifdef MDEP_OtherRegisters + +int mdep_get_other_regs(pid_t pid, REG_SET * data, + size_t data_offs, size_t data_size, + size_t * done_offs, size_t * done_size) { + assert(data_offs >= offsetof(REG_SET, other)); + assert(data_offs + data_size <= offsetof(REG_SET, other) + sizeof(data->other)); + if (data_offs >= REG_OFFSET(other.tls) && data_offs < REG_OFFSET(other.tls) + sizeof(data->other.tls)) { + struct iovec iovec; + iovec.iov_base = &data->other.tls; + iovec.iov_len = sizeof(data->other.tls); + if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_TLS, &iovec) < 0) return -1; + *done_offs = offsetof(REG_SET, other.tls); + *done_size = sizeof(data->other.tls); + return 0; + } + if (data_offs >= REG_OFFSET(other.gp32) && data_offs < REG_OFFSET(other.gp32) + sizeof(data->other.gp32)) { + struct iovec iovec; + iovec.iov_base = &data->other.gp32; + iovec.iov_len = sizeof(data->other.gp32); + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iovec) < 0) return -1; + *done_offs = offsetof(REG_SET, other.gp32); + *done_size = sizeof(data->other.gp32); + return 0; + } + set_errno(ERR_OTHER, "Not supported"); + return -1; +} + +int mdep_set_other_regs(pid_t pid, REG_SET * data, + size_t data_offs, size_t data_size, + size_t * done_offs, size_t * done_size) { + if (data_offs >= REG_OFFSET(other.gp32) && data_offs < REG_OFFSET(other.gp32) + sizeof(data->other.gp32)) { + struct iovec iovec; + iovec.iov_base = &data->other.gp32; + iovec.iov_len = sizeof(data->other.gp32); + if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iovec) < 0) return -1; + *done_offs = offsetof(REG_SET, other.gp32); + *done_size = sizeof(data->other.gp32); + return 0; + } + set_errno(ERR_OTHER, "Not supported"); + return -1; +} + +#endif RegisterDefinition * get_PC_definition(Context * ctx) { if (!context_has_state(ctx)) return NULL; + if (is_alt_isa_thread(ctx)) return pc_def_a32; return pc_def; } int crawl_stack_frame(StackFrame * frame, StackFrame * down) { + if (is_alt_isa_thread(frame->ctx)) return crawl_stack_frame_arm(frame, down); return crawl_stack_frame_a64(frame, down); } #if defined(ENABLE_add_cpudefs_disassembler) && ENABLE_add_cpudefs_disassembler void add_cpudefs_disassembler(Context * cpu_ctx) { add_disassembler(cpu_ctx, "A64", disassemble_a64); + add_disassembler(cpu_ctx, "ARM", disassemble_arm); + add_disassembler(cpu_ctx, "Thumb", disassemble_thumb); } #endif @@ -79,12 +180,72 @@ static RegisterDefinition * alloc_reg(void) { return r; } +static void add_field(RegisterDefinition * parent, const char * name, const char * desc, int * list) { + RegisterDefinition * fld = alloc_reg(); + unsigned size = 0; + int * bits = NULL; + while (list[size] >= 0) size++; + size++; + bits = (int *)loc_alloc(sizeof(int) * size); + memcpy(bits, list, sizeof(int) * size); + fld->name = name; + fld->parent = parent; + if (desc) fld->description = desc; + if (fld->parent->no_read) fld->no_read = 1; + if (fld->parent->no_write) fld->no_write = 1; + if (fld->parent->read_once) fld->read_once = 1; + if (fld->parent->write_once) fld->write_once = 1; + fld->bits = bits; +} + +static void add_psr_fields(RegisterDefinition * psr) { + BitFieldInfo * d = psr_defs; + unsigned i = 0; + + while (d[i].name) { + add_field(psr, d[i].name, d[i].desc, d[i].bits); + i++; + } +} + static void ini_reg_defs(void) { RegisterDefinition * d; + regs_cnt = 0; - regs_max = 800; + regs_max = 100; regs_index = (RegisterDefinition *)loc_alloc_zero(sizeof(RegisterDefinition) * regs_max); - for (d = regs_def; d->name != NULL; d++) { + for (d = regs_def32; d->name != NULL; d++) { + RegisterDefinition * r = alloc_reg(); + assert(d->parent == NULL); + *r = *d; + if (strcmp(r->name, "sp") == 0) { + r->role = "SP"; + } + else if (strcmp(r->name, "pc") == 0) { + r->role = "PC"; + pc_def_a32 = r; + } + else if (strcmp(r->name, "r0") == 0) { + unsigned i; + for (i = 1; i <= 10; i++) { + r = alloc_reg(); + *r = *d; + r->name = loc_printf("r%d", i); + r->offset = d->offset + i * 4; + r->dwarf_id = d->dwarf_id + i; + r->eh_frame_id = d->eh_frame_id + i; + } + } + else if (strcmp(r->name, "cpsr") == 0) { + add_psr_fields(r); + } + } + regs_index_a32 = regs_index; + + regs_cnt = 0; + regs_max = 400; + regs_index = (RegisterDefinition *)loc_alloc_zero(sizeof(RegisterDefinition) * regs_max); + for (d = regs_def64; d->name != NULL; d++) { RegisterDefinition * r = alloc_reg(); assert(d->parent == NULL); *r = *d; @@ -98,16 +259,17 @@ static void ini_reg_defs(void) { else if (strcmp(r->name, "x0") == 0) { unsigned i; for (i = 1; i < 31; i++) { - char name[64]; r = alloc_reg(); *r = *d; - snprintf(name, sizeof(name), "x%d", i); - r->name = loc_strdup(name); + r->name = loc_printf("x%d", i); r->offset = d->offset + i * 8; r->dwarf_id = d->dwarf_id + i; r->eh_frame_id = d->eh_frame_id + i; } } + else if (strcmp(r->name, "cpsr") == 0) { + add_psr_fields(r); + } else if (strcmp(r->name, "vfp") == 0) { int n; RegisterDefinition * x = NULL; @@ -121,10 +283,8 @@ static void ini_reg_defs(void) { case 0: w->name = "64-bit"; for (i = 0; i < 64; i++) { - char nm[32]; x = alloc_reg(); - snprintf(nm, sizeof(nm), "d%d", i); - x->name = loc_strdup(nm); + x->name = loc_printf("d%d", i); x->offset = REG_OFFSET(fp.vregs) + i * 8; x->size = 8; x->fp_value = 1; @@ -134,10 +294,8 @@ static void ini_reg_defs(void) { case 1: w->name = "128-bit"; for (i = 0; i < 32; i++) { - char nm[32]; x = alloc_reg(); - snprintf(nm, sizeof(nm), "v%d", i); - x->name = loc_strdup(nm); + x->name = loc_printf("v%d", i); x->offset = REG_OFFSET(fp.vregs) + i * 16; x->size = 16; x->dwarf_id = 64 + i; @@ -162,8 +320,67 @@ static void ini_reg_defs(void) { } } +int is_alt_isa_thread(Context * ctx) { + return ctx->mem != ctx && EXT(ctx->mem)->is_a32_prs; +} + +unsigned get_arm_word_size(Context * ctx) { + return EXT(ctx->mem)->is_a32_prs ? 4 : 8; +} + +uint8_t * get_alt_break_instruction(Context * ctx, size_t * size) { + static uint8_t A32_BREAK_INST[] = { 0xf0, 0x01, 0xf0, 0xe7 }; + *size = sizeof(A32_BREAK_INST); + return A32_BREAK_INST; +} + +RegisterDefinition * get_alt_reg_definitions(Context * ctx) { + return regs_index_a32; +} + +RegisterDefinition * get_alt_reg_by_id(Context * ctx, unsigned id, RegisterIdScope * scope) { + RegisterDefinition * def = regs_index_a32; + while (def->name) { + switch (scope->id_type) { + case REGNUM_DWARF: if (def->dwarf_id == (int)id) return def; break; + case REGNUM_EH_FRAME: if (def->eh_frame_id == (int)id) return def; break; + } + def++; + } + return NULL; +} + +static void event_context_created(Context * ctx, void * args) { + if (ctx->mem == ctx) { + struct iovec iovec; + struct regset_gp gp; + iovec.iov_base = &gp; + iovec.iov_len = sizeof(gp); + if (ptrace(PTRACE_GETREGSET, id2pid(ctx->id, NULL), NT_PRSTATUS, &iovec) < 0) { + trace(LOG_ALWAYS, "Cannot detect ARM registers size: %s", errno_to_str(errno)); + } + else { + EXT(ctx)->is_a32_prs = iovec.iov_len == 18 * 4; + } + } +} + +static void event_context_exited(Context * ctx, void * args) { +} + +static ContextEventListener context_listener = { + event_context_created, + event_context_exited, + NULL, + NULL, + NULL, + NULL +}; + void ini_cpudefs_mdep(void) { ini_reg_defs(); + add_context_event_listener(&context_listener, NULL); + context_extension_offset = context_extension(sizeof(ContextExtensionA64)); } #endif diff --git a/agent/machine/a64/tcf/cpudefs-mdep.h b/agent/machine/a64/tcf/cpudefs-mdep.h index 450e00f4..911926d5 100644 --- a/agent/machine/a64/tcf/cpudefs-mdep.h +++ b/agent/machine/a64/tcf/cpudefs-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Xilinx, Inc. and others. + * Copyright (c) 2015-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. @@ -34,4 +34,18 @@ extern void ini_cpudefs_mdep(void); extern void add_cpudefs_disassembler(Context * cpu_ctx); #endif + +/*******************************************************************************/ +/* Support for AArch32 Arm and Thumb execution modes */ + +#define ENABLE_cpu_alt_isa_mode 1 + +extern int is_alt_isa_thread(Context * ctx); + +extern uint8_t * get_alt_break_instruction(Context * ctx, size_t * size); +extern RegisterDefinition * get_alt_reg_definitions(Context * ctx); +extern RegisterDefinition * get_alt_reg_by_id(Context * ctx, unsigned id, RegisterIdScope * scope); + +/*******************************************************************************/ + #endif diff --git a/agent/machine/a64/tcf/dwarfreloc-mdep.h b/agent/machine/a64/tcf/dwarfreloc-mdep.h index a1e9fe3f..8bc1db66 100644 --- a/agent/machine/a64/tcf/dwarfreloc-mdep.h +++ b/agent/machine/a64/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Xilinx, Inc. and others. + * Copyright (c) 2014-2021 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. @@ -55,7 +55,7 @@ static void elf_relocate(void) { } break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } switch (reloc_type) { @@ -87,6 +87,6 @@ static void elf_relocate(void) { *(U2_T *)data_buf = (U2_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/a64/tcf/regset-mdep.h b/agent/machine/a64/tcf/regset-mdep.h index 8b74cb50..13d57b55 100644 --- a/agent/machine/a64/tcf/regset-mdep.h +++ b/agent/machine/a64/tcf/regset-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015-2017 Xilinx, Inc. and others. + * Copyright (c) 2015-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. @@ -19,6 +19,19 @@ #if defined(__linux__) #include <elf.h> +#include <tcf/framework/mdep-ptrace.h> + +#ifndef PTRACE_GETREGSET +# define PTRACE_GETREGSET 0x4204 +#endif + +#ifndef PTRACE_SETREGSET +# define PTRACE_SETREGSET 0x4205 +#endif + +#if !defined(NT_ARM_TLS) +#define NT_ARM_TLS 0x401 +#endif #define MDEP_UseREGSET @@ -42,7 +55,23 @@ struct regset_fp { uint32_t fpcr; }; +struct regset_gp32 { + uint32_t regs[16]; + uint32_t cpsr; + uint32_t orig_r0; +}; + +struct regset_extra { + struct regset_gp32 gp32; + uint64_t tls; +}; + #define REGSET_GP NT_PRSTATUS #define REGSET_FP NT_FPREGSET +#define MDEP_OtherRegisters struct regset_extra + +extern unsigned get_arm_word_size(Context * ctx); +#define MDEP_WordSize(ctx) get_arm_word_size(ctx) + #endif diff --git a/agent/machine/a64/tcf/stack-crawl-a64.c b/agent/machine/a64/tcf/stack-crawl-a64.c index c42d5cf2..61a8596d 100644 --- a/agent/machine/a64/tcf/stack-crawl-a64.c +++ b/agent/machine/a64/tcf/stack-crawl-a64.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014-2018 Xilinx, Inc. and others. + * Copyright (c) 2014-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. @@ -56,7 +56,7 @@ typedef struct { typedef struct { uint64_t addr; - RegData reg_data[32]; + RegData reg_data[REG_DATA_SIZE]; RegData cpsr_data; RegData pc_data; MemData mem_data; @@ -95,6 +95,15 @@ typedef struct { #define MEM_CACHE_SIZE 8 static MemCache mem_cache[MEM_CACHE_SIZE]; +static int read_mem(ContextAddress address, void * buf, size_t size) { +#if ENABLE_MemoryAccessModes + static MemoryAccessMode mem_access_mode = { 0, 0, 0, 0, 0, 0, 1 }; + return context_read_mem_ext(stk_ctx, &mem_access_mode, address, buf, size); +#else + return context_read_mem(stk_ctx, address, buf, size); +#endif +} + static int read_byte(uint64_t addr, uint8_t * bt) { unsigned i = 0; MemCache * c = NULL; @@ -115,7 +124,7 @@ static int read_byte(uint64_t addr, uint8_t * bt) { c = mem_cache + mem_cache_idx; c->addr = addr; c->size = sizeof(c->data); - if (context_read_mem(stk_ctx, (ContextAddress)addr, c->data, c->size) < 0) { + if (read_mem((ContextAddress)addr, c->data, c->size) < 0) { #if ENABLE_ExtendedMemoryErrorReports int error = errno; MemoryErrorInfo info; @@ -571,6 +580,32 @@ static int branch_exception_system(void) { pc_data = reg_data[rn]; trace_return = 1; break; + case 4: + if (rn == 31) { + /* eret */ + pc_data.o = 0; + if (chk_reg_loaded(&cpsr_data) < 0) return -1; + if (cpsr_data.o) { + unsigned el = (cpsr_data.v & 0x0c) >> 2; + el_data[el].sp = reg_data[REG_ID_SP]; + pc_data = el_data[el].elr; + cpsr_data = el_data[el].spsr; + reg_data[REG_ID_SP].o = 0; + if (chk_reg_loaded(&cpsr_data) < 0) return -1; + if (cpsr_data.o) { + el = (cpsr_data.v & 0x0c) >> 2; + reg_data[REG_ID_SP] = el_data[(cpsr_data.v & 1) ? el : 0].sp; + if (cpsr_data.v & (1 << 4)) { + /* Change to AArch32 state */ + if (cpsr_data.v & (1 << 5)) pc_data.v &= ~(uint64_t)1; /* T32 or T32EE state */ + else pc_data.v &= ~(uint64_t)3; /* A32 state */ + pc_data.v &= 0xffffffff; + } + } + } + trace_return = 1; + } + break; } } return 0; @@ -1147,6 +1182,11 @@ int crawl_stack_frame_a64(StackFrame * frame, StackFrame * down) { int interrupt_handler = 0; unsigned i; + if (defs == NULL) { + set_errno(ERR_OTHER, "Context has no registers"); + return -1; + } + stk_ctx = frame->ctx; stk_frame = frame; memset(&mem_data, 0, sizeof(mem_data)); diff --git a/agent/machine/arm/tcf/cpudefs-mdep.c b/agent/machine/arm/tcf/cpudefs-mdep.c index 82528666..051631a0 100644 --- a/agent/machine/arm/tcf/cpudefs-mdep.c +++ b/agent/machine/arm/tcf/cpudefs-mdep.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013-2019 Stanislav Yakovlev and others. + * Copyright (c) 2013-2020 Stanislav Yakovlev 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. @@ -74,14 +74,40 @@ RegisterDefinition regs_def[] = { { "pc", REG_OFFSET(gp.regs[15]), 4, 15, 15}, { "cpsr", REG_OFFSET(gp.cpsr), 4, 128, 128}, { "orig_r0", REG_OFFSET(gp.orig_r0), 4, -1, -1}, + { "tls", REG_OFFSET(other.tls), 4, -1, -1, 0, 0, 0, 1 }, { "vfp", 0, 0, -1, -1, 0, 0, 1, 1 }, { NULL, 0, 0, 0, 0}, }; +typedef struct BitFieldInfo { + const char * name; + const char * desc; + int bits[10]; +} BitFieldInfo; + +static BitFieldInfo psr_defs[] = { + { "n", "Negative condition code flag",{ 31, -1 } }, + { "z", "Zero condition code flag",{ 30, -1 } }, + { "c", "Carry condition code flag",{ 29, -1 } }, + { "v", "Overflow condition code flag",{ 28, -1 } }, + { "q", "Cumulative saturation flag",{ 27, -1 } }, + { "it", "If-Then execution state bits",{ 25, 26, 10, 11, 12, 13, 14, 15, -1 } }, + { "j", "Jazelle bit",{ 24, -1 } }, + { "ge", "SIMD Greater than or Equal flags",{ 16, 17, 18, 19, -1 } }, + { "e", "Endianness execution state bit",{ 9, -1 } }, + { "a", "Asynchronous abort disable bit",{ 8, -1 } }, + { "i", "Interrupt disable bit",{ 7, -1 } }, + { "f", "Fast interrupt disable bit",{ 6, -1 } }, + { "t", "Thumb execution state bit",{ 5, -1 } }, + { "m", "Mode field",{ 0, 1, 2, 3, 4, -1 } }, + { NULL, NULL } +}; + RegisterDefinition * regs_index = NULL; static unsigned regs_cnt = 0; static unsigned regs_max = 0; +/* Note: don't use BKPT instruction - it is not supported by 32-bit Linux kernel */ unsigned char BREAK_INST[] = { 0xf0, 0x01, 0xf0, 0xe7 }; static RegisterDefinition * pc_def = NULL; @@ -143,6 +169,32 @@ RegisterDefinition * get_PC_definition(Context * ctx) { return pc_def; } +#ifdef MDEP_OtherRegisters + +int mdep_get_other_regs(pid_t pid, REG_SET * data, + size_t data_offs, size_t data_size, + size_t * done_offs, size_t * done_size) { + assert(data_offs >= offsetof(REG_SET, other)); + assert(data_offs + data_size <= offsetof(REG_SET, other) + sizeof(data->other)); + if (data_offs >= REG_OFFSET(other.tls) && data_offs < REG_OFFSET(other.tls) + sizeof(data->other.tls)) { + if (ptrace(PTRACE_GET_THREAD_AREA, pid, 0, &data->other.tls) < 0) return -1; + *done_offs = offsetof(REG_SET, other.tls); + *done_size = sizeof(data->other.tls); + return 0; + } + set_errno(ERR_OTHER, "Not supported"); + return -1; +} + +int mdep_set_other_regs(pid_t pid, REG_SET * data, + size_t data_offs, size_t data_size, + size_t * done_offs, size_t * done_size) { + set_errno(ERR_OTHER, "Not supported"); + return -1; +} + +#endif + int crawl_stack_frame(StackFrame * frame, StackFrame * down) { return crawl_stack_frame_arm(frame, down); } @@ -154,6 +206,8 @@ void add_cpudefs_disassembler(Context * cpu_ctx) { } #endif +#if ENABLE_HardwareBreakpoints + static int read_reg(Context *ctx, RegisterDefinition * def, size_t size, ContextAddress * addr) { size_t i; uint8_t buf[8]; @@ -168,8 +222,6 @@ static int read_reg(Context *ctx, RegisterDefinition * def, size_t size, Context return 0; } -#if ENABLE_HardwareBreakpoints - static void clear_bp(ContextBreakpoint * bp) { unsigned i; ContextExtensionARM * bps = EXT(bp->ctx); @@ -181,28 +233,89 @@ static void clear_bp(ContextBreakpoint * bp) { } static int get_bp_info(Context * ctx) { - uint32_t buf = 0; ContextExtensionARM * bps = EXT(ctx); - if (bps->info_ok) return 0; - if (ptrace(PTRACE_GETHBPREGS, id2pid(ctx->id, NULL), 0, &buf) < 0) { - /* Kernel does not support hardware breakpoints */ - bps->arch = 0; - bps->wp_size = 0; - bps->wp_cnt = 0; - bps->bp_cnt = 0; - bps->info_ok = 1; - return 0; + if (!bps->info_ok) { + uint32_t buf = 0; + pid_t pid = id2pid(ctx->id, NULL); + if (ptrace(PTRACE_GETHBPREGS, pid, 0, &buf) < 0) { + /* Kernel does not support hardware breakpoints */ + bps->arch = 0; + bps->wp_size = 0; + bps->wp_cnt = 0; + bps->bp_cnt = 0; + bps->info_ok = 1; + return 0; + } + bps->arch = (uint8_t)(buf >> 24); + bps->wp_size = (uint8_t)(buf >> 16); + bps->wp_cnt = (uint8_t)(buf >> 8); + bps->bp_cnt = (uint8_t)buf; + if (bps->wp_cnt > MAX_HWP) bps->wp_cnt = MAX_HWP; + if (bps->bp_cnt > MAX_HBP) bps->bp_cnt = MAX_HBP; + trace(LOG_CONTEXT, + "Breakpoints: pid %u, arch %u, wp size %u, wp count %u, bp count %u", + (unsigned)pid, bps->arch, bps->wp_size, bps->wp_cnt, bps->bp_cnt); + if (bps->arch == 0 || bps->bp_cnt == 0) { + /* Kernel does not support hardware breakpoints */ + bps->arch = 0; + bps->wp_size = 0; + bps->wp_cnt = 0; + bps->bp_cnt = 0; + bps->info_ok = 1; + return 0; + } } - bps->arch = (uint8_t)(buf >> 24); - bps->wp_size = (uint8_t)(buf >> 16); - bps->wp_cnt = (uint8_t)(buf >> 8); - bps->bp_cnt = (uint8_t)buf; - if (bps->wp_cnt > MAX_HWP) bps->wp_cnt = MAX_HWP; - if (bps->bp_cnt > MAX_HBP) bps->bp_cnt = MAX_HBP; bps->info_ok = 1; return 0; } +static int set_debug_cr(pid_t pid, ContextExtensionARM * bps, int i, uint32_t cr) { + if (cr == 0) { + /* Linux kernel does not allow 0 as Control Register value */ + cr |= 0x3 << 1; + if (i < bps->bp_cnt) { + cr |= 0x3 << 5; + } + else { + cr |= 0x1 << 5; + cr |= 0x1 << 4; + } + } + if (i < bps->bp_cnt) { + trace(LOG_CONTEXT, "Breakpoints: pid %u, set reg %d, 0x%08x", (unsigned)pid, i * 2 + 2, cr); + if (ptrace(PTRACE_SETHBPREGS, pid, i * 2 + 2, &cr) < 0) { + set_errno(errno, "Cannot set breakpoint control register"); + return -1; + } + } + else { + trace(LOG_CONTEXT, "Breakpoints: pid %u, set reg %d, 0x%08x", (unsigned)pid, -(i * 2 + 2), cr); + if (ptrace(PTRACE_SETHBPREGS, pid, -(i * 2 + 2), &cr) < 0) { + set_errno(errno, "Cannot set watchpoint control register"); + return -1; + } + } + return 0; +} + +static int set_debug_vr(pid_t pid, ContextExtensionARM * bps, int i, uint32_t vr) { + if (i < bps->bp_cnt) { + trace(LOG_CONTEXT, "Breakpoints: pid %u, set reg %d, 0x%08x", (unsigned)pid, i * 2 + 1, vr); + if (ptrace(PTRACE_SETHBPREGS, pid, i * 2 + 1, &vr) < 0) { + set_errno(errno, "Cannot set breakpoint address register"); + return -1; + } + } + else { + trace(LOG_CONTEXT, "Breakpoints: pid %u, set reg %d, 0x%08x", (unsigned)pid, -(i * 2 + 1), vr); + if (ptrace(PTRACE_SETHBPREGS, pid, -(i * 2 + 1), &vr) < 0) { + set_errno(errno, "Cannot set watchpoint address register"); + return -1; + } + } + return 0; +} + static int set_debug_regs(Context * ctx, int * step_over_hw_bp) { int i, j; ContextAddress pc = 0; @@ -218,9 +331,12 @@ static int set_debug_regs(Context * ctx, int * step_over_hw_bp) { if (read_reg(ctx, pc_def, pc_def->size, &pc) < 0) return -1; for (i = 0; i < bps->bp_cnt + bps->wp_cnt; i++) { - uint32_t cr = 0; ContextBreakpoint * cb = bps->hw_bps[i]; + + if (set_debug_cr(pid, bps, i, 0) < 0) return -1; + if (i == 0 && ext->hw_stepping) { + uint32_t cr = 0; uint32_t vr = 0; if (ext->hw_stepping == 1) { vr = (uint32_t)ext->step_addr & ~0x1; @@ -231,8 +347,9 @@ static int set_debug_regs(Context * ctx, int * step_over_hw_bp) { cr |= 0x1 << 22; cr |= 0xf << 5; } - cr |= 0x7u; - if (ptrace(PTRACE_SETHBPREGS, pid, 1, &vr) < 0) return -1; + cr |= 0x7; + if (set_debug_vr(pid, bps, 0, vr) < 0) return -1; + if (set_debug_cr(pid, bps, 0, cr) < 0) return -1; } else if (cb != NULL) { if (i < bps->bp_cnt && ((uint32_t)cb->address & ~0x1) == pc) { @@ -245,6 +362,7 @@ static int set_debug_regs(Context * ctx, int * step_over_hw_bp) { *step_over_hw_bp = 1; } else { + uint32_t cr = 0; uint32_t vr = (uint32_t)cb->address & ~0x1; if (i < bps->bp_cnt) { cr |= 0x3 << 5; @@ -260,32 +378,15 @@ static int set_debug_regs(Context * ctx, int * step_over_hw_bp) { if (cb->access_types & CTX_BP_ACCESS_DATA_WRITE) cr |= 1 << 4; } cr |= 0x7; - if (i < bps->bp_cnt) { - if (ptrace(PTRACE_SETHBPREGS, pid, i * 2 + 1, &vr) < 0) return -1; - } - else { - if (ptrace(PTRACE_SETHBPREGS, pid, -(i * 2 + 1), &vr) < 0) return -1; - } + if (set_debug_vr(pid, bps, i, vr) < 0) return -1; + if (set_debug_cr(pid, bps, i, cr) < 0) return -1; ext->armed |= 1 << i; } } - if (cr == 0) { - /* Linux kernel does not allow 0 as Control Register value */ - cr |= 0x3u << 1; - cr |= 0xfu << 5; - if (i >= bps->bp_cnt) { - cr |= 1u << 4; - } - } - if (i < bps->bp_cnt) { - if (ptrace(PTRACE_SETHBPREGS, pid, i * 2 + 2, &cr) < 0) return -1; - } - else { - if (ptrace(PTRACE_SETHBPREGS, pid, -(i * 2 + 2), &cr) < 0) return -1; - } } ext->hw_bps_regs_generation = bps->hw_bps_generation; + if (*step_over_hw_bp) ext->hw_bps_regs_generation--; return 0; } @@ -293,7 +394,7 @@ static int enable_hw_stepping_mode(Context * ctx, int mode) { int step = 0; ContextExtensionARM * ext = EXT(ctx); if (mode == 1 && arm_get_next_address(ctx, ext) < 0) return -1; - trace(LOG_CONTEXT, "enable_hw_stepping_mode %s 0x%08x", ctx->id, (unsigned)ext->step_addr); + trace(LOG_CONTEXT, "enable_hw_stepping_mode %s 0x%08x %d", ctx->id, (unsigned)ext->step_addr, mode); ext->hw_stepping = mode; return set_debug_regs(ctx, &step); } @@ -333,24 +434,16 @@ int cpu_bp_plant(ContextBreakpoint * bp) { if (bp->access_types & CTX_BP_ACCESS_VIRTUAL) { if (bp->access_types & CTX_BP_ACCESS_INSTRUCTION) { unsigned i; - unsigned n = 0; for (i = 0; i < bps->bp_cnt; i++) { assert(bps->hw_bps[i] != bp); if (bps->hw_bps[i] == NULL) { bps->hw_bps[i] = bp; bps->hw_bps_generation++; - n++; - break; + return 0; } } - if (n == 0) { - clear_bp(bp); - errno = ERR_UNSUPPORTED; - return -1; - } } if (bp->access_types & (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_DATA_WRITE)) { - unsigned n = 0; if (bp->length <= bps->wp_size) { unsigned i; for (i = bps->bp_cnt; i < bps->bp_cnt + bps->wp_cnt; i++) { @@ -358,19 +451,13 @@ int cpu_bp_plant(ContextBreakpoint * bp) { if (bps->hw_bps[i] == NULL) { bps->hw_bps[i] = bp; bps->hw_bps_generation++; - n++; - break; + return 0; } } } - if (n == 0) { - clear_bp(bp); - errno = ERR_UNSUPPORTED; - return -1; - } } - return 0; } + clear_bp(bp); errno = ERR_UNSUPPORTED; return -1; } @@ -417,6 +504,7 @@ int cpu_bp_on_suspend(Context * ctx, int * triggered) { if (bps->wp_cnt > 0) { siginfo_t siginfo; pid_t pid = id2pid(ctx->id, NULL); + memset(&siginfo, 0, sizeof(siginfo)); if (ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo) < 0) return -1; if (siginfo.si_signo == SIGTRAP && (siginfo.si_code & 0xffff) == 0x0004 && siginfo.si_errno < 0) { /* Watchpoint */ @@ -491,7 +579,7 @@ static int arm_evaluate_condition(uint32_t cond) { case 5 : return N == 0; case 6 : return V; case 7 : return V == 0; - case 8 : return C == 0 && Z == 0; + case 8 : return C == 1 && Z == 0; case 9 : return C == 0 || Z == 1; case 10: return N == V; case 11: return N != V; @@ -712,7 +800,7 @@ static int arm_get_next_data_processing(void) { return 0; } -static int arm_get_next_ldr(void) { +static int arm_get_next_ldr(int * to_thumb) { int I = (arm_instr & (1 << 25)) != 0; int P = (arm_instr & (1 << 24)) != 0; int U = (arm_instr & (1 << 23)) != 0; @@ -759,6 +847,16 @@ static int arm_get_next_ldr(void) { if (arm_read_mem(addr, &arm_next, 4) < 0) return -1; break; } + + if (arm_next & 1) { + arm_next &= ~(uint32_t)1; + *to_thumb = 1; + } + else { + arm_next &= ~(uint32_t)3; + *to_thumb = 0; + } + return 0; } @@ -852,7 +950,7 @@ static int thumb_get_next_cbz(void) { if (N ^ (reg == 0)) { uint32_t offs = (arm_instr >> 3) & 0x1f; if (arm_instr & (1 << 9)) offs |= 0x20; - arm_next = arm_pc + (offs << 1); + arm_next = arm_pc + (offs << 1) + 4; } return 0; } @@ -862,7 +960,9 @@ static int thumb_get_next_bc(int * to_thumb) { int J2 = (arm_instr & (1 << 11)) != 0; int S = (arm_instr & (1 << 26)) != 0; if ((arm_instr & 0xf800d000) == 0xf0008000) { - if (arm_evaluate_condition((arm_instr >> 22) & 0xf)) { + uint32_t c = (arm_instr >> 22) & 0xf; + if ((c >> 1) == 7) return 0; + if (arm_evaluate_condition(c)) { uint32_t offs = arm_instr & 0x7ff; offs |= ((arm_instr >> 16) & 0x3f) << 11; if (J1) offs |= 1 << 17; @@ -886,7 +986,7 @@ static int thumb_get_next_bc(int * to_thumb) { return 0; } -static int thumb_get_next_ldr(void) { +static int thumb_get_next_ldr(int * to_thumb) { uint32_t Rn = (arm_instr >> 16) & 0xf; uint32_t Rt = (arm_instr >> 12) & 0xf; if (Rt == 15) { @@ -897,6 +997,14 @@ static int thumb_get_next_ldr(void) { if (arm_read_reg(Rn, &addr) < 0) return -1; if (P) addr = U ? addr + imm32 : addr - imm32; if (arm_read_mem(addr, &arm_next, 4) < 0) return -1; + if (arm_next & 1) { + arm_next &= ~(uint32_t)1; + *to_thumb = 1; + } + else { + arm_next &= ~(uint32_t)3; + *to_thumb = 0; + } } return 0; } @@ -958,7 +1066,7 @@ static int arm_get_next_address(Context * ctx, ContextExtensionARM * ext) { break; case 2: case 3: /* Load */ - if (arm_get_next_ldr() < 0) return -1; + if (arm_get_next_ldr(&to_thumb) < 0) return -1; break; case 4: /* Load/store multiple */ if (arm_get_next_ldm(&to_thumb) < 0) return -1; @@ -971,11 +1079,12 @@ static int arm_get_next_address(Context * ctx, ContextExtensionARM * ext) { } else { /* Thumb mode */ + uint32_t it = ((arm_cpsr >> 25) & 0x3) | ((arm_cpsr >> 8) & 0xfc); to_thumb = 1; if (((arm_instr >> 11) & 0x1f) >= 0x1d) { arm_next = arm_pc + 4; arm_instr = (arm_instr << 16) | (arm_instr >> 16); - if ((arm_instr & 0xfe000000) == 0xe8000000) { + if ((arm_instr & 0xfe400000) == 0xe8000000) { /* Load/store multiple */ if (arm_get_next_ldm(&to_thumb) < 0) return -1; } @@ -985,7 +1094,7 @@ static int arm_get_next_address(Context * ctx, ContextExtensionARM * ext) { } else if ((arm_instr & 0xff700000) == 0xf8500000) { /* Load word */ - if (thumb_get_next_ldr() < 0) return -1; + if (thumb_get_next_ldr(&to_thumb) < 0) return -1; } else if ((arm_instr & 0xfff000e0) == 0xe8d00000) { /* Table Branch */ @@ -999,11 +1108,14 @@ static int arm_get_next_address(Context * ctx, ContextExtensionARM * ext) { if (thumb_get_next_pop(&to_thumb) < 0) return -1; } else if ((arm_instr & 0xf000) == 0xd000) { - /* Conditional branch */ - if (arm_evaluate_condition((arm_instr >> 8) & 0xf)) { - uint32_t offs = (arm_instr & 0xff) << 1; - if (offs & 0x100) offs |= 0xfffffe00; - arm_next = arm_pc + offs + 4; + uint32_t c = (arm_instr >> 4) & 0x000f; + if (c != 0xf) { + /* Conditional branch */ + if (arm_evaluate_condition((arm_instr >> 8) & 0xf)) { + uint32_t offs = (arm_instr & 0xff) << 1; + if (offs & 0x100) offs |= 0xfffffe00; + arm_next = arm_pc + offs + 4; + } } } else if ((arm_instr & 0xf800) == 0xe000) { @@ -1024,6 +1136,53 @@ static int arm_get_next_address(Context * ctx, ContextExtensionARM * ext) { /* cbnz, cbz */ if (thumb_get_next_cbz() < 0) return -1; } + else if ((arm_instr & 0xff00) == 0xbf00) { + /* it */ + unsigned n = 0; + uint32_t m = arm_instr & 0x000f; + uint32_t c = (arm_instr >> 4) & 0x000f; + while ((m << n) & 0xf) { + uint32_t skip_instr = 0; + if (n == 0) { + if (arm_evaluate_condition(c)) break; + } + else if (m & (1 << (4 - n))) { + if (arm_evaluate_condition(c | 1u)) break; + } + else { + if (arm_evaluate_condition(c & ~1u)) break; + } + if (arm_read_mem(arm_next, &skip_instr, 4) < 0) return -1; + if (((skip_instr >> 11) & 0x1f) >= 0x1d) { + /* 32-bit instruction */ + arm_next += 4; + } + else { + /* 16-bit instruction */ + arm_next += 2; + } + n++; + } + } + } + if (it) { + /* If-Then execution state */ + it = (it & 0xe0) | ((it & 0x0f) << 1); + while (it & 0xf) { + uint32_t skip_instr = 0; + uint32_t c = (it >> 4) & 0x0f; + if (arm_evaluate_condition(c)) break; + if (arm_read_mem(arm_next, &skip_instr, 4) < 0) return -1; + if (((skip_instr >> 11) & 0x1f) >= 0x1d) { + /* 32-bit instruction */ + arm_next += 4; + } + else { + /* 16-bit instruction */ + arm_next += 2; + } + it = (it & 0xe0) | ((it & 0x0f) << 1); + } } } @@ -1040,7 +1199,7 @@ static int arm_get_next_address(Context * ctx, ContextExtensionARM * ext) { } } - ext->step_to_thumb = to_thumb; + ext->step_to_thumb = to_thumb || (arm_next & 2) != 0; ext->step_addr = arm_next; return 0; } @@ -1051,17 +1210,28 @@ static int enable_sw_stepping_mode(Context * ctx) { assert(!grp->exited); assert(!ext->sw_stepping); if (arm_get_next_address(ctx, ext) < 0) return -1; - trace(LOG_CONTEXT, "enable_sw_stepping_mode %s 0x%08x", ctx->id, (unsigned)ext->step_addr); + trace(LOG_CONTEXT, "enable_sw_stepping_mode %s 0x%08x %d", ctx->id, (unsigned)ext->step_addr, ext->step_to_thumb); if (ext->step_to_thumb) { - static uint8_t bp_thumb[] = { 0x00, 0xbe }; +#if defined(__aarch64__) + static uint8_t bp_thumb[] = { 0x70, 0xbe }; +#else + /* Note: don't use BKPT instruction - it is not supported by 32-bit Linux kernel */ + static uint8_t bp_thumb[] = { 0x01, 0xde }; +#endif ext->opcode_size = sizeof(bp_thumb); if (context_read_mem(grp, ext->step_addr, ext->opcode, ext->opcode_size) < 0) return -1; if (context_write_mem(grp, ext->step_addr, bp_thumb, ext->opcode_size) < 0) return -1; } else { - ext->opcode_size = sizeof(BREAK_INST); +#if defined(__aarch64__) + static uint8_t bp_arm[] = { 0x70, 0xbe, 0x20, 0xe1 }; +#else + /* Note: don't use BKPT instruction - it is not supported by 32-bit Linux kernel */ + static uint8_t bp_arm[] = { 0xf0, 0x01, 0xf0, 0xe7 }; +#endif + ext->opcode_size = sizeof(bp_arm); if (context_read_mem(grp, ext->step_addr, ext->opcode, ext->opcode_size) < 0) return -1; - if (context_write_mem(grp, ext->step_addr, BREAK_INST, ext->opcode_size) < 0) return -1; + if (context_write_mem(grp, ext->step_addr, bp_arm, ext->opcode_size) < 0) return -1; } ext->sw_stepping = 1; run_ctrl_lock(); @@ -1130,6 +1300,34 @@ static RegisterDefinition * alloc_reg(void) { # endif #endif +static void add_field(RegisterDefinition * parent, const char * name, const char * desc, int * list) { + RegisterDefinition * fld = alloc_reg(); + unsigned size = 0; + int * bits = NULL; + while (list[size] >= 0) size++; + size++; + bits = (int *)loc_alloc(sizeof(int) * size); + memcpy(bits, list, sizeof(int) * size); + fld->name = name; + fld->parent = parent; + if (desc) fld->description = desc; + if (fld->parent->no_read) fld->no_read = 1; + if (fld->parent->no_write) fld->no_write = 1; + if (fld->parent->read_once) fld->read_once = 1; + if (fld->parent->write_once) fld->write_once = 1; + fld->bits = bits; +} + +static void add_psr_fields(RegisterDefinition * psr) { + BitFieldInfo * d = psr_defs; + unsigned i = 0; + + while (d[i].name) { + add_field(psr, d[i].name, d[i].desc, d[i].bits); + i++; + } +} + static void ini_reg_defs(void) { int i; RegisterDefinition * d; @@ -1157,6 +1355,9 @@ static void ini_reg_defs(void) { else if (r->offset == offsetof(REG_SET, REG_CPSR)) { cpsr_def = r; } + if (strcmp(r->name, "cpsr") == 0) { + add_psr_fields(r); + } if (strcmp(r->name, "vfp") == 0) { uint32_t fpsid = 0; #if USE_getauxval diff --git a/agent/machine/arm/tcf/disassembler-arm.c b/agent/machine/arm/tcf/disassembler-arm.c index 7b88e217..41cba939 100644 --- a/agent/machine/arm/tcf/disassembler-arm.c +++ b/agent/machine/arm/tcf/disassembler-arm.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2017 Xilinx, Inc. and others. + * Copyright (c) 2013-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. @@ -2191,7 +2191,7 @@ static void disassemble_data_instr(uint32_t instr, const char * cond, uint32_t a add_char(' '); add_reg_name(rd); add_str(", "); - add_modifed_immediate_address(instr & 0x00000fff, addr, add, 4); + add_modifed_immediate_address(instr & 0x00000fff, addr + 8, add, 4); return; } @@ -2926,6 +2926,18 @@ static void disassemble_media_instr(uint32_t instr, const char * cond) { } return; } + + if ((instr & 0x0fd000f0) == 0x07100010) { + add_str(instr & (1 << 21) ? "udiv" : "sdiv"); + add_str(cond); + add_char(' '); + add_reg_name((instr >> 16) & 0xf); + add_str(", "); + add_reg_name(instr & 0xf); + add_str(", "); + add_reg_name((instr >> 8) & 0xf); + return; + } } static void disassemble_load_store_instr(uint32_t instr, const char * cond) { @@ -3053,20 +3065,15 @@ static void disassemble_supervisor_and_ext_load_store(uint32_t instr, const char } } -DisassemblyResult * disassemble_arm(uint8_t * code, - ContextAddress addr, ContextAddress size, DisassemblerParams * params) { - unsigned i; - uint32_t instr = 0; +static DisassemblyResult * disassemble_instr(ContextAddress addr, uint32_t instr) { uint8_t cond = 0; const char * cond_name = NULL; static DisassemblyResult dr; - if (size < 4) return NULL; memset(&dr, 0, sizeof(dr)); dr.size = 4; buf_pos = 0; - ctx = params->ctx; - for (i = 0; i < 4; i++) instr |= (uint32_t)*code++ << (i * 8); + cond = (instr >> 28) & 0xf; cond_name = cond_names[cond]; @@ -3097,4 +3104,26 @@ DisassemblyResult * disassemble_arm(uint8_t * code, return &dr; } +DisassemblyResult * disassemble_arm(uint8_t * code, + ContextAddress addr, ContextAddress size, DisassemblerParams * params) { + unsigned i; + uint32_t instr = 0; + + ctx = params->ctx; + if (size < 4) return NULL; + for (i = 0; i < 4; i++) instr |= (uint32_t)*code++ << (i * 8); + return disassemble_instr(addr, instr); +} + +DisassemblyResult * disassemble_arm_big_endian_code(uint8_t * code, + ContextAddress addr, ContextAddress size, DisassemblerParams * params) { + unsigned i; + uint32_t instr = 0; + + ctx = params->ctx; + if (size < 4) return NULL; + for (i = 0; i < 4; i++) instr |= (uint32_t)*code++ << ((3 - i) * 8); + return disassemble_instr(addr, instr); +} + #endif /* SERVICE_Disassembly */ diff --git a/agent/machine/arm/tcf/disassembler-arm.h b/agent/machine/arm/tcf/disassembler-arm.h index 2e8ed7b9..21d38d85 100644 --- a/agent/machine/arm/tcf/disassembler-arm.h +++ b/agent/machine/arm/tcf/disassembler-arm.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 Xilinx, Inc. and others. + * Copyright (c) 2013-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. @@ -23,7 +23,13 @@ extern DisassemblyResult * disassemble_arm(uint8_t * buf, ContextAddress addr, ContextAddress size, DisassemblerParams * params); +extern DisassemblyResult * disassemble_arm_big_endian_code(uint8_t * buf, + ContextAddress addr, ContextAddress size, DisassemblerParams * params); + extern DisassemblyResult * disassemble_thumb(uint8_t * buf, ContextAddress addr, ContextAddress size, DisassemblerParams * params); +extern DisassemblyResult * disassemble_thumb_big_endian_code(uint8_t * buf, + ContextAddress addr, ContextAddress size, DisassemblerParams * params); + #endif /* D_disassembler_arm */ diff --git a/agent/machine/arm/tcf/disassembler-thumb.c b/agent/machine/arm/tcf/disassembler-thumb.c index 583492e8..82fcf1fb 100644 --- a/agent/machine/arm/tcf/disassembler-thumb.c +++ b/agent/machine/arm/tcf/disassembler-thumb.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2016 Xilinx, Inc. and others. + * Copyright (c) 2013-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. @@ -25,9 +25,9 @@ static char buf[128]; static size_t buf_pos = 0; +static int code_be = 0; static uint16_t instr = 0; static uint32_t instr_addr = 0; -static uint8_t * instr_code = NULL; static ContextAddress instr_size = 0; static const char * it_cond_name = NULL; static unsigned it_cnt = 0; @@ -1544,7 +1544,7 @@ static void disassemble_long_multiply_32(uint16_t suffix) { } } -static void disassemble_thumb7(void) { +static void disassemble_thumb7(uint8_t * code) { unsigned i; uint16_t suffix = 0; @@ -1561,7 +1561,7 @@ static void disassemble_thumb7(void) { } instr_size = 4; - for (i = 0; i < 2; i++) suffix |= (uint16_t)*instr_code++ << (i * 8); + for (i = 0; i < 2; i++) suffix |= (uint16_t)*code++ << ((code_be ? 1 - i : i) * 8); if ((instr & 0xfe00) == 0xe800) { disassemble_load_store_32(suffix); @@ -1724,7 +1724,7 @@ static DisassemblyResult * disassemble_arm_ti(uint8_t * code, ContextAddress add return dr; } -DisassemblyResult * disassemble_thumb(uint8_t * code, +static DisassemblyResult * disassemble_thumb_any(uint8_t * code, ContextAddress addr, ContextAddress size, DisassemblerParams * prm) { unsigned i; static DisassemblyResult dr; @@ -1732,13 +1732,12 @@ DisassemblyResult * disassemble_thumb(uint8_t * code, if (size < 2) return NULL; instr = 0; - for (i = 0; i < 2; i++) instr |= (uint16_t)code[i] << (i * 8); + for (i = 0; i < 2; i++) instr |= (uint16_t)code[i] << ((code_be ? 1 - i : i) * 8); memset(&dr, 0, sizeof(dr)); params = prm; instr_size = 2; instr_addr = (uint32_t)addr; - instr_code = code + 2; buf_pos = 0; it_cond_name = NULL; @@ -1759,10 +1758,18 @@ DisassemblyResult * disassemble_thumb(uint8_t * code, if ((instr & 0xec00) == 0xec00 && size >= 4) { /* Coprocessor instructions - same as ARM encoding */ uint8_t tmp[4]; - tmp[2] = code[0]; - tmp[3] = code[1]; - tmp[0] = code[2]; - tmp[1] = code[3]; + if (code_be) { + tmp[2] = code[1]; + tmp[3] = code[0]; + tmp[0] = code[3]; + tmp[1] = code[2]; + } + else { + tmp[2] = code[0]; + tmp[3] = code[1]; + tmp[0] = code[2]; + tmp[1] = code[3]; + } if ((instr & 0xef00) == 0xef00) { /* Advanced SIMD data-processing instructions */ tmp[3] = 0xf2 | ((instr >> 12) & 1); @@ -1773,10 +1780,18 @@ DisassemblyResult * disassemble_thumb(uint8_t * code, if ((instr & 0xff10) == 0xf900 && size >= 4) { /* Advanced SIMD element or structure load/store instructions */ uint8_t tmp[4]; - tmp[2] = code[0]; - tmp[3] = 0xf4; - tmp[0] = code[2]; - tmp[1] = code[3]; + if (code_be) { + tmp[2] = code[1]; + tmp[3] = 0xf4; + tmp[0] = code[3]; + tmp[1] = code[2]; + } + else { + tmp[2] = code[0]; + tmp[3] = 0xf4; + tmp[0] = code[2]; + tmp[1] = code[3]; + } return disassemble_arm_ti(tmp, addr, 4); } @@ -1788,7 +1803,7 @@ DisassemblyResult * disassemble_thumb(uint8_t * code, case 4: disassemble_thumb4(); break; case 5: disassemble_thumb5(); break; case 6: disassemble_thumb6(); break; - case 7: disassemble_thumb7(); break; + case 7: disassemble_thumb7(code + 2); break; } dr.text = buf; @@ -1800,7 +1815,7 @@ DisassemblyResult * disassemble_thumb(uint8_t * code, } else if (dr.size == 4) { uint16_t suffix = 0; - for (i = 0; i < 2; i++) suffix |= (uint16_t)code[i + 2] << (i * 8); + for (i = 0; i < 2; i++) suffix |= (uint16_t)code[i + 2] << ((code_be ? 1 - i : i) * 8); snprintf(buf, sizeof(buf), ".word 0x%04x%04x", instr, suffix); } else { @@ -1813,4 +1828,16 @@ DisassemblyResult * disassemble_thumb(uint8_t * code, return &dr; } +DisassemblyResult * disassemble_thumb(uint8_t * code, + ContextAddress addr, ContextAddress size, DisassemblerParams * prm) { + code_be = 0; + return disassemble_thumb_any(code, addr, size, prm); +} + +DisassemblyResult * disassemble_thumb_big_endian_code(uint8_t * code, + ContextAddress addr, ContextAddress size, DisassemblerParams * prm) { + code_be = 1; + return disassemble_thumb_any(code, addr, size, prm); +} + #endif /* SERVICE_Disassembly */ diff --git a/agent/machine/arm/tcf/dwarfreloc-mdep.h b/agent/machine/arm/tcf/dwarfreloc-mdep.h index 54775a7a..582ee9c8 100644 --- a/agent/machine/arm/tcf/dwarfreloc-mdep.h +++ b/agent/machine/arm/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2014 Xilinx, Inc. and others. + * Copyright (c) 2013-2021 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. @@ -45,7 +45,7 @@ static void elf_relocate(void) { } break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } switch (reloc_type) { @@ -66,6 +66,6 @@ static void elf_relocate(void) { *(U2_T *)data_buf = (U2_T)(sym_value + reloc_addend); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/arm/tcf/regset-mdep.h b/agent/machine/arm/tcf/regset-mdep.h index c4014922..9cb3f33e 100644 --- a/agent/machine/arm/tcf/regset-mdep.h +++ b/agent/machine/arm/tcf/regset-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013-2018 Stanislav Yakovlev and others. + * Copyright (c) 2013-2019 Stanislav Yakovlev 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. @@ -20,6 +20,7 @@ #if defined(__linux__) #include <elf.h> +#include <tcf/framework/mdep-ptrace.h> #define MDEP_UseREGSET @@ -35,6 +36,10 @@ # define PTRACE_SETREGSET 0x4205 #endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 22 +#endif + struct regset_gp { uint32_t regs[16]; uint32_t cpsr; @@ -46,7 +51,13 @@ struct regset_fp { uint32_t fpscr; }; +struct regset_extra { + uint64_t tls; +}; + #define REGSET_GP NT_PRSTATUS #define REGSET_FP NT_ARM_VFP +#define MDEP_OtherRegisters struct regset_extra + #endif diff --git a/agent/machine/arm/tcf/stack-crawl-arm-ext.h b/agent/machine/arm/tcf/stack-crawl-arm-ext.h index 9b024fb5..a11790bc 100644 --- a/agent/machine/arm/tcf/stack-crawl-arm-ext.h +++ b/agent/machine/arm/tcf/stack-crawl-arm-ext.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Wind River + * Copyright (c) 2015-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. diff --git a/agent/machine/arm/tcf/stack-crawl-arm.c b/agent/machine/arm/tcf/stack-crawl-arm.c index 2842ea94..d14abae9 100644 --- a/agent/machine/arm/tcf/stack-crawl-arm.c +++ b/agent/machine/arm/tcf/stack-crawl-arm.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013-2019 Xilinx, Inc. and others. + * Copyright (c) 2013-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. @@ -81,6 +81,8 @@ typedef struct { #define CPU_ARMv7M 3 #define CPU_ARM32 4 +enum ISA_TYPE { ISA_ARM, ISA_THUMB, ISA_JAZELLE }; + static unsigned cpu_type = 0; static Context * stk_ctx = NULL; static StackFrame * stk_frame = NULL; @@ -108,6 +110,15 @@ static MemCache mem_cache[MEM_CACHE_SIZE]; /* Extension can access static variables and static functions */ #include <machine/arm/tcf/stack-crawl-arm-ext.h> +static int read_mem(ContextAddress address, void * buf, size_t size) { +#if ENABLE_MemoryAccessModes + static MemoryAccessMode mem_access_mode = { 0, 0, 0, 0, 0, 0, 1 }; + return context_read_mem_ext(stk_ctx, &mem_access_mode, address, buf, size); +#else + return context_read_mem(stk_ctx, address, buf, size); +#endif +} + static int read_byte(uint32_t addr, uint8_t * bt) { unsigned i = 0; MemCache * c = NULL; @@ -128,7 +139,7 @@ static int read_byte(uint32_t addr, uint8_t * bt) { c = mem_cache + mem_cache_idx; c->addr = addr; c->size = sizeof(c->data); - if (context_read_mem(stk_ctx, addr, c->data, c->size) < 0) { + if (read_mem(addr, c->data, c->size) < 0) { #if ENABLE_ExtendedMemoryErrorReports int error = errno; MemoryErrorInfo info; @@ -179,7 +190,7 @@ static int read_half(uint32_t addr, uint16_t * h) { errno = ERR_INV_ADDRESS; return -1; } - if (context_read_mem(stk_ctx, addr, buf, 2) < 0) return -1; + if (read_mem(addr, buf, 2) < 0) return -1; *h = (uint32_t)buf[0] | (buf[1] << 8); return 0; } @@ -190,7 +201,7 @@ static int read_word(uint32_t addr, uint32_t * w) { errno = ERR_INV_ADDRESS; return -1; } - if (context_read_mem(stk_ctx, addr, buf, 4) < 0) return -1; + if (read_mem(addr, buf, 4) < 0) return -1; *w = (uint32_t)buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); return 0; } @@ -2267,6 +2278,18 @@ static int trace_arm(void) { return 0; } +static enum ISA_TYPE get_isa_type(void) { + uint32_t flag_t = 1 << 5; + uint32_t flag_j = 1 << 24; + if (cpu_type == CPU_ARMv7M) { + flag_t = 1 << 24; + flag_j = 0; + } + if (reg_data[REG_ID_CPSR].v & flag_j) return ISA_JAZELLE; + if (reg_data[REG_ID_CPSR].v & flag_t) return ISA_THUMB; + return ISA_ARM; +} + static int trace_instructions(void) { unsigned i; RegData org_sp = reg_data[13]; @@ -2325,6 +2348,9 @@ static int trace_instructions(void) { else if (!reg_data[15].v) { error = set_errno(ERR_OTHER, "PC == 0"); } + else if (chk_loaded(REG_ID_CPSR) < 0) { + error = errno; + } else if (!reg_data[REG_ID_CPSR].o) { error = set_errno(ERR_OTHER, "CPSR value not available"); } @@ -2334,18 +2360,20 @@ static int trace_instructions(void) { } else { int r = 0; - uint32_t flag_t = 1 << 5; - uint32_t flag_j = 1 << 24; - if (cpu_type == CPU_ARMv7M) { - flag_t = 1 << 24; - flag_j = 0; + switch (get_isa_type()) { + case ISA_JAZELLE: r = trace_jazelle(); break; + case ISA_THUMB: r = trace_thumb(); break; + default: r = trace_arm(); break; } - if (reg_data[REG_ID_CPSR].v & flag_j) r = trace_jazelle(); - else if (reg_data[REG_ID_CPSR].v & flag_t) r = trace_thumb(); - else r = trace_arm(); if (r < 0) error = errno; } if (!error && trace_return) { + if (reg_data[15].o && reg_data[15].v == 0 && + (cpu_type == CPU_ARMv7M || (chk_loaded(14) == 0 && reg_data[14].o && (reg_data[14].v & ~(uint32_t)1) == 0))) { + /* Empty frame, assuming stack bottom, stop stack trace */ + memset(®_data, 0, sizeof(reg_data)); + return 0; + } if (chk_loaded(13) < 0 || !reg_data[13].o) { error = set_errno(ERR_OTHER, "Stack crawl: invalid SP value"); } @@ -2378,33 +2406,64 @@ static int trace_instructions(void) { EPILOGUE_NOT_FOUND_HOOK; - if (func_size > 12 && (func_addr & 0x3) == 0) { - unsigned n = 0; + reg_data[REG_ID_CPSR] = org_cpsr; + if (func_size > 12 && (func_addr & 0x3) == 0 && chk_loaded(REG_ID_CPSR) == 0 && reg_data[REG_ID_CPSR].o) { /* Check for common ARM prologue pattern */ - while (n < 3 && n < func_size / 4 - 1) { + unsigned n = 0; + while (n < 16 && n < func_size - 1) { uint32_t instr = 0; uint32_t push_regs = 0; - if (read_word(func_addr + n * 4, &instr) < 0) break; - if ((instr & 0xffffe000) == 0xe92d4000) { - /* PUSH {..., lr} */ - push_regs = instr & 0xffff; + if (read_word(func_addr + n, &instr) < 0) break; + if (get_isa_type() == ISA_ARM) { + if ((instr & 0xffffe000) == 0xe92d4000) { + /* PUSH {..., lr} */ + push_regs = instr & 0xffff; + } + else if ((instr & 0xffffffff) == 0xe52de004) { + /* PUSH {lr} */ + push_regs |= 1 << 14; + } + n += 4; + } + else if (get_isa_type() == ISA_THUMB) { + if ((instr & 0xfe00) == 0xb400) { + push_regs = instr & 0xff; + if (instr & (1 << 8)) push_regs |= 1 << 14; + } + if (((instr & 0xffff) >> 11) >= 0x1d) { + n += 4; + } + else { + n += 2; + } } - else if ((instr & 0xffffffff) == 0xe52de004) { - /* PUSH {lr} */ - push_regs |= 1 << 14; + else { + break; } if (push_regs) { reg_data[13] = org_sp; if (chk_loaded(13) == 0) { uint32_t addr = reg_data[13].v; - while (n < 8 && n < func_size / 4 - 1) { - if (read_word(func_addr + n * 4, &instr) < 0) break; - if ((instr & 0xfffff000) == 0xe24dd000) { - /* SUB sp, sp, #... */ - addr += modified_immediate_constant(instr); + while (n < 32 && n < func_size - 1) { + if (read_word(func_addr + n, &instr) < 0) break; + if (get_isa_type() == ISA_ARM) { + if ((instr & 0xfffff000) == 0xe24dd000) { + /* SUB sp, sp, #... */ + addr += modified_immediate_constant(instr); + break; + } + n += 4; + } + else if (get_isa_type() == ISA_THUMB) { + if ((instr & 0xff80) == 0xb080) { + /* SUB sp, #... */ + addr += (instr & 0x7f) << 2; + } + break; + } + else { break; } - n++; } for (i = 0; i < 16; i++) { if (push_regs & (1 << i)) { @@ -2428,7 +2487,6 @@ static int trace_instructions(void) { } break; } - n++; } } @@ -2448,10 +2506,13 @@ static int trace_instructions(void) { bx_write_pc(); return 0; } - if (org_sp.v != 0 && org_lr.v != 0 && org_pc.v != org_lr.v) { - reg_data[13] = org_sp; - reg_data[15] = org_lr; - bx_write_pc(); + if (org_sp.v != 0) { + uint32_t ret_addr = org_lr.v & ~(uint32_t)1; + if (ret_addr != 0 && org_pc.v != ret_addr) { + reg_data[13] = org_sp; + reg_data[15] = org_lr; + bx_write_pc(); + } } return 0; } @@ -2466,6 +2527,11 @@ static int trace_frame(StackFrame * frame, StackFrame * down) { for (i = 0; i < MEM_CACHE_SIZE; i++) mem_cache[i].size = 0; #endif + if (defs == NULL) { + set_errno(ERR_OTHER, "Context has no registers"); + return -1; + } + stk_ctx = frame->ctx; stk_frame = frame; memset(®_data, 0, sizeof(reg_data)); @@ -2474,7 +2540,7 @@ static int trace_frame(StackFrame * frame, StackFrame * down) { branch_cnt = 0; for (def = defs; def->name; def++) { - if (def->dwarf_id >= 13 && def->dwarf_id <= 15) { + if ((def->dwarf_id >= 13 && def->dwarf_id <= 15) || def->dwarf_id == REG_ID_CPSR) { uint64_t v = 0; if (read_reg_value(frame, def, &v) < 0) continue; reg_data[def->dwarf_id].v = (uint32_t)v; @@ -2486,8 +2552,22 @@ static int trace_frame(StackFrame * frame, StackFrame * down) { } } + if (cpu_type == CPU_ARM32 && reg_data[15].o && reg_data[REG_ID_CPSR].o) { + const char * isa = NULL; + ContextAddress addr = 0; + ContextAddress size = 0; + assert(reg_data[15].o == REG_VAL_OTHER); + assert(reg_data[REG_ID_CPSR].o == REG_VAL_OTHER); + if (get_context_isa(stk_ctx, reg_data[15].v, &isa, &addr, &size) == 0 && isa != NULL) { + if (strcmp(isa, "ARM") == 0) reg_data[REG_ID_CPSR].v &= ~(1 << 5); + if (strcmp(isa, "Thumb") == 0) reg_data[REG_ID_CPSR].v |= (1 << 5); + } + } + spsr_id = get_spsr_id(); - if ((spsr_id == 0 || reg_data[spsr_id].o == 0) && reg_data[13].v == 0) return 0; + if (spsr_id == 0 || reg_data[spsr_id].o == 0 || reg_data[14].o == 0 || reg_data[14].v == 0) { + if (reg_data[13].v == 0) return 0; + } if (trace_instructions() < 0) return -1; diff --git a/agent/machine/i386/tcf/cpu-regs-gdb.h b/agent/machine/i386/tcf/cpu-regs-gdb.h index d5fa9b87..02d4a372 100644 --- a/agent/machine/i386/tcf/cpu-regs-gdb.h +++ b/agent/machine/i386/tcf/cpu-regs-gdb.h @@ -45,8 +45,8 @@ static const char * cpu_regs_gdb_i386 = " <reg name='st5' bitsize='80' type='i387_ext'/>\n" " <reg name='st6' bitsize='80' type='i387_ext'/>\n" " <reg name='st7' bitsize='80' type='i387_ext'/>\n" -" <reg name='fctrl' bitsize='32' type='int' group='float' id='65'/>\n" -" <reg name='fstat' bitsize='32' type='int' group='float' id='66'/>\n" +" <reg name='fctrl' bitsize='32' type='int' group='float'/>\n" +" <reg name='fstat' bitsize='32' type='int' group='float'/>\n" " <reg name='ftag' bitsize='32' type='int' group='float'/>\n" " <reg name='fiseg' bitsize='32' type='int' group='float'/>\n" " <reg name='fioff' bitsize='32' type='int' group='float'/>\n" diff --git a/agent/machine/i386/tcf/dwarfreloc-mdep.h b/agent/machine/i386/tcf/dwarfreloc-mdep.h index 5cd90f66..5fa70067 100644 --- a/agent/machine/i386/tcf/dwarfreloc-mdep.h +++ b/agent/machine/i386/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2014 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. @@ -42,6 +42,6 @@ static void elf_relocate(void) { *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/i386/tcf/regset-mdep.h b/agent/machine/i386/tcf/regset-mdep.h index 78fecda0..84841618 100644 --- a/agent/machine/i386/tcf/regset-mdep.h +++ b/agent/machine/i386/tcf/regset-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2017 Wind River Systems, Inc. and others. + * Copyright (c) 2012-2019 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. @@ -13,5 +13,38 @@ * Wind River Systems - initial API and implementation *******************************************************************************/ +#if defined(__linux__) + +#include <elf.h> +#include <tcf/framework/mdep-ptrace.h> + /* additional CPU registers */ -#define MDEP_OtherRegisters struct user_fpxregs_struct + +#if !defined(PTRACE_GETFPXREGS) && !defined(PT_GETFPXREGS) +#define PTRACE_GETFPXREGS 18 +#endif + +#if !defined(PTRACE_SETFPXREGS) && !defined(PT_SETFPXREGS) +#define PTRACE_SETFPXREGS 19 +#endif + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +struct i386_user_desc { + uint32_t entry; + uint32_t base; + uint32_t limit; + uint32_t status; +}; + +struct i386_regset_extra { + struct user_fpxregs_struct fpx; + struct i386_user_desc fs; + struct i386_user_desc gs; +}; + +#define MDEP_OtherRegisters struct i386_regset_extra + +#endif diff --git a/agent/machine/i686/tcf/regset-mdep.h b/agent/machine/i686/tcf/regset-mdep.h index 78fecda0..84841618 100644 --- a/agent/machine/i686/tcf/regset-mdep.h +++ b/agent/machine/i686/tcf/regset-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2017 Wind River Systems, Inc. and others. + * Copyright (c) 2012-2019 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. @@ -13,5 +13,38 @@ * Wind River Systems - initial API and implementation *******************************************************************************/ +#if defined(__linux__) + +#include <elf.h> +#include <tcf/framework/mdep-ptrace.h> + /* additional CPU registers */ -#define MDEP_OtherRegisters struct user_fpxregs_struct + +#if !defined(PTRACE_GETFPXREGS) && !defined(PT_GETFPXREGS) +#define PTRACE_GETFPXREGS 18 +#endif + +#if !defined(PTRACE_SETFPXREGS) && !defined(PT_SETFPXREGS) +#define PTRACE_SETFPXREGS 19 +#endif + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +struct i386_user_desc { + uint32_t entry; + uint32_t base; + uint32_t limit; + uint32_t status; +}; + +struct i386_regset_extra { + struct user_fpxregs_struct fpx; + struct i386_user_desc fs; + struct i386_user_desc gs; +}; + +#define MDEP_OtherRegisters struct i386_regset_extra + +#endif diff --git a/agent/machine/microblaze/tcf/disassembler-microblaze.c b/agent/machine/microblaze/tcf/disassembler-microblaze.c index b76ca173..00aa7b9b 100644 --- a/agent/machine/microblaze/tcf/disassembler-microblaze.c +++ b/agent/machine/microblaze/tcf/disassembler-microblaze.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Xilinx, Inc. and others. + * Copyright (c) 2018-2019 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. @@ -134,6 +134,9 @@ enum Instructions { i_addlikc, i_rsublikc, i_mull, i_bslll, i_bslra, i_bslrl, i_bsllli, i_bslrai, i_bslrli, i_bslefi, i_bslifi, + i_addli2, i_rsubli2, i_addli2c, i_rsubli2c, + i_addli2k, i_rsubli2k, i_addli2kc, i_rsubli2kc, + i_orli2, i_andli2, i_xorli2, i_andnli2, i_orl, i_andl, i_xorl, i_andnl, i_pcmplbf, i_pcmpleq, i_pcmplne, i_srla, i_srlc, i_srll, @@ -447,6 +450,18 @@ static InstructionInfo instruction_info[] = { { 0x19, OP(bslrli), INST_TYPE_RD_RA_IMM6, F_IMM }, { 0x19, OP(bslefi), INST_TYPE_RD_RA_IMM6_IMM6, F_IMM }, { 0x19, OP(bslifi), INST_TYPE_RD_RA_IMM6_IMM6, F_IMM }, + { 0x1a, i_addli2, "addli", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_rsubli2, "rsubli", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_addli2c, "addlic", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_rsubli2c, "rsublic", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_addli2k, "addlik", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_rsubli2k, "rsublik", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_addli2kc, "addlikc", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_rsubli2kc, "rsublikc", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_orli2, "orli", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_andli2, "andli", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_xorli2, "xorli", INST_TYPE_RD_IMM, F_IMM }, + { 0x1a, i_andnli2, "andnli", INST_TYPE_RD_IMM, F_IMM }, { 0x20, OP(orl), INST_TYPE_RD_RA_RB, 0 }, { 0x21, OP(andl), INST_TYPE_RD_RA_RB, 0 }, { 0x22, OP(xorl), INST_TYPE_RD_RA_RB, 0 }, @@ -807,6 +822,24 @@ static int decode_instruction(void) { } break; + case 0x1a: + switch ((instr_bits >> 16) & 0x1f) { + case 0x00: op = i_addli2; break; + case 0x01: op = i_rsubli2; break; + case 0x02: op = i_addli2c; break; + case 0x03: op = i_rsubli2c; break; + case 0x04: op = i_addli2k; break; + case 0x05: op = i_rsubli2k; break; + case 0x06: op = i_addli2kc; break; + case 0x07: op = i_rsubli2kc; break; + case 0x10: op = i_orli2; break; + case 0x11: op = i_andli2; break; + case 0x12: op = i_xorli2; break; + case 0x13: op = i_andnli2; break; + default: return 0; + } + break; + case 0x1b: switch ((instr_bits >> 10) & 0x3f) { case 0x00: /* 000000 */ op = i_get; break; diff --git a/agent/machine/microblaze/tcf/dwarfreloc-mdep.h b/agent/machine/microblaze/tcf/dwarfreloc-mdep.h index 6d9d9346..ff490d60 100644 --- a/agent/machine/microblaze/tcf/dwarfreloc-mdep.h +++ b/agent/machine/microblaze/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2017 Xilinx, Inc. and others. + * Copyright (c) 2013-2021 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. @@ -59,6 +59,6 @@ static void elf_relocate(void) { *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/microblaze/tcf/stack-crawl-microblaze.c b/agent/machine/microblaze/tcf/stack-crawl-microblaze.c index 6483860f..aa15622e 100644 --- a/agent/machine/microblaze/tcf/stack-crawl-microblaze.c +++ b/agent/machine/microblaze/tcf/stack-crawl-microblaze.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 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. @@ -90,6 +90,15 @@ typedef struct { static MemCache mem_cache[MEM_CACHE_SIZE]; +static int read_mem(ContextAddress address, void * buf, size_t size) { +#if ENABLE_MemoryAccessModes + static MemoryAccessMode mem_access_mode = { 0, 0, 0, 0, 0, 0, 1 }; + return context_read_mem_ext(stk_ctx, &mem_access_mode, address, buf, size); +#else + return context_read_mem(stk_ctx, address, buf, size); +#endif +} + static int read_byte(uint64_t addr, uint8_t * bt) { unsigned i = 0; MemCache * c = NULL; @@ -106,7 +115,7 @@ static int read_byte(uint64_t addr, uint8_t * bt) { c = mem_cache + mem_cache_idx; c->addr = addr; c->size = sizeof(c->data); - if (context_read_mem(stk_ctx, (ContextAddress)addr, c->data, c->size) < 0) { + if (read_mem((ContextAddress)addr, c->data, c->size) < 0) { #if ENABLE_ExtendedMemoryErrorReports int error = errno; MemoryErrorInfo info; @@ -1094,6 +1103,7 @@ static int trace_instructions(void) { } int crawl_stack_frame_microblaze(StackFrame * frame, StackFrame * down) { + RegisterDefinition * defs = get_reg_definitions(frame->ctx); RegisterDefinition * def = NULL; uint64_t pc = 0; @@ -1102,6 +1112,11 @@ int crawl_stack_frame_microblaze(StackFrame * frame, StackFrame * down) { for (i = 0; i < MEM_CACHE_SIZE; i++) mem_cache[i].size = 0; #endif + if (defs == NULL) { + set_errno(ERR_OTHER, "Context has no registers"); + return -1; + } + reg_size = 4; stk_ctx = frame->ctx; memset(®_data, 0, sizeof(reg_data)); @@ -1109,7 +1124,7 @@ int crawl_stack_frame_microblaze(StackFrame * frame, StackFrame * down) { branch_pos = 0; branch_cnt = 0; - for (def = get_reg_definitions(stk_ctx); def->name; def++) { + for (def = defs; def->name; def++) { if (def->dwarf_id == 0) reg_size = def->size; if (def->dwarf_id < 0 || def->dwarf_id >= REG_DATA_SIZE) continue; if (read_reg_value(frame, def, ®_data[def->dwarf_id].v) < 0) continue; @@ -1120,7 +1135,7 @@ int crawl_stack_frame_microblaze(StackFrame * frame, StackFrame * down) { if (trace_instructions() < 0) return -1; - for (def = get_reg_definitions(stk_ctx); def->name; def++) { + for (def = defs; def->name; def++) { if (def->dwarf_id < 0 || def->dwarf_id >= REG_DATA_SIZE) continue; if (chk_loaded(def->dwarf_id) < 0) continue; if (!reg_data[def->dwarf_id].o) continue; diff --git a/agent/machine/powerpc/tcf/cpudefs-mdep.c b/agent/machine/powerpc/tcf/cpudefs-mdep.c index 79b7aa34..7dbae8df 100644 --- a/agent/machine/powerpc/tcf/cpudefs-mdep.c +++ b/agent/machine/powerpc/tcf/cpudefs-mdep.c @@ -80,7 +80,7 @@ RegisterDefinition regs_def[] = { { "msr", REG_OFFSET(user.regs.msr), RSZ, 66, -1, 1}, { "orig_gpr3", REG_OFFSET(user.regs.orig_gpr3), RSZ, -1, -1, 1}, { "ctr", REG_OFFSET(user.regs.ctr), RSZ, 109, -1, 1}, - { "link", REG_OFFSET(user.regs.link), RSZ, 108, -1, 1}, + { "link", REG_OFFSET(user.regs.link), RSZ, 108, 108, 1}, { "xer", REG_OFFSET(user.regs.xer), RSZ, 101, -1, 1}, { "ccr", REG_OFFSET(user.regs.ccr), RSZ, -1, -1, 1}, #ifdef __powerpc64__ diff --git a/agent/machine/powerpc/tcf/dwarfreloc-mdep.h b/agent/machine/powerpc/tcf/dwarfreloc-mdep.h index 22985e36..a9fdfed2 100644 --- a/agent/machine/powerpc/tcf/dwarfreloc-mdep.h +++ b/agent/machine/powerpc/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Xilinx, Inc. and others. + * Copyright (c) 2014-2021 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. @@ -44,6 +44,6 @@ static void elf_relocate(void) { *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/ppc64/tcf/dwarfreloc-mdep.h b/agent/machine/ppc64/tcf/dwarfreloc-mdep.h index 16c4662b..52980f8b 100644 --- a/agent/machine/ppc64/tcf/dwarfreloc-mdep.h +++ b/agent/machine/ppc64/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2015-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. @@ -52,6 +52,6 @@ static void elf_relocate(void) { *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/riscv/tcf/cpu-regs-gdb.h b/agent/machine/riscv/tcf/cpu-regs-gdb.h new file mode 100644 index 00000000..6b3f5e54 --- /dev/null +++ b/agent/machine/riscv/tcf/cpu-regs-gdb.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#ifndef D_cpu_regs_gdb_riscv32 +#define D_cpu_regs_gdb_riscv32 + +#include <tcf/config.h> + +static const char * cpu_regs_gdb_riscv32 = +"<architecture>rv32</architecture>\n" +"<feature name='org.gnu.gdb.riscv.cpu'>\n" +" <reg name='zero' bitsize='32' type='int' regnum='0' />\n" +" <reg name='ra' bitsize='32' type='code_ptr' />\n" +" <reg name='sp' bitsize='32' type='data_ptr' />\n" +" <reg name='gp' bitsize='32' type='data_ptr' />\n" +" <reg name='tp' bitsize='32' type='data_ptr' />\n" +" <reg name='t0' bitsize='32' type='int' />\n" +" <reg name='t1' bitsize='32' type='int' />\n" +" <reg name='t2' bitsize='32' type='int' />\n" +" <reg name='fp' bitsize='32' type='data_ptr' />\n" +" <reg name='s1' bitsize='32' type='int' />\n" +" <reg name='a0' bitsize='32' type='int' />\n" +" <reg name='a1' bitsize='32' type='int' />\n" +" <reg name='a2' bitsize='32' type='int' />\n" +" <reg name='a3' bitsize='32' type='int' />\n" +" <reg name='a4' bitsize='32' type='int' />\n" +" <reg name='a5' bitsize='32' type='int' />\n" +" <reg name='a6' bitsize='32' type='int' />\n" +" <reg name='a7' bitsize='32' type='int' />\n" +" <reg name='s2' bitsize='32' type='int' />\n" +" <reg name='s3' bitsize='32' type='int' />\n" +" <reg name='s4' bitsize='32' type='int' />\n" +" <reg name='s5' bitsize='32' type='int' />\n" +" <reg name='s6' bitsize='32' type='int' />\n" +" <reg name='s7' bitsize='32' type='int' />\n" +" <reg name='s8' bitsize='32' type='int' />\n" +" <reg name='s9' bitsize='32' type='int' />\n" +" <reg name='s10' bitsize='32' type='int' />\n" +" <reg name='s11' bitsize='32' type='int' />\n" +" <reg name='t3' bitsize='32' type='int' />\n" +" <reg name='t4' bitsize='32' type='int' />\n" +" <reg name='t5' bitsize='32' type='int' />\n" +" <reg name='t6' bitsize='32' type='int' />\n" +" <reg name='pc' bitsize='32' type='code_ptr' />\n" +"</feature>\n" +"<feature name='org.gnu.gdb.riscv.csr'>\n" +"</feature>\n"; + +#endif /* D_cpu_regs_gdb_riscv32 */ diff --git a/agent/machine/riscv/tcf/disassembler-riscv.c b/agent/machine/riscv/tcf/disassembler-riscv.c new file mode 100644 index 00000000..b8eca34c --- /dev/null +++ b/agent/machine/riscv/tcf/disassembler-riscv.c @@ -0,0 +1,1880 @@ +/******************************************************************************* + * Copyright (c) 2019 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#include <tcf/config.h> + +#if SERVICE_Disassembly + +#include <assert.h> +#include <stdio.h> +#include <tcf/framework/context.h> +#include <tcf/services/symbols.h> +#include <machine/riscv/tcf/disassembler-riscv.h> + +static char buf[128]; +static size_t buf_pos = 0; +static unsigned xlen = 0; +static DisassemblerParams * params = NULL; +static uint64_t instr_addr = 0; +static uint32_t instr = 0; + +static const int imm_bits_w[32] = { 6, 10, 11, 12, 5 }; +static const int imm_bits_d[32] = { 10, 11, 12, 5, 6 }; +static const int imm_bits_q[32] = { 11, 12, 5, 6, 10 }; + +static const int imm_bits_lw_sp[32] = { 4, 5, 6, 12, 2, 3 }; +static const int imm_bits_ld_sp[32] = { 5, 6, 12, 2, 3, 4 }; +static const int imm_bits_lq_sp[32] = { 6, 12, 2, 3, 4, 5 }; +static const int imm_bits_sw_sp[32] = { 9, 10, 11, 12, 7, 8 }; +static const int imm_bits_sd_sp[32] = { 10, 11, 12, 7, 8, 9 }; +static const int imm_bits_sq_sp[32] = { 11, 12, 7, 8, 9, 10 }; + +static const int imm_bits_s[32] = { 7, 8, 9, 10, 11, 25, 26, 27, 28, 29, 30, 31 }; +static const int imm_bits_j[32] = { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 20, 12, 13, 14, 15, 16, 17, 18, 19, 31 }; +static const int imm_bits_b[32] = { 8, 9, 10, 11, 25, 26, 27, 28, 29, 30, 7, 31 }; +static const int imm_bits_jc[32] = { 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12 }; +static const int imm_bits_bc[32] = { 3, 4, 10, 11, 2, 5, 6, 12 }; + +static const int imm_bits_addi_sp[32] = { 6, 2, 5, 3, 4, 12 }; +static const int imm_bits_addi_spn[32] = { 6, 5, 11, 12, 7, 8, 9, 10 }; +static const int imm_bits_shift[32] = { 2, 3, 4, 5, 6, 12 }; + +static void add_char(char ch) { + if (buf_pos >= sizeof(buf) - 1) return; + buf[buf_pos++] = ch; + if (ch == ' ') while (buf_pos < 8) buf[buf_pos++] = ch; +} + +static void add_str(const char * s) { + while (*s) add_char(*s++); +} + +static void add_dec_uint32(uint32_t n) { + char s[32]; + size_t i = 0; + do { + s[i++] = (char)('0' + n % 10); + n = n / 10; + } + while (n != 0); + while (i > 0) add_char(s[--i]); +} + +#if 0 +static void add_dec_uint64(uint64_t n) { + char s[64]; + size_t i = 0; + do { + s[i++] = (char)('0' + (int)(n % 10)); + n = n / 10; + } + while (n != 0); + while (i > 0) add_char(s[--i]); +} +#endif + +static void add_hex_uint32(uint32_t n) { + char s[32]; + size_t i = 0; + while (i < 8) { + uint32_t d = n & 0xf; + if (i > 0 && n == 0) break; + s[i++] = (char)(d < 10 ? '0' + d : 'a' + d - 10); + n = n >> 4; + } + while (i > 0) add_char(s[--i]); +} + +static void add_hex_uint64(uint64_t n) { + char s[64]; + size_t i = 0; + while (i < 16) { + uint32_t d = n & 0xf; + if (i > 0 && n == 0) break; + s[i++] = (char)(d < 10 ? '0' + d : 'a' + d - 10); + n = n >> 4; + } + while (i > 0) add_char(s[--i]); +} + +#if 0 +static void add_flt_uint32(uint32_t n) { + char str[32]; + union { + uint32_t n; + float f; + } u; + u.n = n; + snprintf(str, sizeof(str), "%#g", u.f); + add_str(str); +} + +static void add_flt_uint64(uint64_t n) { + char str[32]; + union { + uint64_t n; + double d; + } u; + u.n = n; + snprintf(str, sizeof(str), "%#g", u.d); + add_str(str); +} +#endif + +static void add_addr(uint64_t addr) { + while (buf_pos < 16) add_char(' '); + add_str("; addr=0x"); + add_hex_uint64(addr); +#if ENABLE_Symbols + if (params->ctx != NULL) { + Symbol * sym = NULL; + char * name = NULL; + ContextAddress sym_addr = 0; + if (find_symbol_by_addr(params->ctx, STACK_NO_FRAME, (ContextAddress)addr, &sym) < 0) return; + if (get_symbol_name(sym, &name) < 0 || name == NULL) return; + if (get_symbol_address(sym, &sym_addr) < 0) return; + if (sym_addr <= addr) { + add_str(": "); + add_str(name); + if (sym_addr < addr) { + add_str(" + 0x"); + add_hex_uint64(addr - (uint64_t)sym_addr); + } + } + } +#endif +} + +static void add_reg(unsigned n) { + static const char * names[] = { + "zero", "ra", + "sp", "gp", + "tp", "t0", + "t1", "t2", + "s0", "s1", + "a0", "a1", + "a2", "a3", + "a4", "a5", + "a6", "a7", + "s2", "s3", + "s4", "s5", + "s6", "s7", + "s8", "s9", + "s10", "s11", + "t3", "t4", + "t5", "t6" + }; + add_str(names[n & 0x1f]); +} + +static void add_reg_csr(unsigned csr) { + switch (csr) { + case 1: add_str("fflags"); return; + } + add_str("csr"); + add_dec_uint32(csr); +} + +static void add_freg(unsigned n) { + static const char * names[] = { + "ft0", "ft1", + "ft2", "ft3", + "ft4", "ft5", + "ft6", "ft7", + "fs0", "fs1", + "fa0", "fa1", + "fa2", "fa3", + "fa4", "fa5", + "fa6", "fa7", + "fs2", "fs3", + "fs4", "fs5", + "fs6", "fs7", + "fs8", "fs9", + "fs10", "fs11", + "ft8", "ft9", + "ft10", "ft11" + }; + add_str(names[n & 0x1f]); +} + +static void add_rvc_reg(unsigned n) { + static const char * names[] = { + "s0", "s1", + "a0", "a1", + "a2", "a3", + "a4", "a5", + }; + add_str(names[n & 0x7]); +} + +static void add_rvc_freg(unsigned n) { + static const char * names[] = { + "fs0", "fs1", + "fa0", "fa1", + "fa2", "fa3", + "fa4", "fa5", + }; + add_str(names[n & 0x7]); +} + +static void add_rm(unsigned rm) { + static const char * names[] = { + "rne", "rtz", + "rdn", "rup", + "rmm", "5", + "6", "dyn", + }; + if ((rm & 0x7) == 7) return; + add_str(", "); + add_str(names[rm & 0x7]); +} + +static uint32_t get_imm(const int * bits) { + unsigned i; + uint32_t v = 0; + for (i = 0; i < 32 && bits[i]; i++) { + if (instr & (1u << bits[i])) v |= 1u << i; + } + return v; +} + +static int32_t get_imm_se(const int * bits) { + unsigned i; + uint32_t v = 0; + for (i = 0; i < 32 && bits[i]; i++) { + if (instr & (1u << bits[i])) v |= 1u << i; + } + if (v & (1u << (i - 1))) v |= ~((1u << i) - 1); + return v; +} + +static int32_t get_imm_rse(unsigned pos, unsigned bits) { + uint32_t v = (instr >> pos) & ((1u << bits) - 1); + if (v & (1u << (bits - 1))) v |= ~((1u << bits) - 1); + return v; +} + +static void disassemble_rv32i(void) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + if ((instr & 0x0000007f) == 0x00000037) { + unsigned imm = instr >> 12; + add_str("lui "); + add_reg(rd); + add_str(", 0x"); + add_hex_uint32(imm); + return; + } + if ((instr & 0x0000007f) == 0x00000017) { + unsigned imm = instr >> 12; + add_str("auipc "); + add_reg(rd); + add_str(", 0x"); + add_hex_uint32(imm); + return; + } + if ((instr & 0x0000007f) == 0x0000006f) { + int32_t imm = get_imm_se(imm_bits_j); + if (rd == 0) { + add_str("j "); + } + else { + add_str("jal "); + add_reg(rd); + add_str(", "); + } + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_char('+'); + add_dec_uint32(imm); + } + add_addr(instr_addr + ((int64_t)imm << 1)); + return; + } + if ((instr & 0x0000707f) == 0x00000067) { + int32_t imm = instr >> 20; + if (rd == 0 && imm == 0 && rs1 == 1) { + add_str("ret"); + return; + } + add_str("jalr "); + add_reg(rd); + add_str(", "); + if (imm == 0) { + add_reg(rs1); + return; + } + add_dec_uint32(imm); + add_char('('); + add_reg(rs1); + add_char(')'); + return; + } + if ((instr & 0x0000007f) == 0x00000063) { + int32_t imm = get_imm_se(imm_bits_b); + if (rs2 == 0) { + switch ((instr >> 12) & 7) { + case 0: + add_str("beqz "); + break; + case 1: + add_str("bnez "); + break; + case 4: + add_str("bltz "); + break; + case 5: + add_str("bgez "); + break; + case 6: + add_str("bltuz "); + break; + case 7: + add_str("bgeuz "); + break; + } + } + else if (rs1 == 0) { + switch ((instr >> 12) & 7) { + case 4: + add_str("bgtz "); + break; + case 5: + add_str("blez "); + break; + case 6: + add_str("bgtuz "); + break; + case 7: + add_str("bteuz "); + break; + } + } + else { + switch ((instr >> 12) & 7) { + case 0: + add_str("beq "); + break; + case 1: + add_str("bne "); + break; + case 4: + add_str("blt "); + break; + case 5: + add_str("bge "); + break; + case 6: + add_str("bltu "); + break; + case 7: + add_str("bgeu "); + break; + } + } + if (buf_pos > 0) { + if (rs1 != 0) { + add_reg(rs1); + add_str(", "); + } + if (rs2 != 0) { + add_reg(rs2); + add_str(", "); + } + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_char('+'); + add_dec_uint32(imm); + } + add_addr(instr_addr + ((int64_t)imm << 1)); + return; + } + } + if ((instr & 0x0000007f) == 0x00000003) { + int32_t imm = get_imm_rse(20, 12); + switch ((instr >> 12) & 7) { + case 0: + add_str("lb "); + break; + case 1: + add_str("lh "); + break; + case 2: + add_str("lw "); + break; + case 4: + add_str("lbu "); + break; + case 5: + add_str("lhu "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_dec_uint32(imm); + } + add_str("("); + add_reg(rs1); + add_str(")"); + return; + } + } + if ((instr & 0x0000007f) == 0x00000023) { + int32_t imm = get_imm_se(imm_bits_s); + switch ((instr >> 12) & 7) { + case 0: + add_str("sb "); + break; + case 1: + add_str("sh "); + break; + case 2: + add_str("sw "); + break; + } + if (buf_pos > 0) { + add_reg(rs2); + add_str(", "); + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_dec_uint32(imm); + } + add_str("("); + add_reg(rs1); + add_str(")"); + return; + } + } + if ((instr & 0x0000007f) == 0x00000013) { + unsigned func = (instr >> 12) & 7; + int32_t imm = get_imm_rse(20, 12); + switch (func) { + case 0: + if (rs1 == 0) { + if (rd == 0 && imm == 0) { + add_str("nop"); + return; + } + add_str("li "); + add_reg(rd); + add_str(", "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm); + return; + } + if (imm == 0) { + add_str("mv "); + add_reg(rd); + add_str(", "); + add_reg(rs1); + return; + } + add_str("addi "); + break; + case 2: + add_str("slti "); + break; + case 3: + if (imm == 1) { + add_str("seqz "); + add_reg(rd); + add_str(", "); + add_reg(rs1); + return; + } + add_str("sltiu "); + break; + case 4: + if (imm == -1) { + add_str("not "); + add_reg(rd); + add_str(", "); + add_reg(rs1); + return; + } + add_str("xori "); + break; + case 6: + add_str("ori "); + break; + case 7: + add_str("andi "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm); + return; + } + } + if ((instr & 0xbe00007f) == 0x00000013) { + unsigned func = (instr >> 12) & 7; + uint32_t imm = rs2; + switch (func) { + case 1: + add_str("slli "); + break; + case 5: + add_str(instr & (1 << 30) ? "srai " : "srli "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", 0x"); + add_hex_uint32(imm); + return; + } + } + if ((instr & 0xfe00007f) == 0x00000033) { + unsigned func = (instr >> 12) & 7; + static const char * nm[8] = { "add", "sll", "slt", "sltu", "xor", "srl", "or", "and" }; + if (func == 2 && rs1 == 0) add_str("sgtz "); + if (func == 3 && rs1 == 0) add_str("snez "); + if (func == 2 && rs2 == 0) add_str("sltz "); + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1 ? rs1 : rs2); + return; + } + add_str(nm[func]); + add_char(' '); + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + add_reg(rs2); + return; + } + if ((instr & 0xfe00007f) == 0x40000033) { + unsigned func = (instr >> 12) & 7; + switch (func) { + case 0: + if (rs1 == 0) { + add_str("neg "); + add_reg(rd); + add_str(", "); + add_reg(rs2); + return; + } + add_str("sub "); + break; + case 5: + add_str("sra "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + add_reg(rs2); + return; + } + } + if ((instr & 0x0000707f) == 0x0000000f) { + unsigned fm = instr >> 28; + unsigned p = (instr >> 24) & 0xf; + unsigned s = (instr >> 20) & 0xf; + if (p != 0 && s != 0) { + add_str("fence"); + if (fm == 8) add_str(".tso"); + add_char(' '); + if (p & 8) add_char('i'); + if (p & 4) add_char('o'); + if (p & 2) add_char('r'); + if (p & 1) add_char('w'); + add_str(", "); + if (s & 8) add_char('i'); + if (s & 4) add_char('o'); + if (s & 2) add_char('r'); + if (s & 1) add_char('w'); + return; + } + } + if (instr == 0x00000073) { + add_str("ecall"); + return; + } + if (instr == 0x00100073) { + add_str("ebreak"); + return; + } + if ((instr & 0x0fffffff) == 0x00200073) { + switch (instr >> 28) { + case 0: add_str("uret"); return; + case 1: add_str("sret"); return; + case 3: add_str("mret"); return; + } + } + if (instr == 0x10500073) { + add_str("wfi"); + return; + } + if ((instr & 0xfe007fff) == 0x12000073) { + add_str("sfence.vma "); + add_reg(rs1); + add_str(", "); + add_reg(rs2); + return; + } +} + +static void disassemble_rv32a(void) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + if ((instr & 0x0000307f) == 0x0000202f) { + unsigned func = (instr >> 27) & 0x1f; + switch (func) { + case 2: if (rs2 == 0) add_str("lr.w"); break; + case 3: add_str("sc.w"); break; + case 1: add_str("amoswap.w"); break; + case 0: add_str("amoadd.w"); break; + case 4: add_str("amoxor.w"); break; + case 12: add_str("amoand.w"); break; + case 8: add_str("amoor.w"); break; + case 16: add_str("amomin.w"); break; + case 20: add_str("amomax.w"); break; + case 24: add_str("amominu.w"); break; + case 28: add_str("amomaxu.w"); break; + } + if (buf_pos > 0) { + if (instr & (1 << 26)) add_str(".aq"); + if (instr & (1 << 25)) add_str(".rl"); + add_char(' '); + add_reg(rd); + add_str(", "); + if (func != 2) { + add_reg(rs2); + add_str(", "); + } + add_char('('); + add_reg(rs1); + add_char(')'); + return; + } + } +} + +static void disassemble_rv_z(void) { + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + unsigned func = (instr >> 12) & 7; + if ((instr & 0x0000007f) == 0x0000000f && func == 1) { + unsigned imm = instr >> 20; + add_str("fence.i "); + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", 0x"); + add_hex_uint32(imm); + return; + } + if ((instr & 0x0000007f) == 0x00000073) { + const char * nms[4] = { NULL, "csrrw", "csrrs", "csrrc" }; + const char * nm = nms[func & 3]; + unsigned csr = instr >> 20; + if (nm != NULL) { + if (csr == 1) { + if (rs1 == 0 && func == 2) { + add_str("frflags "); + add_reg(rd); + return; + } + if (func == 1) { + add_str("fsflags "); + if (rd != 0) { + add_reg(rd); + add_str(", "); + } + add_reg(rs1); + return; + } + } + if (csr == 2) { + if (rs1 == 0 && func == 2) { + add_str("frrm "); + add_reg(rd); + return; + } + if (func == 1) { + add_str("fsrm "); + if (rd != 0) { + add_reg(rd); + add_str(", "); + } + add_reg(rs1); + return; + } + } + if (func == 2 && rs1 == 0) { + add_str("csrr "); + add_reg(rd); + add_str(", "); + add_reg_csr(csr); + return; + } + if (rd == 0) { + const char * nms_rd0[4] = { NULL, "csrw", "csrs", "csrc" }; + add_str(nms_rd0[func & 3]); + if (func >= 4) add_char('i'); + add_char(' '); + } + else { + add_str(nm); + if (func >= 4) add_char('i'); + add_char(' '); + add_reg(rd); + add_str(", "); + } + add_reg_csr(csr); + add_str(", "); + if (func < 4) add_reg(rs1); + else add_dec_uint32(rs1); + return; + } + } +} + +static void disassemble_rv32m(void) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + unsigned func = (instr >> 12) & 7; + if ((instr & 0xfe00007f) == 0x02000033) { + switch (func) { + case 0: + add_str("mul "); + break; + case 1: + add_str("mulh "); + break; + case 2: + add_str("mulhsu "); + break; + case 3: + add_str("mulhu "); + break; + case 4: + add_str("div "); + break; + case 5: + add_str("divu "); + break; + case 6: + add_str("rem "); + break; + case 7: + add_str("remu "); + break; + } + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + add_reg(rs2); + return; + } +} + +static void disassemble_rv32f(void) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + unsigned rm = (instr >> 12) & 0x7; + if ((instr & 0x0000005f) == 0x00000007) { + unsigned size = (instr >> 12) & 7; + char sz_char = 0; + switch (size) { + case 2: sz_char = 'w'; break; + case 3: sz_char = 'd'; break; + case 4: sz_char = 'q'; break; + } + if (sz_char) { + int32_t imm = 0; + if (instr & 0x00000020) { + imm = get_imm_se(imm_bits_s); + add_str("fs"); + add_char(sz_char); + add_char(' '); + add_freg(rs2); + } + else { + imm = get_imm_rse(20, 12); + add_str("fl"); + add_char(sz_char); + add_char(' '); + add_freg(rd); + } + add_str(", "); + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_dec_uint32(imm); + } + add_char('('); + add_reg(rs1); + add_char(')'); + return; + } + } + if ((instr & 0x00000073) == 0x00000043) { + unsigned size = (instr >> 25) & 3; + char sz_char = 0; + switch (size) { + case 0: sz_char = 's'; break; + case 1: sz_char = 'd'; break; + case 3: sz_char = 'q'; break; + } + if (sz_char) { + const char * nm[4] = { "fmadd.", "fmsub.", "fnmsub.", "fnmadd." }; + add_str(nm[(instr >> 2) & 3]); + add_char(sz_char); + add_char(' '); + add_freg(rd); + add_str(", "); + add_freg(rs1); + add_str(", "); + add_freg(rs2); + add_str(", "); + add_freg((instr >> 27) & 0x1f); + add_rm(rm); + return; + } + } + if ((instr & 0x0000007f) == 0x00000053) { + unsigned size = (instr >> 25) & 3; + char sz_char = 0; + switch (size) { + case 0: sz_char = 's'; break; + case 1: sz_char = 'd'; break; + case 3: sz_char = 'q'; break; + } + if (sz_char) { + int no_rs2 = 0; + int no_rm = 0; + switch ((instr >> 27) & 0x1f) { + case 0: + add_str("fadd."); + add_char(sz_char); + break; + case 1: + add_str("fsub."); + add_char(sz_char); + break; + case 2: + add_str("fmul."); + add_char(sz_char); + break; + case 3: + add_str("fdiv."); + add_char(sz_char); + break; + case 4: + if (rs1 == rs2) { + if (rm == 0) add_str("fmv."); + if (rm == 1) add_str("fneg."); + if (rm == 2) add_str("fabs."); + if (buf_pos > 0) { + add_char(sz_char); + add_char(' '); + add_freg(rd); + add_str(", "); + add_freg(rs1); + return; + } + } + no_rm = 1; + if (rm == 0) add_str("fsgnj."); + if (rm == 1) add_str("fsgnjn."); + if (rm == 2) add_str("fsgnjx."); + if (buf_pos > 0) add_char(sz_char); + break; + case 5: + no_rm = 1; + if (rm == 0) add_str("fmin."); + if (rm == 1) add_str("fmax."); + if (buf_pos > 0) add_char(sz_char); + break; + case 8: + no_rs2 = 1; + if (rs2 == 0 && size == 1) add_str("fcvt.d.s"); + if (rs2 == 1 && size == 0) add_str("fcvt.s.d"); + if (rs2 == 0 && size == 3) add_str("fcvt.q.s"); + if (rs2 == 3 && size == 0) add_str("fcvt.s.q"); + if (rs2 == 1 && size == 3) add_str("fcvt.q.d"); + if (rs2 == 3 && size == 1) add_str("fcvt.d.q"); + if (buf_pos > 0) { + add_char(' '); + add_freg(rd); + add_str(", "); + add_freg(rs1); + if (rs2 > size) add_rm(rm); + return; + } + break; + case 11: + no_rs2 = 1; + if (rs2 == 0) add_str("fsqrt."); + if (buf_pos > 0) add_char(sz_char); + break; + case 20: + no_rm = 1; + if (rm == 0) add_str("fle."); + if (rm == 1) add_str("flt."); + if (rm == 2) add_str("feq."); + if (buf_pos > 0) { + add_char(sz_char); + add_char(' '); + add_reg(rd); + add_str(", "); + add_freg(rs1); + add_str(", "); + add_freg(rs2); + return; + } + break; + case 24: + no_rs2 = 1; + if (rs2 == 0) add_str("fcvt.w."); + if (rs2 == 1) add_str("fcvt.wu."); + if (buf_pos > 0) { + add_char(sz_char); + add_char(' '); + add_reg(rd); + add_str(", "); + add_freg(rs1); + add_rm(rm); + return; + } + break; + case 26: + no_rs2 = 1; + if (rs2 == 0 || rs2 == 1) { + add_str("fcvt."); + add_char(sz_char); + add_char('.'); + add_char('w'); + if (rs2 == 1) add_char('u'); + add_char(' '); + add_freg(rd); + add_str(", "); + add_reg(rs1); + add_rm(rm); + return; + } + break; + case 28: + no_rm = 1; + no_rs2 = 1; + if (rs2 == 0) { + if (rm == 0) { + add_str("fmv.x."); + if (sz_char == 's') sz_char = 'w'; + add_char(sz_char); + add_char(' '); + add_reg(rd); + add_str(", "); + add_freg(rs1); + return; + } + if (rm == 1) add_str("fclass."); + if (buf_pos > 0) add_char(sz_char); + } + break; + case 30: + no_rm = 1; + no_rs2 = 1; + if (rs2 == 0 && rm == 0 && size == 0) { + add_str("fmv.w.x "); + add_freg(rd); + add_str(", "); + add_reg(rs1); + return; + } + break; + } + if (buf_pos > 0) { + add_char(' '); + add_freg(rd); + add_str(", "); + add_freg(rs1); + if (!no_rs2) { + add_str(", "); + add_freg(rs2); + } + if (!no_rm) { + add_rm(rm); + } + return; + } + } + } +} + +static void disassemble_rv64i(void) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + unsigned func = (instr >> 12) & 7; + if ((instr & 0x0000007f) == 0x00000003) { + int32_t imm = get_imm_rse(20, 12); + switch (func) { + case 6: + add_str("lwu "); + break; + case 3: + add_str("ld "); + break; + } + if (buf_pos > 0) { + add_reg((instr >> 7) & 0x1f); + add_str(", "); + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_dec_uint32(imm); + } + add_char('('); + add_reg(rs1); + add_char(')'); + return; + } + } + if ((instr & 0x0000307f) == 0x00003023) { + int32_t imm = get_imm_se(imm_bits_s); + add_str("sd "); + add_reg(rs2); + add_str(", "); + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_dec_uint32(imm); + } + add_char('('); + add_reg(rs1); + add_char(')'); + return; + } + if ((instr & 0xbc00007f) == 0x00000013) { + uint32_t imm = (instr >> 20) & 0x3f; + switch (func) { + case 1: + add_str("slli "); + break; + case 5: + add_str(instr & (1 << 30) ? "srai " : "srli "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", 0x"); + add_hex_uint32(imm); + return; + } + } + if ((instr & 0x0000707f) == 0x0000001b) { + int32_t imm = get_imm_rse(20, 12); + if (imm == 0) { + add_str("sext.w "); + add_reg(rd); + add_str(", "); + add_reg(rs1); + return; + + } + add_str("addiw "); + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm); + return; + } + if ((instr & 0xbe00007f) == 0x0000001b) { + uint32_t imm = (instr >> 20) & 0x1f; + switch (func) { + case 1: + add_str(instr & (1 << 30) ? "" : "slliw "); + break; + case 5: + add_str(instr & (1 << 30) ? "sraiw " : "srliw "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", 0x"); + add_hex_uint32(imm); + return; + } + } + if ((instr & 0xfe00007f) == 0x0000003b) { + switch (func) { + case 0: + add_str("addw "); + break; + case 1: + add_str("sllw "); + break; + case 5: + add_str("srlw "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + add_reg(rs2); + return; + } + } + if ((instr & 0xfe00007f) == 0x4000003b) { + switch (func) { + case 0: + if (rs1 == 0) { + add_str("negw "); + add_reg(rd); + add_str(", "); + add_reg(rs2); + return; + } + add_str("subw "); + break; + case 5: + add_str("sraw "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + add_reg(rs2); + return; + } + } + disassemble_rv32i(); +} + +static void disassemble_rv64a(void) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + if ((instr & 0x0000307f) == 0x0000302f) { + unsigned func = (instr >> 27) & 0x1f; + switch (func) { + case 2: if (rs2 == 0) add_str("lr.d"); break; + case 3: add_str("sc.d"); break; + case 1: add_str("amoswap.d"); break; + case 0: add_str("amoadd.d"); break; + case 4: add_str("amoxor.d"); break; + case 12: add_str("amoand.d"); break; + case 8: add_str("amoor.d"); break; + case 16: add_str("amomin.d"); break; + case 20: add_str("amomax.d"); break; + case 24: add_str("amominu.d"); break; + case 28: add_str("amomaxu.d"); break; + } + if (buf_pos > 0) { + if (instr & (1 << 26)) add_str(".aq"); + if (instr & (1 << 25)) add_str(".rl"); + add_char(' '); + add_reg(rd); + add_str(", "); + if (func != 2) { + add_reg(rs2); + add_str(", "); + } + add_char('('); + add_reg(rs1); + add_char(')'); + return; + } + } + disassemble_rv32a(); +} + +static void disassemble_rv64m(void) { + unsigned func = (instr >> 12) & 7; + if ((instr & 0xfe00007f) == 0x0200003b) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + switch (func) { + case 0: + add_str("mulw "); + break; + case 4: + add_str("divw "); + break; + case 5: + add_str("divuw "); + break; + case 6: + add_str("remw "); + break; + case 7: + add_str("remuw "); + break; + } + if (buf_pos > 0) { + add_reg(rd); + add_str(", "); + add_reg(rs1); + add_str(", "); + add_reg(rs2); + return; + } + } + disassemble_rv32m(); +} + +static void disassemble_rv64f(void) { + if ((instr & 0x0000007f) == 0x00000053) { + unsigned size = (instr >> 25) & 3; + char sz_char = 0; + switch (size) { + case 0: sz_char = 's'; break; + case 1: sz_char = 'd'; break; + case 3: sz_char = 'q'; break; + } + if (sz_char) { + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + unsigned rm = (instr >> 12) & 0x7; + switch ((instr >> 27) & 0x1f) { + case 24: + if (rs2 == 2) add_str("fcvt.l."); + if (rs2 == 3) add_str("fcvt.lu."); + if (buf_pos > 0) { + add_char(sz_char); + add_char(' '); + add_reg(rd); + add_str(", "); + add_freg(rs1); + add_rm(rm); + return; + } + break; + case 26: + if (rs2 == 2 || rs2 == 3) { + add_str("fcvt."); + add_char(sz_char); + add_char('.'); + add_char('l'); + if (rs2 == 3) add_char('u'); + add_char(' '); + add_freg(rd); + add_str(", "); + add_reg(rs1); + add_rm(rm); + return; + } + break; + case 30: + if (rs2 == 0 && rm == 0 && size == 1) { + add_str("fmv.d.x "); + add_freg(rd); + add_str(", "); + add_reg(rs1); + return; + } + break; + } + } + } + disassemble_rv32f(); +} + +static void disassemble_rv128i(void) { + disassemble_rv64i(); +} + +static void disassemble_rv128m(void) { + disassemble_rv64m(); +} + +static void disassemble_rv128f(void) { + disassemble_rv64f(); +} + +static void disassemble_rv32c(void) { + /* Quadrant 0 */ + if ((instr & 0xffff) == 0x0000) { + add_str("illegal instruction"); + return; + } + if ((instr & 0xe003) == 0x0000) { + uint32_t imm = get_imm(imm_bits_addi_spn); + if (imm != 0) { + add_str("addi "); + add_rvc_reg((instr >> 2) & 0x7); + add_str(", "); + add_reg(2); + add_str(", "); + add_dec_uint32(imm * 4); + return; + } + } + if ((instr & 0x6003) == 0x2000) { + add_str(instr & 0x8000 ? "fsd " : "fld "); + add_rvc_freg((instr >> 2) & 0x7); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_d) * 8); + add_str("("); + add_rvc_reg((instr >> 7) & 0x7); + add_str(")"); + return; + } + if ((instr & 0x6003) == 0x4000) { + add_str(instr & 0x8000 ? "sw " : "lw "); + add_rvc_reg((instr >> 2) & 0x7); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_w) * 4); + add_str("("); + add_rvc_reg((instr >> 7) & 0x7); + add_str(")"); + return; + } + if ((instr & 0x6003) == 0x6000) { + add_str(instr & 0x8000 ? "fsw " : "flw "); + add_rvc_freg((instr >> 2) & 0x7); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_w) * 4); + add_str("("); + add_rvc_reg((instr >> 7) & 0x7); + add_str(")"); + return; + } + + /* Quadrant 1 */ + if ((instr & 0xef83) == 0x0001) { + add_str("nop"); + return; + } + if ((instr & 0xe003) == 0x0001) { + int32_t imm = get_imm_se(imm_bits_shift); + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + add_str("addi "); + add_reg(rd); + add_str(", "); + add_reg(rd); + add_str(", "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm); + return; + } + } + if ((instr & 0x6003) == 0x2001) { + int32_t imm = get_imm_se(imm_bits_jc); + if (instr & 0x8000) { + add_str("j "); + } + else { + add_str("jal "); + add_reg(1); + add_str(", "); + } + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_char('+'); + add_dec_uint32(imm); + } + add_addr(instr_addr + ((int64_t)imm << 1)); + return; + } + if ((instr & 0xe003) == 0x4001) { + int32_t imm = get_imm_se(imm_bits_shift); + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + add_str("li "); + add_reg(rd); + add_str(", "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm); + return; + } + } + if ((instr & 0xe003) == 0x6001) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd == 2) { + int32_t imm = get_imm_se(imm_bits_addi_sp); + if (imm != 0) { + add_str("addi sp, sp, "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm << 4); + return; + } + } + if (rd != 0) { + int32_t imm = get_imm_se(imm_bits_shift); + if (imm != 0) { + add_str("lui "); + add_reg(rd); + add_str(", 0x"); + add_hex_uint32(imm & 0xfffff); + return; + } + } + } + if ((instr & 0xe003) == 0x8001) { + unsigned rd = (instr >> 7) & 0x7; + unsigned func = (instr >> 10) & 3; + if (func < 2) { + uint32_t imm = get_imm(imm_bits_shift); + if (xlen == 32 && imm >= 32) return; + if (imm == 0) { + if (xlen == 128) imm = 64; + else return; + } + add_str(func ? "srai " : "srli "); + add_rvc_reg(rd); + add_str(", "); + add_rvc_reg(rd); + add_str(", 0x"); + add_hex_uint32(imm); + } + else if (func == 2) { + int32_t imm = get_imm_se(imm_bits_shift); + add_str("andi "); + add_rvc_reg(rd); + add_str(", "); + add_rvc_reg(rd); + add_str(", "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm); + } + else if ((instr & (1 << 12)) == 0) { + switch ((instr >> 5) & 3) { + case 0: + add_str("sub "); + break; + case 1: + add_str("xor "); + break; + case 2: + add_str("or "); + break; + case 3: + add_str("and "); + break; + } + add_rvc_reg(rd); + add_str(", "); + add_rvc_reg(rd); + add_str(", "); + add_rvc_reg((instr >> 2) & 7); + } + return; + } + if ((instr & 0xc003) == 0xc001) { + int32_t imm = get_imm_se(imm_bits_bc); + add_str(instr & 0x2000 ? "bnez " : "beqz "); + add_rvc_reg((instr >> 7) & 7); + add_str(", "); + if (imm < 0) { + add_char('-'); + add_dec_uint32(-imm); + } + else { + add_char('+'); + add_dec_uint32(imm); + } + add_addr(instr_addr + ((int64_t)imm << 1)); + return; + } + + /* Quadrant 2 */ + if ((instr & 0xe003) == 0x4002) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + add_str("lw "); + add_reg(rd); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_lw_sp) * 4); + add_str("(sp)"); + return; + } + } + if ((instr & 0xe003) == 0x6002) { + unsigned rd = (instr >> 7) & 0x1f; + add_str("flw "); + add_freg(rd); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_lw_sp) * 4); + add_str("(sp)"); + return; + } + if ((instr & 0xe003) == 0x2002) { + unsigned rd = (instr >> 7) & 0x1f; + add_str("fld "); + add_freg(rd); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_ld_sp) * 8); + add_str("(sp)"); + return; + } + if ((instr & 0xe003) == 0xc002) { + add_str("sw "); + add_reg((instr >> 2) & 0x1f); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_sw_sp) * 4); + add_str("(sp)"); + return; + } + if ((instr & 0xe003) == 0xe002) { + add_str("fsw "); + add_freg((instr >> 2) & 0x1f); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_sw_sp) * 4); + add_str("(sp)"); + return; + } + if ((instr & 0xe003) == 0xa002) { + add_str("fsd "); + add_freg((instr >> 2) & 0x1f); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_sd_sp) * 8); + add_str("(sp)"); + return; + } + if ((instr & 0xe003) == 0x0002) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + uint32_t imm = get_imm(imm_bits_shift); + if (xlen == 32 && imm >= 32) return; + if (imm == 0) { + if (xlen == 128) imm = 64; + else return; + } + add_str("slli "); + add_reg(rd); + add_str(", "); + add_reg(rd); + add_str(", 0x"); + add_hex_uint32(imm); + return; + } + } + if ((instr & 0xe003) == 0x8002) { + unsigned rd = (instr >> 7) & 0x1f; + unsigned rs = (instr >> 2) & 0x1f; + if ((instr & (1 << 12)) == 0) { + if (rd == 0) return; + if (rs == 0) { + if (rd == 1) { + add_str("ret"); + return; + } + add_str("jr "); + add_reg(rd); + return; + } + add_str("mv "); + } + else { + if (rd == 0 && rs == 0) { + add_str("ebreak"); + return; + } + if (rd == 0) return; + if (rs == 0) { + add_str("jalr "); + add_reg(rd); + return; + } + add_str("add "); + add_reg(rd); + add_str(", "); + } + add_reg(rd); + add_str(", "); + add_reg(rs); + return; + } +} + +static void disassemble_rv64c(void) { + if ((instr & 0xe003) == 0x2001) { + int32_t imm = get_imm_se(imm_bits_shift); + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + if (imm == 0) { + add_str("sext.w "); + add_reg(rd); + add_str(", "); + add_reg(rd); + return; + } + add_str("addiw "); + add_reg(rd); + add_str(", "); + add_reg(rd); + add_str(", "); + if (imm < 0) { + add_char('-'); + imm = -imm; + } + add_dec_uint32(imm); + return; + } + } + if ((instr & 0xe003) == 0x6002) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + add_str("ld "); + add_reg(rd); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_ld_sp) * 8); + add_str("(sp)"); + return; + } + } + if ((instr & 0xe003) == 0xe002) { + add_str("sd "); + add_reg((instr >> 2) & 0x1f); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_sd_sp) * 8); + add_str("(sp)"); + return; + } + if ((instr & 0x6003) == 0x6000) { + add_str(instr & 0x8000 ? "sd " : "ld "); + add_rvc_reg((instr >> 2) & 0x7); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_d) * 8); + add_str("("); + add_rvc_reg((instr >> 7) & 0x7); + add_str(")"); + return; + } + if ((instr & 0xfc03) == 0x9c01) { + unsigned rd = (instr >> 7) & 0x7; + switch ((instr >> 5) & 3) { + case 0: + add_str("subw "); + break; + case 1: + add_str("addw "); + break; + default: + return; + } + add_rvc_reg(rd); + add_str(", "); + add_rvc_reg(rd); + add_str(", "); + add_rvc_reg((instr >> 2) & 7); + return; + } + disassemble_rv32c(); +} + +static void disassemble_rv128c(void) { + if ((instr & 0xe003) == 0x2002) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + add_str("lq "); + add_reg(rd); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_lq_sp) * 16); + add_str("(sp)"); + return; + } + } + if ((instr & 0xe003) == 0xa002) { + add_str("sq "); + add_reg((instr >> 2) & 0x1f); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_sq_sp) * 16); + add_str("(sp)"); + return; + } + if ((instr & 0x6003) == 0x2000) { + add_str(instr & 0x8000 ? "sq " : "lq "); + add_rvc_reg((instr >> 2) & 0x7); + add_str(", "); + add_dec_uint32(get_imm(imm_bits_q) * 16); + add_str("("); + add_rvc_reg((instr >> 7) & 0x7); + add_str(")"); + return; + } + disassemble_rv64c(); +} + +static void disassemble_rv32(void) { + disassemble_rv32i(); + if (buf_pos > 0) return; + disassemble_rv32a(); + if (buf_pos > 0) return; + disassemble_rv32m(); + if (buf_pos > 0) return; + disassemble_rv32f(); + if (buf_pos > 0) return; + disassemble_rv_z(); +} + +static void disassemble_rv64(void) { + disassemble_rv64i(); + if (buf_pos > 0) return; + disassemble_rv64a(); + if (buf_pos > 0) return; + disassemble_rv64m(); + if (buf_pos > 0) return; + disassemble_rv64f(); + if (buf_pos > 0) return; + disassemble_rv_z(); +} + +static void disassemble_rv128(void) { + disassemble_rv128i(); + if (buf_pos > 0) return; + disassemble_rv64a(); + if (buf_pos > 0) return; + disassemble_rv128m(); + if (buf_pos > 0) return; + disassemble_rv128f(); + if (buf_pos > 0) return; + disassemble_rv_z(); +} + +static DisassemblyResult * disassemble_riscv(uint8_t * code, + ContextAddress addr, ContextAddress size, + DisassemblerParams * disass_params) { + static DisassemblyResult dr; + + if (size == 0) return NULL; + memset(&dr, 0, sizeof(dr)); + buf_pos = 0; + instr = 0; + instr_addr = addr; + params = disass_params; + + if ((*code & 3) == 3) { + if (size < 4) return NULL; + instr = (uint32_t)code[0] + ((uint32_t)code[1] << 8) + ((uint32_t)code[2] << 16) + ((uint32_t)code[3] << 24); + dr.size = 4; + if (xlen == 32) disassemble_rv32(); + if (xlen == 64) disassemble_rv64(); + if (xlen == 128) disassemble_rv128(); + } + else { + if (size < 2) return NULL; + instr = (uint32_t)code[0] + ((uint32_t)code[1] << 8); + dr.size = 2; + if (xlen == 32) disassemble_rv32c(); + if (xlen == 64) disassemble_rv64c(); + if (xlen == 128) disassemble_rv128c(); + } + + dr.text = buf; + if (buf_pos == 0) { + if (dr.size == 2) { + snprintf(buf, sizeof(buf), ".half 0x%04x", (unsigned)instr); + } + else { + snprintf(buf, sizeof(buf), ".word 0x%08x", (unsigned)instr); + } + } + else { + buf[buf_pos] = 0; + } + return &dr; +} + +DisassemblyResult * disassemble_riscv32(uint8_t * code, + ContextAddress addr, ContextAddress size, + DisassemblerParams * disass_params) { + xlen = 32; + return disassemble_riscv(code, addr, size, disass_params); +} + +DisassemblyResult * disassemble_riscv64(uint8_t * code, + ContextAddress addr, ContextAddress size, + DisassemblerParams * disass_params) { + xlen = 64; + return disassemble_riscv(code, addr, size, disass_params); +} + +DisassemblyResult * disassemble_riscv128(uint8_t * code, + ContextAddress addr, ContextAddress size, + DisassemblerParams * disass_params) { + xlen = 128; + return disassemble_riscv(code, addr, size, disass_params); +} + +#endif /* SERVICE_Disassembly */ diff --git a/agent/machine/riscv/tcf/disassembler-riscv.h b/agent/machine/riscv/tcf/disassembler-riscv.h new file mode 100644 index 00000000..c21e15d7 --- /dev/null +++ b/agent/machine/riscv/tcf/disassembler-riscv.h @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2019 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#ifndef D_disassembler_riscv +#define D_disassembler_riscv + +#include <tcf/config.h> + +#include <tcf/services/disassembly.h> + +extern DisassemblyResult * disassemble_riscv32(uint8_t * buf, + ContextAddress addr, ContextAddress size, DisassemblerParams * params); + +extern DisassemblyResult * disassemble_riscv64(uint8_t * buf, + ContextAddress addr, ContextAddress size, DisassemblerParams * params); + +extern DisassemblyResult * disassemble_riscv128(uint8_t * buf, + ContextAddress addr, ContextAddress size, DisassemblerParams * params); + +#endif /* D_disassembler_riscv */ diff --git a/agent/machine/riscv/tcf/stack-crawl-riscv.c b/agent/machine/riscv/tcf/stack-crawl-riscv.c new file mode 100644 index 00000000..6b3ec821 --- /dev/null +++ b/agent/machine/riscv/tcf/stack-crawl-riscv.c @@ -0,0 +1,1505 @@ +/******************************************************************************* +* Copyright (c) 2019-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. +* 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: +* Xilinx - initial API and implementation +*******************************************************************************/ + +/* +* This module implements stack crawl for RISC-V processor. +*/ + +#include <tcf/config.h> + +#if ENABLE_DebugContext + +#include <assert.h> +#include <tcf/framework/trace.h> +#include <tcf/framework/context.h> +#include <tcf/framework/myalloc.h> +#include <machine/riscv/tcf/uxlen.h> +#include <machine/riscv/tcf/stack-crawl-riscv.h> + +#define MEM_HASH_SIZE 61 +#define REG_DATA_SIZE 32 +#define BRANCH_LIST_SIZE 12 + +#define REG_VAL_FRAME 1 +#define REG_VAL_ADDR 2 +#define REG_VAL_STACK 3 +#define REG_VAL_OTHER 4 + +#define REG_ID_RA 1 +#define REG_ID_SP 2 + +#define MAX_INST 200 + +typedef struct { + int_xlen_t v[MEM_HASH_SIZE]; /* Value */ + int_xlen_t a[MEM_HASH_SIZE]; /* Address */ + uint8_t size[MEM_HASH_SIZE]; + uint8_t valid[MEM_HASH_SIZE]; +} MemData; + +typedef struct { + int_xlen_t v; + unsigned o; +} RegData; + +typedef struct { + int_xlen_t addr; + RegData reg_data[REG_DATA_SIZE]; + RegData pc_data; + MemData mem_data; +} BranchData; + +static Context * stk_ctx = NULL; +static StackFrame * stk_frame = NULL; +static MemData mem_data; +static RegData reg_data[REG_DATA_SIZE]; +static RegData pc_data; +static RegData mepc_data; +static RegData sepc_data; +static RegData uepc_data; + +static uint32_t instr; + +static unsigned branch_pos = 0; +static unsigned branch_cnt = 0; +static BranchData branch_data[BRANCH_LIST_SIZE]; + +static int trace_return = 0; +static int trace_branch = 0; + +typedef struct { + ContextAddress addr; + size_t size; + uint8_t data[64]; +} MemCache; + +#define MEM_CACHE_SIZE 8 +static MemCache mem_cache[MEM_CACHE_SIZE]; +static unsigned mem_cache_idx = 0; + +static const int imm_bits_w[32] = { 6, 10, 11, 12, 5 }; +static const int imm_bits_d[32] = { 10, 11, 12, 5, 6 }; +static const int imm_bits_q[32] = { 11, 12, 5, 6, 10 }; + +static const int imm_bits_lw_sp[32] = { 4, 5, 6, 12, 2, 3 }; +static const int imm_bits_ld_sp[32] = { 5, 6, 12, 2, 3, 4 }; +static const int imm_bits_lq_sp[32] = { 6, 12, 2, 3, 4, 5 }; +static const int imm_bits_sw_sp[32] = { 9, 10, 11, 12, 7, 8 }; +static const int imm_bits_sd_sp[32] = { 10, 11, 12, 7, 8, 9 }; +static const int imm_bits_sq_sp[32] = { 11, 12, 7, 8, 9, 10 }; + +static const int imm_bits_s[32] = { 7, 8, 9, 10, 11, 25, 26, 27, 28, 29, 30, 31 }; +static const int imm_bits_b[32] = { 8, 9, 10, 11, 25, 26, 27, 28, 29, 30, 7, 31 }; +static const int imm_bits_j[32] = { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 20, 12, 13, 14, 15, 16, 17, 18, 19, 31 }; +static const int imm_bits_jc[32] = { 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12 }; +static const int imm_bits_bc[32] = { 3, 4, 10, 11, 2, 5, 6, 12 }; + +static const int imm_bits_addi_sp[32] = { 6, 2, 5, 3, 4, 12 }; +static const int imm_bits_addi_spn[32] = { 6, 5, 11, 12, 7, 8, 9, 10 }; +static const int imm_bits_shift[32] = { 2, 3, 4, 5, 6, 12 }; + +static int read_reg128(StackFrame * frame, RegisterDefinition * reg_def, int_xlen_t * v); + +static int read_mem(ContextAddress address, void * buf, size_t size) { +#if ENABLE_MemoryAccessModes + static MemoryAccessMode mem_access_mode = { 0, 0, 0, 0, 0, 0, 1 }; + return context_read_mem_ext(stk_ctx, &mem_access_mode, address, buf, size); +#else + return context_read_mem(stk_ctx, address, buf, size); +#endif +} + +static int read_byte(int_xlen_t addr, uint8_t * bt) { + unsigned i = 0; + MemCache * c = NULL; + ContextAddress ca = 0; + + addr = fix_sign(addr, xlen, 0); + if (int_xlen_to_h(addr) != 0) { + /* TODO: 128-bit memory address */ + errno = ERR_INV_ADDRESS; + return -1; + } + ca = (ContextAddress)int_xlen_to_l(addr); + if (ca == 0) { + errno = ERR_INV_ADDRESS; + return -1; + } + for (i = 0; i < MEM_CACHE_SIZE; i++) { + c = mem_cache + mem_cache_idx; + if (c->addr <= ca && (c->addr + c->size < c->addr || c->addr + c->size > ca)) { + *bt = c->data[ca - c->addr]; + return 0; + } + mem_cache_idx = (mem_cache_idx + 1) % MEM_CACHE_SIZE; + } + mem_cache_idx = (mem_cache_idx + 1) % MEM_CACHE_SIZE; + c = mem_cache + mem_cache_idx; + c->addr = ca; + c->size = sizeof(c->data); + if (read_mem(ca, c->data, c->size) < 0) { +#if ENABLE_ExtendedMemoryErrorReports + int error = errno; + MemoryErrorInfo info; + if (context_get_mem_error_info(&info) < 0 || info.size_valid == 0) { + c->size = 0; + errno = error; + return -1; + } + c->size = info.size_valid; +#else + c->size = 0; + return -1; +#endif + } + *bt = c->data[0]; + return 0; +} + +static int read_u16(int_xlen_t addr, uint16_t * w) { + unsigned i; + uint16_t n = 0; + for (i = 0; i < 2; i++) { + uint8_t bt = 0; + if (read_byte(int_xlen_add_u(addr, i), &bt) < 0) return -1; + n |= (uint32_t)bt << (i * 8); + } + *w = n; + return 0; +} + +static int read_u32(int_xlen_t addr, uint32_t * w) { + unsigned i; + uint32_t n = 0; + for (i = 0; i < 4; i++) { + uint8_t bt = 0; + if (read_byte(int_xlen_add_u(addr, i), &bt) < 0) return -1; + n |= (uint32_t)bt << (i * 8); + } + *w = n; + return 0; +} + +static int read_u64(int_xlen_t addr, uint64_t * w) { + unsigned i; + uint64_t n = 0; + for (i = 0; i < 8; i++) { + uint8_t bt = 0; + if (read_byte(int_xlen_add_u(addr, i), &bt) < 0) return -1; + n |= (uint64_t)bt << (i * 8); + } + *w = n; + return 0; +} + +static int read_u128(int_xlen_t addr, int_xlen_t * v) { + uint64_t l = 0; + uint64_t h = 0; + if (read_u64(addr, &l) < 0) return -1; + if (read_u64(int_xlen_add_u(addr, 8), &h) < 0) return -1; + *v = int_xlen_from_u2(l, h); + return 0; +} + +static int mem_hash_index(const int_xlen_t addr) { + int v = (int)(int_xlen_to_l(addr) % MEM_HASH_SIZE); + int s = v; + + do { + /* Check if the element is occupied */ + if (mem_data.size[s]) { + /* Check if it is occupied with the sought data */ + if (int_xlen_cmpu(mem_data.a[s], addr) == 0) return s; + } + else { + /* Item is free, this is where the item should be stored */ + return s; + } + + /* Search the next entry */ + s++; + if (s >= MEM_HASH_SIZE) s = 0; + } + while (s != v); + + /* Search failed, hash is full and the address not stored */ + errno = ERR_OTHER; + return -1; +} + +static int mem_hash_read(const int_xlen_t addr, int_xlen_t * v, unsigned bytes, int * valid) { + int i = mem_hash_index(addr); + + if (i >= 0 && mem_data.size[i] && int_xlen_cmpu(mem_data.a[i], addr) == 0) { + *valid = mem_data.valid[i] && mem_data.size[i] >= bytes; + *v = mem_data.v[i]; + return 0; + } + + /* Address not found in the hash */ + errno = ERR_OTHER; + return -1; +} + +static int load_reg_from_mem(const int_xlen_t addr, RegData * r, unsigned bits) { + uint8_t v8 = 0; + uint16_t v16 = 0; + uint32_t v32 = 0; + uint64_t v64 = 0; + memset(r, 0, sizeof(RegData)); + switch (bits) { + case 8: + if (read_byte(addr, &v8) < 0) return -1; + r->v = int_xlen_from_u(v8); + break; + case 16: + if (read_u16(addr, &v16) < 0) return -1; + r->v = int_xlen_from_u(v16); + break; + case 32: + if (read_u32(addr, &v32) < 0) return -1; + r->v = int_xlen_from_u(v32); + break; + case 64: + if (read_u64(addr, &v64) < 0) return -1; + r->v = int_xlen_from_u(v64); + break; + case 128: + if (read_u128(addr, &r->v) < 0) return -1; + break; + default: + errno = ERR_UNSUPPORTED; + return -1; + } + r->o = REG_VAL_OTHER; + return 0; +} + +static int load_reg(const int_xlen_t addr, RegData * r, unsigned bits) { + int valid = 0; + + /* Check if the value can be found in the hash */ + if (mem_hash_read(addr, &r->v, bits >> 3, &valid) == 0) { + if (valid) { + r->v = fix_sign(r->v, bits, 1); + r->o = REG_VAL_OTHER; + return 0; + } + memset(r, 0, sizeof(RegData)); + } + else { + /* Not in the hash, so read from real memory */ + if (load_reg_from_mem(addr, r, bits) < 0) return -1; + r->v = fix_sign(r->v, bits, 1); + } + return 0; +} + +static int load_reg_lazy(int_xlen_t addr, unsigned r, unsigned bits, int sign) { + int valid = 0; + if (mem_hash_read(addr, ®_data[r].v, bits >> 3, &valid) == 0) { + if (valid) { + reg_data[r].v = fix_sign(reg_data[r].v, bits, sign); + reg_data[r].o = REG_VAL_OTHER; + return 0; + } + memset(reg_data + r, 0, sizeof(RegData)); + return 0; + } + if (bits == xlen) { + reg_data[r].o = REG_VAL_ADDR; + reg_data[r].v = addr; + return 0; + } + if (load_reg_from_mem(addr, reg_data + r, bits) < 0) return -1; + reg_data[r].v = fix_sign(reg_data[r].v, bits, sign); + return 0; +} + +static int chk_reg_loaded(RegData * r) { + if (r->o == 0) return 0; + if (r->o == REG_VAL_OTHER) return 0; + if (r->o == REG_VAL_FRAME) { + RegisterDefinition * def = get_reg_definitions(stk_ctx) + int_xlen_to_l(r->v); + if (read_reg128(stk_frame, def, &r->v) < 0) { + if (stk_frame->is_top_frame) return -1; + r->o = 0; + return 0; + } + r->o = REG_VAL_OTHER; + return 0; + } + return load_reg(r->v, r, xlen); +} + +static int chk_loaded(unsigned r) { + return chk_reg_loaded(reg_data + r); +} + +static int mem_hash_write(int_xlen_t addr, int_xlen_t v, unsigned bytes, int valid) { + int n = mem_hash_index(addr); + unsigned i; + + if (n < 0) { + set_errno(ERR_OTHER, "Memory hash overflow"); + return -1; + } + + /* Fix lazy loaded registers */ + for (i = 0; i < REG_DATA_SIZE; i++) { + if (reg_data[i].o != REG_VAL_ADDR && reg_data[i].o != REG_VAL_STACK) continue; + if (int_xlen_cmpu(reg_data[i].v, int_xlen_add_u(addr, xlen >> 3)) >= 0) continue; + if (int_xlen_cmpu(int_xlen_add_u(reg_data[i].v, xlen >> 3), addr) <= 0) continue; + if (load_reg(reg_data[i].v, reg_data + i, xlen) < 0) return -1; + } + + /* Store the item */ + mem_data.a[n] = addr; + mem_data.v[n] = v; + mem_data.size[n] = (uint8_t)bytes; + mem_data.valid[n] = (uint8_t)valid; + return 0; +} + +static int store_reg(int_xlen_t addr, unsigned r, unsigned bits) { + if (chk_loaded(r) < 0) return -1; + assert(reg_data[r].o == 0 || reg_data[r].o == REG_VAL_OTHER); + return mem_hash_write(addr, reg_data[r].v, bits >> 3, reg_data[r].o != 0); +} + +static uint32_t get_imm(const int * bits) { + unsigned i; + uint32_t v = 0; + for (i = 0; i < 32 && bits[i]; i++) { + if (instr & (1u << bits[i])) v |= 1u << i; + } + return v; +} + +static int32_t get_imm_se(const int * bits) { + unsigned i; + uint32_t v = 0; + for (i = 0; i < 32 && bits[i]; i++) { + if (instr & (1u << bits[i])) v |= 1u << i; + } + if (v & (1u << (i - 1))) v |= ~((1u << i) - 1); + return v; +} + +static int32_t get_imm_rse(unsigned pos, unsigned bits) { + uint32_t v = (instr >> pos) & ((1u << bits) - 1); + if (v & (1u << (bits - 1))) v |= ~((1u << bits) - 1); + return v; +} + +static void add_branch(int_xlen_t addr) { + if (branch_cnt < BRANCH_LIST_SIZE) { + int add = 1; + unsigned i = 0; + addr = fix_sign(addr, xlen, 1); + for (i = 0; i < branch_cnt; i++) { + BranchData * b = branch_data + i; + if (int_xlen_cmpu(b->addr, addr) == 0) { + add = 0; + break; + } + } + if (add) { + BranchData * b = branch_data + branch_cnt++; + b->addr = addr; + b->mem_data = mem_data; + memcpy(b->reg_data, reg_data, sizeof(reg_data)); + b->pc_data.o = REG_VAL_OTHER; + b->pc_data.v = addr; + } + } +} + +static int trace_rv32i(void) { + unsigned func = (instr >> 12) & 7; + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + if ((instr & 0x0000007f) == 0x00000037) { /* lui */ + if (rd != 0) { + int64_t imm = (int32_t)(instr & 0xfffff000); + reg_data[rd].v = int_xlen_from_i(imm); + reg_data[rd].o = REG_VAL_OTHER; + } + return 0; + } + if ((instr & 0x0000007f) == 0x00000017) { /* auipc */ + if (rd != 0) { + int64_t imm = (int32_t)(instr & 0xfffff000); + reg_data[rd].v = int_xlen_add(pc_data.v, int_xlen_from_i(imm)); + reg_data[rd].o = REG_VAL_OTHER; + } + return 0; + } + if ((instr & 0x0000007f) == 0x0000006f) { /* j, jal */ + int32_t imm = get_imm_se(imm_bits_j); + if (rd == 0) { + add_branch(int_xlen_add_i(pc_data.v, (int64_t)imm << 1)); + trace_branch = 1; + } + else { + reg_data[rd].v = int_xlen_add_u(pc_data.v, 4); + reg_data[rd].o = pc_data.o; + } + return 0; + } + if ((instr & 0x0000707f) == 0x00000067) { /* jalr */ + int32_t imm = instr >> 20; + if (rd == 0) { + if (imm == 0 && rs1 == 1) { /* ret */ + pc_data = reg_data[1]; + trace_return = 1; + return 0; + } + if (reg_data[rs1].o) add_branch(reg_data[rs1].v); + trace_branch = 1; + return 0; + } + reg_data[rd].v = int_xlen_add_u(pc_data.v, 4); + reg_data[rd].o = pc_data.o; + return 0; + } + if ((instr & 0x0000007f) == 0x00000063) { /* conditional branch */ + int32_t imm = get_imm_se(imm_bits_b); + add_branch(int_xlen_add_i(pc_data.v, (int64_t)imm << 1)); + return 0; + } + if ((instr & 0x0000007f) == 0x00000003) { + if (func <= 2 || func == 4 || func == 5) { + if (rd != 0) { + int32_t imm = get_imm_rse(20, 12); + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + int_xlen_t addr = int_xlen_add_i(reg_data[rs1].v, imm); + switch (func) { + case 0: + /* lb */ + return load_reg_lazy(addr, rd, 8, 1); + case 1: + /* lh */ + return load_reg_lazy(addr, rd, 16, 1); + case 2: + /* lw */ + return load_reg_lazy(addr, rd, 32, 1); + case 4: + /* lbu */ + return load_reg_lazy(addr, rd, 8, 0); + case 5: + /* lhu */ + return load_reg_lazy(addr, rd, 16, 0); + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if ((instr & 0x0000007f) == 0x00000023) { + if (func <= 2) { + int32_t imm = get_imm_se(imm_bits_s); + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + int_xlen_t addr = int_xlen_add_i(reg_data[rs1].v, imm); + switch (func) { + case 0: + /* sb */ + return store_reg(addr, rs2, 8); + case 1: + /* sh */ + return store_reg(addr, rs2, 16); + case 2: + /* sw */ + return store_reg(addr, rs2, 32); + } + } + return 0; + } + } + if ((instr & 0x0000007f) == 0x00000013) { + if (func != 1 && func != 5) { + if (rd != 0) { + int32_t imm = get_imm_rse(20, 12); + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + switch (func) { + case 0: /* addi */ + reg_data[rd].v = int_xlen_add(reg_data[rs1].v, int_xlen_from_i(imm)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 2: /* slti */ + reg_data[rd].v = int_xlen_from_u(int_xlen_cmpi(reg_data[rs1].v, int_xlen_from_i(imm)) < 0 ? 1 : 0); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 3: /* sltiu */ + reg_data[rd].v = int_xlen_from_u(int_xlen_cmpu(reg_data[rs1].v, int_xlen_from_i(imm)) < 0 ? 1 : 0); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 4: /* xori */ + reg_data[rd].v = int_xlen_xor(reg_data[rs1].v, int_xlen_from_i(imm)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 6: /* ori */ + reg_data[rd].v = int_xlen_or(reg_data[rs1].v, int_xlen_from_i(imm)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 7: /* andi */ + reg_data[rd].v = int_xlen_and(reg_data[rs1].v, int_xlen_from_i(imm)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if ((instr & 0xbe00007f) == 0x00000013) { + if (func == 1 || func == 5) { + if (rd != 0) { + uint32_t imm = (instr >> 20) & 0x1f; + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + switch (func) { + case 1: + reg_data[rd].v = int_xlen_sll(reg_data[rs1].v, imm); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 5: + reg_data[rd].v = instr & (1 << 30) ? + int_xlen_sra(reg_data[rs1].v, imm) : + int_xlen_srl(reg_data[rs1].v, imm); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if ((instr & 0xfe00007f) == 0x00000033) { + if (rd != 0) { + if (chk_loaded(rs1) < 0) return -1; + if (chk_loaded(rs2) < 0) return -1; + if (reg_data[rs1].o && reg_data[rs2].o) { + switch (func) { + case 0: /* add */ + reg_data[rd].v = int_xlen_add(reg_data[rs1].v, reg_data[rs2].v); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 1: /* sll */ + reg_data[rd].v = int_xlen_sll(reg_data[rs1].v, int_xlen_to_l(reg_data[rs2].v) & (xlen - 1)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 2: /* slt */ + reg_data[rd].v = int_xlen_from_u(int_xlen_cmpi(reg_data[rs1].v, reg_data[rs2].v) < 0 ? 1 : 0); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 3: /* sltu */ + reg_data[rd].v = int_xlen_from_u(int_xlen_cmpu(reg_data[rs1].v, reg_data[rs2].v) < 0 ? 1 : 0); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 4: /* xor */ + reg_data[rd].v = int_xlen_xor(reg_data[rs1].v, reg_data[rs2].v); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 5: /* srl */ + reg_data[rd].v = int_xlen_srl(reg_data[rs1].v, int_xlen_to_l(reg_data[rs2].v) & (xlen - 1)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 6: /* or */ + reg_data[rd].v = int_xlen_or(reg_data[rs1].v, reg_data[rs2].v); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 7: /* and */ + reg_data[rd].v = int_xlen_and(reg_data[rs1].v, reg_data[rs2].v); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + reg_data[rd].o = 0; + } + return 0; + } + if ((instr & 0xfe00007f) == 0x40000033) { + if (func == 0 || func == 5) { + if (rd != 0) { + if (chk_loaded(rs1) < 0) return -1; + if (chk_loaded(rs2) < 0) return -1; + switch (func) { + case 0: + reg_data[rd].v = int_xlen_sub(reg_data[rs1].v, reg_data[rs2].v); + reg_data[rd].o = reg_data[rs1].o && reg_data[rs2].o ? REG_VAL_OTHER : 0; + return 0; + case 5: + reg_data[rd].v = int_xlen_sra(reg_data[rs1].v, int_xlen_to_l(reg_data[rs2].v)); + reg_data[rd].o = reg_data[rs1].o && reg_data[rs2].o ? REG_VAL_OTHER : 0; + return 0; + } + } + return 0; + } + } + if ((instr & 0x0000707f) == 0x0000000f) { + unsigned p = (instr >> 24) & 0xf; + unsigned s = (instr >> 20) & 0xf; + if (p != 0 && s != 0) { + /* fence - no register changes */ + return 0; + } + } + if (instr == 0x00000073) { + /* ecall */ + return 0; + } + if (instr == 0x00100073) { + /* ebreak - no register changes */ + return 0; + } + if ((instr & 0x0fffffff) == 0x00200073) { + switch (instr >> 28) { + case 0: /* uret */ + pc_data = uepc_data; + trace_return = 1; + return 0; + case 1: /* sret */ + pc_data = sepc_data; + trace_return = 1; + return 0; + case 3: /* mret */ + pc_data = mepc_data; + trace_return = 1; + return 0; + } + } + if (instr == 0x10500073) { + /* wfi - no register changes */ + return 0; + } + if ((instr & 0xfe007fff) == 0x12000073) { + /* sfence.vma - no register changes */ + return 0; + } + return 0; +} + +static int trace_rv32(void) { + if (trace_rv32i() < 0) return -1; + return 0; +} + +static int trace_rv64i(void) { + unsigned func = (instr >> 12) & 7; + unsigned rs2 = (instr >> 20) & 0x1f; + unsigned rs1 = (instr >> 15) & 0x1f; + unsigned rd = (instr >> 7) & 0x1f; + if ((instr & 0x0000007f) == 0x00000003) { + if (func == 3 || func == 6) { + if (rd != 0) { + int32_t imm = get_imm_rse(20, 12); + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + int_xlen_t addr = int_xlen_add_i(reg_data[rs1].v, imm); + switch (func) { + case 3: + /* ld */ + return load_reg_lazy(addr, rd, 64, 1); + case 6: + /* lwu */ + return load_reg_lazy(addr, rd, 32, 0); + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if ((instr & 0x0000007f) == 0x00000023) { + if (func == 3) { /* sd */ + int32_t imm = get_imm_se(imm_bits_s); + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + int_xlen_t addr = int_xlen_add_i(reg_data[rs1].v, imm); + return store_reg(addr, rs2, 64); + } + return 0; + } + } + if ((instr & 0xbc00007f) == 0x00000013) { + if (func == 1 || func == 5) { + if (rd != 0) { + uint32_t imm = (instr >> 20) & 0x3f; + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + switch (func) { + case 1: + reg_data[rd].v = int_xlen_sll(reg_data[rs1].v, imm); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 5: + reg_data[rd].v = instr & (1 << 30) ? + int_xlen_sra(reg_data[rs1].v, imm) : + int_xlen_srl(reg_data[rs1].v, imm); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if ((instr & 0x0000707f) == 0x0000001b) { /* addiw */ + if (rd != 0) { + int32_t imm = get_imm_rse(20, 12); + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + reg_data[rd].v = fix_sign(int_xlen_add_i(reg_data[rs1].v, imm), 32, 1); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + reg_data[rd].o = 0; + } + return 0; + } + if ((instr & 0xbe00007f) == 0x0000001b) { + if (func == 1 || func == 5) { + if (rd != 0) { + uint32_t imm = (instr >> 20) & 0x1f; + if (chk_loaded(rs1) < 0) return -1; + if (reg_data[rs1].o) { + switch (func) { + case 1: + reg_data[rd].v = fix_sign(int_xlen_sll(reg_data[rs1].v, imm), 32, 1); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 5: + if (instr & (1 << 30)) { + reg_data[rd].v = int_xlen_sra(fix_sign(reg_data[rs1].v, 32, 1), imm); + } + else { + reg_data[rd].v = int_xlen_srl(fix_sign(reg_data[rs1].v, 32, 0), imm); + } + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if ((instr & 0xfe00007f) == 0x0000003b) { + if (func == 0 || func == 1 || func == 5) { + if (rd != 0) { + if (chk_loaded(rs1) < 0) return -1; + if (chk_loaded(rs2) < 0) return -1; + if (reg_data[rs1].o && reg_data[rs2].o) { + switch (func) { + case 0: /* addw */ + reg_data[rd].v = fix_sign(int_xlen_add(reg_data[rs1].v, reg_data[rs2].v), 32, 1); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 1: /* sllw */ + reg_data[rd].v = fix_sign(int_xlen_sll(reg_data[rs1].v, int_xlen_to_l(reg_data[rs2].v) & (xlen - 1)), 32, 1); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 5: /* srlw */ + reg_data[rd].v = int_xlen_srl(fix_sign(reg_data[rs1].v, 32, 0), int_xlen_to_l(reg_data[rs2].v) & (xlen - 1)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if ((instr & 0xfe00007f) == 0x4000003b) { + if (func == 0 || func == 5) { + if (rd != 0) { + if (chk_loaded(rs1) < 0) return -1; + if (chk_loaded(rs2) < 0) return -1; + if (reg_data[rs1].o && reg_data[rs2].o) { + switch (func) { + case 0: /* subw */ + reg_data[rd].v = fix_sign(int_xlen_sub(reg_data[rs1].v, reg_data[rs2].v), 32, 1); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + case 5: /* sraw */ + reg_data[rd].v = int_xlen_sra(fix_sign(reg_data[rs1].v, 32, 1), int_xlen_to_l(reg_data[rs2].v) & (xlen - 1)); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + reg_data[rd].o = 0; + } + return 0; + } + } + if (trace_rv32i() < 0) return -1; + return 0; +} + + + +static int trace_rv64(void) { + if (trace_rv64i() < 0) return -1; + return 0; +} + +static int trace_rv128(void) { + if (trace_rv64i() < 0) return -1; + return 0; +} + +static int trace_rv32c(void) { + /* Quadrant 0 */ + if ((instr & 0xffff) == 0x0000) { + set_errno(ERR_OTHER, "Illegal instruction"); + return -1; + } + if ((instr & 0xe003) == 0x0000) { + uint32_t imm = get_imm(imm_bits_addi_spn); + if (imm != 0) { + unsigned rd = ((instr >> 2) & 0x7) + 8; + if (chk_loaded(REG_ID_SP) < 0) return -1; + reg_data[rd].v = int_xlen_add_u(reg_data[REG_ID_SP].v, imm * 4); + reg_data[rd].o = reg_data[REG_ID_SP].o; + return 0; + } + } + if ((instr & 0x6003) == 0x2000) { + /* FP registers are not traced */ + return 0; + } + if ((instr & 0x6003) == 0x4000) { + unsigned rd = ((instr >> 2) & 0x7) + 8; + unsigned rs = ((instr >> 7) & 0x7) + 8; + int ld = (instr & 0x8000) == 0; + if (chk_loaded(rs) < 0) return -1; + if (reg_data[rs].o) { + uint32_t imm = get_imm(imm_bits_w); + int_xlen_t addr = int_xlen_add_u(reg_data[rs].v, imm * 4); + if (ld) { + if (load_reg_lazy(addr, rd, 32, 1) < 0) return -1; + } + else { + if (store_reg(addr, rd, 32) < 0) return -1; + } + return 0; + } + if (ld) reg_data[rd].o = 0; + return 0; + } + if ((instr & 0x6003) == 0x6000) { + /* FP registers are not traced */ + return 0; + } + + /* Quadrant 1 */ + if ((instr & 0xef83) == 0x0001) { + /* nop */ + return 0; + } + if ((instr & 0xe003) == 0x0001) { /* addi */ + int32_t imm = get_imm_se(imm_bits_shift); + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + if (chk_loaded(rd) < 0) return -1; + reg_data[rd].v = int_xlen_add_i(reg_data[rd].v, imm); + return 0; + } + } + if ((instr & 0x6003) == 0x2001) { /* j, jal */ + int32_t imm = get_imm_se(imm_bits_jc); + if (instr & 0x8000) { + add_branch(int_xlen_add_i(pc_data.v, (int64_t)imm << 1)); + trace_branch = 1; + } + else { + reg_data[REG_ID_RA].v = int_xlen_add_u(pc_data.v, 2); + reg_data[REG_ID_RA].o = pc_data.o; + } + return 0; + } + if ((instr & 0xe003) == 0x4001) { + int32_t imm = get_imm_se(imm_bits_shift); + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + reg_data[rd].v = int_xlen_from_i(imm); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + if ((instr & 0xe003) == 0x6001) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd == 2) { + int32_t imm = get_imm_se(imm_bits_addi_sp); + if (imm != 0) { + reg_data[REG_ID_SP].v = int_xlen_add_i(reg_data[REG_ID_SP].v, imm << 4); + return 0; + } + } + if (rd != 0) { + int32_t imm = get_imm_se(imm_bits_shift); + if (imm != 0) { + reg_data[rd].v = int_xlen_from_i(imm << 12); + reg_data[rd].o = REG_VAL_OTHER; + return 0; + } + } + } + if ((instr & 0xe003) == 0x8001) { + unsigned rd = ((instr >> 7) & 0x7) + 8; + unsigned func = (instr >> 10) & 3; + if (func < 2) { + uint32_t imm = get_imm(imm_bits_shift); + if (xlen == 32 && imm >= 32) return 0; + if (imm == 0) { + if (xlen == 128) imm = 64; + else return 0; + } + if (chk_loaded(rd) < 0) return -1; + reg_data[rd].v = func ? int_xlen_sra(reg_data[rd].v, imm) : int_xlen_srl(reg_data[rd].v, imm); + } + else if (func == 2) { + int32_t imm = get_imm_se(imm_bits_shift); + if (chk_loaded(rd) < 0) return -1; + reg_data[rd].v = int_xlen_and(reg_data[rd].v, int_xlen_from_i(imm)); + } + else if ((instr & (1 << 12)) == 0) { + unsigned rs = ((instr >> 2) & 0x7) + 8; + if (chk_loaded(rd) < 0) return -1; + if (chk_loaded(rs) < 0) return -1; + switch ((instr >> 5) & 3) { + case 0: + reg_data[rd].v = int_xlen_sub(reg_data[rd].v, reg_data[rs].v); + break; + case 1: + reg_data[rd].v = int_xlen_xor(reg_data[rd].v, reg_data[rs].v); + break; + case 2: + reg_data[rd].v = int_xlen_or(reg_data[rd].v, reg_data[rs].v); + break; + case 3: + reg_data[rd].v = int_xlen_and(reg_data[rd].v, reg_data[rs].v); + break; + } + reg_data[rd].o = reg_data[rd].o && reg_data[rs].o ? REG_VAL_OTHER : 0; + } + return 0; + } + if ((instr & 0xc003) == 0xc001) { + int32_t imm = get_imm_se(imm_bits_bc); + add_branch(int_xlen_add_i(pc_data.v, imm << 1)); + return 0; + } + + /* Quadrant 2 */ + if ((instr & 0xe003) == 0x4002) { /* lw */ + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + if (chk_loaded(REG_ID_SP) < 0) return -1; + if (reg_data[REG_ID_SP].o) { + uint32_t imm = get_imm(imm_bits_lw_sp); + return load_reg_lazy(int_xlen_add_u(reg_data[REG_ID_SP].v, imm * 4), rd, 32, 1); + } + reg_data[rd].o = 0; + return 0; + } + } + if ((instr & 0xe003) == 0x6002) { + /* FP registers are not traced */ + return 0; + } + if ((instr & 0xe003) == 0x2002) { + /* FP registers are not traced */ + return 0; + } + if ((instr & 0xe003) == 0xc002) { + unsigned rd = (instr >> 2) & 0x1f; + if (chk_loaded(REG_ID_SP) < 0) return -1; + if (reg_data[REG_ID_SP].o) { + uint32_t imm = get_imm(imm_bits_sw_sp); + if (store_reg(int_xlen_add_u(reg_data[REG_ID_SP].v, imm * 4), rd, 32) < 0) return -1; + } + return 0; + } + if ((instr & 0xe003) == 0xe002) { + /* FP registers are not traced */ + return 0; + } + if ((instr & 0xe003) == 0xa002) { + /* FP registers are not traced */ + return 0; + } + if ((instr & 0xe003) == 0x0002) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + uint32_t imm = get_imm(imm_bits_shift); + if (xlen == 32 && imm >= 32) return 0; + if (imm == 0) { + if (xlen == 128) imm = 64; + else return 0; + } + if (chk_loaded(rd) < 0) return -1; + reg_data[rd].v = int_xlen_sll(reg_data[rd].v, imm); + return 0; + } + } + if ((instr & 0xe003) == 0x8002) { + unsigned rd = (instr >> 7) & 0x1f; + unsigned rs = (instr >> 2) & 0x1f; + if ((instr & (1 << 12)) == 0) { + if (rd == 0) return 0; + if (rs == 0) { + if (chk_loaded(rd) < 0) return -1; + if (rd == REG_ID_RA) { + pc_data = reg_data[rd]; + trace_return = 1; + return 0; + } + if (reg_data[rd].o) add_branch(reg_data[rd].v); + trace_branch = 1; + return 0; + } + if (chk_loaded(rs) < 0) return -1; + reg_data[rd] = reg_data[rs]; + return 0; + } + if (rd == 0 && rs == 0) { + /* ebreak */ + return 0; + } + if (rd == 0) return 0; + if (rs == 0) { + reg_data[REG_ID_RA].v = int_xlen_add_u(pc_data.v, 2); + reg_data[REG_ID_RA].o = pc_data.o; + return 0; + } + if (chk_loaded(rd) < 0) return -1; + if (chk_loaded(rs) < 0) return -1; + reg_data[rd].v = int_xlen_add(reg_data[rd].v, reg_data[rs].v); + reg_data[rd].o = reg_data[rd].o && reg_data[rs].o ? REG_VAL_OTHER : 0; + return 0; + } + + return 0; +} + +static int trace_rv64c(void) { + if ((instr & 0xe003) == 0x2001) { + int32_t imm = get_imm_se(imm_bits_shift); + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + if (chk_loaded(rd) < 0) return -1; + reg_data[rd].v = int_xlen_add_i(reg_data[rd].v, imm); + return 0; + } + } + if ((instr & 0xe003) == 0x6002) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + if (chk_loaded(REG_ID_SP) < 0) return -1; + if (reg_data[REG_ID_SP].o) { + uint32_t imm = get_imm(imm_bits_ld_sp); + return load_reg_lazy(int_xlen_add_u(reg_data[REG_ID_SP].v, imm * 8), rd, 64, 1); + } + reg_data[rd].o = 0; + return 0; + } + } + if ((instr & 0xe003) == 0xe002) { + unsigned rd = (instr >> 2) & 0x1f; + if (chk_loaded(REG_ID_SP) < 0) return -1; + if (reg_data[REG_ID_SP].o) { + uint32_t imm = get_imm(imm_bits_sd_sp); + if (store_reg(int_xlen_add_u(reg_data[REG_ID_SP].v, imm * 8), rd, 64) < 0) return -1; + } + return 0; + } + if ((instr & 0x6003) == 0x6000) { + unsigned rd = ((instr >> 2) & 0x7) + 8; + unsigned rs = ((instr >> 7) & 0x7) + 8; + int ld = (instr & 0x8000) == 0; + if (chk_loaded(rs) < 0) return -1; + if (reg_data[rs].o) { + uint32_t imm = get_imm(imm_bits_d); + int_xlen_t addr = int_xlen_add_u(reg_data[rs].v, imm * 8); + if (ld) { + if (load_reg_lazy(addr, rd, 64, 1) < 0) return -1; + } + else { + if (store_reg(addr, rd, 64) < 0) return -1; + } + return 0; + } + if (ld) reg_data[rd].o = 0; + return 0; + } + if ((instr & 0xfc03) == 0x9c01) { + unsigned rd = ((instr >> 7) & 0x7) + 8; + unsigned rs = ((instr >> 2) & 0x7) + 8; + if (chk_loaded(rd) < 0) return -1; + if (chk_loaded(rs) < 0) return -1; + switch ((instr >> 5) & 3) { + case 0: + reg_data[rd].v = int_xlen_sub(reg_data[rd].v, reg_data[rs].v); + break; + case 1: + reg_data[rd].v = int_xlen_add(reg_data[rd].v, reg_data[rs].v); + break; + default: + return 0; + } + reg_data[rd].o = reg_data[rd].o && reg_data[rs].o ? REG_VAL_OTHER : 0; + return 0; + } + return trace_rv32c(); +} + +static int trace_rv128c(void) { + if ((instr & 0xe003) == 0x2002) { + unsigned rd = (instr >> 7) & 0x1f; + if (rd != 0) { + if (chk_loaded(REG_ID_SP) < 0) return -1; + if (reg_data[REG_ID_SP].o) { + uint32_t imm = get_imm(imm_bits_lq_sp); + return load_reg_lazy(int_xlen_add_u(reg_data[REG_ID_SP].v, imm * 16), rd, 128, 1); + } + reg_data[rd].o = 0; + return 0; + } + } + if ((instr & 0xe003) == 0xa002) { + unsigned rd = (instr >> 2) & 0x1f; + if (chk_loaded(REG_ID_SP) < 0) return -1; + if (reg_data[REG_ID_SP].o) { + uint32_t imm = get_imm(imm_bits_sq_sp); + if (store_reg(int_xlen_add_u(reg_data[REG_ID_SP].v, imm * 16), rd, 128) < 0) return -1; + } + return 0; + } + if ((instr & 0x6003) == 0x2000) { + unsigned rd = ((instr >> 2) & 0x7) + 8; + unsigned rs = ((instr >> 7) & 0x7) + 8; + int ld = (instr & 0x8000) == 0; + if (chk_loaded(rs) < 0) return -1; + if (reg_data[rs].o) { + uint32_t imm = get_imm(imm_bits_q); + int_xlen_t addr = int_xlen_add_u(reg_data[rs].v, imm * 16); + if (ld) { + if (load_reg_lazy(addr, rd, 128, 1) < 0) return -1; + } + else { + if (store_reg(addr, rd, 128) < 0) return -1; + } + return 0; + } + if (ld) reg_data[rd].o = 0; + return 0; + } + return trace_rv64c(); +} + +static int trace_riscv(void) { + assert(pc_data.o != REG_VAL_ADDR); + assert(pc_data.o != REG_VAL_STACK); + + /* Check PC alignment */ + if (int_xlen_to_l(pc_data.v) & 0x1) { + set_errno(ERR_OTHER, "PC misalignment"); + return -1; + } + + /* Read the instruction */ + if (read_u32(pc_data.v, &instr) < 0) return -1; + + if ((instr & 3) == 3) { + if (xlen == 32 && trace_rv32() < 0) return -1; + if (xlen == 64 && trace_rv64() < 0) return -1; + if (xlen == 128 && trace_rv128() < 0) return -1; + if (!trace_return && !trace_branch) pc_data.v = int_xlen_add_u(pc_data.v, 4); + } + else { + instr &= 0xffff; + if (xlen == 32 && trace_rv32c() < 0) return -1; + if (xlen == 64 && trace_rv64c() < 0) return -1; + if (xlen == 128 && trace_rv128c() < 0) return -1; + if (!trace_return && !trace_branch) pc_data.v = int_xlen_add_u(pc_data.v, 2); + } + + return 0; +} + +static int trace_instructions(void) { + unsigned i; + RegData org_pc = pc_data; + RegData org_regs[REG_DATA_SIZE]; + memcpy(org_regs, reg_data, sizeof(org_regs)); + for (;;) { + unsigned t; + BranchData * b = NULL; + if (chk_loaded(REG_ID_SP) < 0) return -1; + trace(LOG_STACK, "Stack crawl: pc %#" PRIx64 ", sp %#" PRIx64, + pc_data.o ? int_xlen_to_l(pc_data.v) : (uint64_t)0, + reg_data[REG_ID_SP].o ? int_xlen_to_l(reg_data[REG_ID_SP].v) : (uint64_t)0); + for (t = 0; t < MAX_INST; t++) { + int error = 0; + trace_return = 0; + trace_branch = 0; + if (pc_data.o != REG_VAL_OTHER) { + error = set_errno(ERR_OTHER, "PC value not available"); + } + else if (int_xlen_cmpu(pc_data.v, int_xlen_from_u(0)) == 0) { + error = set_errno(ERR_OTHER, "PC == 0"); + } + else if (trace_riscv() < 0) { + error = errno; + } + if (!error && trace_return) { + if (chk_loaded(REG_ID_SP) < 0 || !reg_data[REG_ID_SP].o) { + error = set_errno(ERR_OTHER, "Stack crawl: invalid SP value"); + } + } + if (error) { + trace(LOG_STACK, "Stack crawl: %s", errno_to_str(error)); + break; + } + if (trace_return) return 0; + if (trace_branch) break; + } + if (branch_pos >= branch_cnt) break; + b = branch_data + branch_pos++; + memcpy(reg_data, b->reg_data, sizeof(reg_data)); + mem_data = b->mem_data; + pc_data = b->pc_data; + } + trace(LOG_STACK, "Stack crawl: Function epilogue not found"); + for (i = 0; i < REG_DATA_SIZE; i++) reg_data[i].o = 0; + pc_data.o = 0; + + if (pc_data.o == 0) { + if (chk_reg_loaded(&org_pc) < 0) return -1; + if (chk_reg_loaded(org_regs + REG_ID_RA) < 0) return -1; + if (chk_reg_loaded(org_regs + REG_ID_SP) < 0) return -1; + if (int_xlen_cmpu(org_regs[REG_ID_SP].v, int_xlen_from_u(0)) != 0 && + int_xlen_cmpu(org_regs[REG_ID_RA].v, int_xlen_from_u(0)) != 0 && + int_xlen_cmpu(org_pc.v, org_regs[REG_ID_RA].v) != 0) { + pc_data = org_regs[REG_ID_RA]; + } + } + return 0; +} + +static int read_reg128(StackFrame * frame, RegisterDefinition * reg_def, int_xlen_t * v) { + uint8_t buf[16]; + uint64_t l = 0; + uint64_t h = 0; + if (reg_def == NULL) { + set_errno(ERR_INV_CONTEXT, "Invalid register"); + return -1; + } + if (frame == NULL) { + set_errno(ERR_INV_CONTEXT, "Invalid stack frame"); + return -1; + } + if (reg_def->size > sizeof(buf)) { + errno = ERR_INV_DATA_SIZE; + return -1; + } + if (read_reg_bytes(frame, reg_def, 0, reg_def->size, buf) < 0) return -1; + if (v != NULL) { + size_t i; + for (i = 0; i < 8 && i < reg_def->size; i++) { + l = l << 8; + l |= buf[reg_def->big_endian ? i : reg_def->size - i - 1]; + } + } + if (v != NULL) { + size_t i; + for (i = 8; i < reg_def->size; i++) { + h = h << 8; + h |= buf[reg_def->big_endian ? i : reg_def->size - i - 1]; + } + } + *v = int_xlen_from_u2(l, h); + return 0; +} + +static int write_reg128(StackFrame * frame, RegisterDefinition * reg_def, int_xlen_t v) { + size_t i; + uint8_t buf[16]; + uint64_t l = int_xlen_to_l(v); + uint64_t h = int_xlen_to_h(v); + if (reg_def == NULL) { + set_errno(ERR_INV_CONTEXT, "Invalid register"); + return -1; + } + if (frame == NULL) { + set_errno(ERR_INV_CONTEXT, "Invalid stack frame"); + return -1; + } + if (reg_def->size > sizeof(buf)) { + errno = ERR_INV_DATA_SIZE; + return -1; + } + for (i = 0; i < 8 && i < reg_def->size; i++) { + buf[reg_def->big_endian ? reg_def->size - i - 1 : i] = (uint8_t)l; + l = l >> 8; + } + for (i = 8; i < reg_def->size; i++) { + buf[reg_def->big_endian ? reg_def->size - i - 1 : i] = (uint8_t)h; + h = h >> 8; + } + if (write_reg_bytes(frame, reg_def, 0, reg_def->size, buf) < 0) return -1; + if (!frame->is_top_frame) frame->has_reg_data = 1; + return 0; +} + +static int crawl_stack_frame_riscv(StackFrame * frame, StackFrame * down) { + RegisterDefinition * defs = get_reg_definitions(frame->ctx); + RegisterDefinition * def = NULL; + unsigned i; + + if (defs == NULL) { + set_errno(ERR_OTHER, "Context has no registers"); + return -1; + } + + stk_ctx = frame->ctx; + stk_frame = frame; + memset(&mem_data, 0, sizeof(mem_data)); + memset(®_data, 0, sizeof(reg_data)); + memset(&pc_data, 0, sizeof(pc_data)); + memset(&mepc_data, 0, sizeof(mepc_data)); + memset(&sepc_data, 0, sizeof(sepc_data)); + memset(&uepc_data, 0, sizeof(uepc_data)); + branch_pos = 0; + branch_cnt = 0; + + for (i = 0; i < MEM_CACHE_SIZE; i++) mem_cache[i].size = 0; + + for (def = defs; def->name; def++) { + if (def->dwarf_id == 0) { + assert(xlen == def->size * 8); + reg_data[def->dwarf_id].v = int_xlen_from_u(0); + reg_data[def->dwarf_id].o = REG_VAL_OTHER; + } + else if (def->dwarf_id == REG_ID_SP) { + if (read_reg128(frame, def, ®_data[REG_ID_SP].v) < 0) continue; + if (int_xlen_cmpu(reg_data[REG_ID_SP].v, int_xlen_from_u(0)) == 0) return 0; + reg_data[REG_ID_SP].o = REG_VAL_OTHER; + } + else if (def->dwarf_id >= 0 && def->dwarf_id < REG_DATA_SIZE) { + reg_data[def->dwarf_id].v = int_xlen_from_u(def - defs); + reg_data[def->dwarf_id].o = REG_VAL_FRAME; + } + else if (strcmp(def->name, "pc") == 0) { + if (read_reg128(frame, def, &pc_data.v) < 0) continue; + pc_data.o = REG_VAL_OTHER; + } + else if (strcmp(def->name, "mepc") == 0) { + if (read_reg128(frame, def, &mepc_data.v) < 0) continue; + mepc_data.o = REG_VAL_OTHER; + } + else if (strcmp(def->name, "sepc") == 0) { + if (read_reg128(frame, def, &sepc_data.v) < 0) continue; + sepc_data.o = REG_VAL_OTHER; + } + else if (strcmp(def->name, "uepc") == 0) { + if (read_reg128(frame, def, &uepc_data.v) < 0) continue; + uepc_data.o = REG_VAL_OTHER; + } + } + + if (trace_instructions() < 0) return -1; + + for (def = defs; def->name; def++) { + if (def->dwarf_id >= 0 && def->dwarf_id < REG_DATA_SIZE) { + int r = def->dwarf_id; +#if ENABLE_StackRegisterLocations + if (r == REG_ID_SP) { + /* Skip */ + } + else if (reg_data[r].o == REG_VAL_ADDR || reg_data[r].o == REG_VAL_STACK) { + int_xlen_t v; + int valid = 0; + LocationExpressionCommand * cmds = NULL; + if (mem_hash_read(reg_data[r].v, &v, xlen >> 3, &valid) == 0) { + if (valid && write_reg128(down, def, v) < 0) return -1; + continue; + } + cmds = (LocationExpressionCommand *)tmp_alloc_zero(sizeof(LocationExpressionCommand) * 2); + cmds[0].cmd = SFT_CMD_NUMBER; + cmds[0].args.num = int_xlen_to_l(reg_data[r].v); + cmds[1].cmd = SFT_CMD_RD_MEM; + cmds[1].args.mem.size = xlen >> 3; + if (write_reg_location(down, def, cmds, 2) == 0) { + down->has_reg_data = 1; + continue; + } + } + else if (reg_data[r].o == REG_VAL_FRAME) { + LocationExpressionCommand * cmds = (LocationExpressionCommand *)tmp_alloc_zero(sizeof(LocationExpressionCommand)); + cmds[0].cmd = SFT_CMD_RD_REG; + cmds[0].args.reg = defs + int_xlen_to_l(reg_data[r].v); + if (write_reg_location(down, def, cmds, 1) == 0) { + down->has_reg_data = 1; + continue; + } + } +#endif + assert(r != 0 || reg_data[r].o == REG_VAL_OTHER || reg_data[r].o == 0); + assert(r != 0 || int_xlen_to_l(reg_data[r].v) == 0); + if (chk_loaded(r) < 0) continue; + if (!reg_data[r].o) continue; + if (r == REG_ID_SP) frame->fp = (ContextAddress)int_xlen_to_l(reg_data[r].v); + if (write_reg128(down, def, reg_data[r].v) < 0) return -1; + } + else if (strcmp(def->name, "pc") == 0) { + if (chk_reg_loaded(&pc_data) < 0) continue; + if (!pc_data.o) continue; + if (write_reg128(down, def, pc_data.v) < 0) return -1; + } + } + + stk_frame = NULL; + stk_ctx = NULL; + return 0; +} + +int crawl_stack_frame_riscv32(StackFrame * frame, StackFrame * down) { + xlen = 32; + return crawl_stack_frame_riscv(frame, down); +} + +int crawl_stack_frame_riscv64(StackFrame * frame, StackFrame * down) { + xlen = 64; + return crawl_stack_frame_riscv(frame, down); +} + +int crawl_stack_frame_riscv128(StackFrame * frame, StackFrame * down) { + xlen = 128; + return crawl_stack_frame_riscv(frame, down); +} + +#endif /* ENABLE_DebugContext */ diff --git a/agent/machine/riscv/tcf/stack-crawl-riscv.h b/agent/machine/riscv/tcf/stack-crawl-riscv.h new file mode 100644 index 00000000..580d9292 --- /dev/null +++ b/agent/machine/riscv/tcf/stack-crawl-riscv.h @@ -0,0 +1,31 @@ +/******************************************************************************* +* Copyright (c) 2019 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. +* 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: +* Xilinx - initial API and implementation +*******************************************************************************/ + +/* +* This module implements stack crawl for RISC-V processor. +*/ + +#ifndef D_stack_crawl_riscv +#define D_stack_crawl_riscv + +#include <tcf/config.h> + +#include <tcf/framework/cpudefs.h> + +extern int crawl_stack_frame_riscv32(StackFrame * frame, StackFrame * down); +extern int crawl_stack_frame_riscv64(StackFrame * frame, StackFrame * down); +extern int crawl_stack_frame_riscv128(StackFrame * frame, StackFrame * down); + +#endif /* D_stack_crawl_riscv */ diff --git a/agent/machine/riscv/tcf/uxlen.h b/agent/machine/riscv/tcf/uxlen.h new file mode 100644 index 00000000..5c01d3d2 --- /dev/null +++ b/agent/machine/riscv/tcf/uxlen.h @@ -0,0 +1,221 @@ +/******************************************************************************* +* Copyright (c) 2019-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. +* 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: +* Xilinx - initial API and implementation +*******************************************************************************/ + +typedef struct { + uint64_t l; + uint64_t h; +} int_xlen_t; + +static unsigned xlen = 0; + +static int_xlen_t fix_sign(int_xlen_t v, unsigned bits, int sign) { + int_xlen_t mask; + mask.h = 0; + if (bits < 64) { + mask.l = ((uint64_t)1 << bits) - 1; + } + else { + mask.l = ~(uint64_t)0; + if (bits > 64) { + assert(bits == 128); + mask.h = ~(uint64_t)0; + } + } + if (sign) { + if (bits <= 64) sign = (v.l & ((uint64_t)1 << (bits - 1))) != 0; + else sign = (v.h & ((uint64_t)1 << (bits - 65))) != 0; + } + if (sign) { + v.l |= ~mask.l; + v.h |= ~mask.h; + } + else { + v.l &= mask.l; + v.h &= mask.h; + } + return v; +} + +static int int_xlen_cmpu(int_xlen_t x, int_xlen_t y) { + if (xlen > 64) { + if (x.h < y.h) return -1; + if (x.h > y.h) return +1; + } + if (x.l < y.l) return -1; + if (x.l > y.l) return +1; + return 0; +} + +static int int_xlen_cmpi(int_xlen_t x, int_xlen_t y) { + if (xlen > 64) { + if ((int64_t)x.h < (int64_t)y.h) return -1; + if ((int64_t)x.h > (int64_t)y.h) return +1; + } + if ((int64_t)x.l < (int64_t)y.l) return -1; + if ((int64_t)x.l > (int64_t)y.l) return +1; + return 0; +} + +static int_xlen_t int_xlen_neg(int_xlen_t x) { + int_xlen_t z; + z.l = ~x.l + 1; + z.h = ~x.h; + if (z.l < ~x.l) z.h++; + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_add(int_xlen_t x, int_xlen_t y) { + int_xlen_t z; + z.l = x.l + y.l; + z.h = x.h + y.h; + if (z.l < x.l) z.h++; + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_sub(int_xlen_t x, int_xlen_t y) { + int_xlen_t z; + int_xlen_t n = int_xlen_neg(y); + z.l = x.l + n.l; + z.h = x.h + n.h; + if (z.l < x.l) z.h++; + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_from_u(uint64_t x) { + int_xlen_t z; + z.l = x; + z.h = 0; + return z; +} + +static int_xlen_t int_xlen_from_i(int64_t x) { + int_xlen_t z; + z.l = x; + z.h = x < 0 ? (int64_t)-1 : 0; + return z; +} + +static int_xlen_t int_xlen_from_u2(uint64_t x, uint64_t y) { + int_xlen_t z; + z.l = x; + z.h = y; + return z; +} + +#define int_xlen_to_l(x) ((x).l) +#define int_xlen_to_h(x) ((x).h) +#define int_xlen_add_u(x, y) int_xlen_add(x, int_xlen_from_u(y)) +#define int_xlen_add_i(x, y) int_xlen_add(x, int_xlen_from_i(y)) + +static int_xlen_t int_xlen_sll(int_xlen_t x, unsigned y) { + int_xlen_t z; + unsigned i; + z.l = z.h = 0; + for (i = 0; i < xlen; i++) { + int b = 0; + if (i >= y) { + unsigned j = i - y; + if (j < 64) { + b = (x.l & ((uint64_t)1 << j)) != 0; + } + else { + b = (x.h & ((uint64_t)1 << (j - 64))) != 0; + } + } + if (b) { + if (i < 64) { + z.l |= (uint64_t)1 << i; + } + else { + z.h |= (uint64_t)1 << (i - 64); + } + } + } + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_srl(int_xlen_t x, unsigned y) { + int_xlen_t z; + unsigned i; + z.l = z.h = 0; + for (i = 0; i < xlen; i++) { + int b = 0; + if (i + y < xlen) { + unsigned j = i + y; + if (j < 64) { + b = (x.l & ((uint64_t)1 << j)) != 0; + } + else { + b = (x.h & ((uint64_t)1 << (j - 64))) != 0; + } + } + if (b) { + if (i < 64) { + z.l |= (uint64_t)1 << i; + } + else { + z.h |= (uint64_t)1 << (i - 64); + } + } + } + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_sra(int_xlen_t x, unsigned y) { + int_xlen_t z; + unsigned i; + z.l = z.h = 0; + for (i = 0; i < xlen; i++) { + int b = 0; + unsigned j = i + y; + if (j >= xlen) j = xlen - 1; + if (j < 64) { + b = (x.l & ((uint64_t)1 << j)) != 0; + } + else { + b = (x.h & ((uint64_t)1 << (j - 64))) != 0; + } + if (b) { + if (i < 64) { + z.l |= (uint64_t)1 << i; + } + else { + z.h |= (uint64_t)1 << (i - 64); + } + } + } + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_and(int_xlen_t x, int_xlen_t y) { + int_xlen_t z; + z.l = x.l & y.l; + z.h = x.h & y.h; + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_xor(int_xlen_t x, int_xlen_t y) { + int_xlen_t z; + z.l = x.l ^ y.l; + z.h = x.h ^ y.h; + return fix_sign(z, xlen, 1); +} + +static int_xlen_t int_xlen_or(int_xlen_t x, int_xlen_t y) { + int_xlen_t z; + z.l = x.l | y.l; + z.h = x.h | y.h; + return fix_sign(z, xlen, 1); +} diff --git a/agent/machine/riscv64/tcf/cpu-regs-gdb.h b/agent/machine/riscv64/tcf/cpu-regs-gdb.h new file mode 100644 index 00000000..455195a2 --- /dev/null +++ b/agent/machine/riscv64/tcf/cpu-regs-gdb.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#ifndef D_cpu_regs_gdb_riscv64 +#define D_cpu_regs_gdb_riscv64 + +#include <tcf/config.h> + +static const char * cpu_regs_gdb_riscv64 = +"<architecture>rv64</architecture>\n" +"<feature name='org.gnu.gdb.riscv.cpu'>\n" +" <reg name='zero' bitsize='64' type='int' regnum='0' />\n" +" <reg name='ra' bitsize='64' type='code_ptr' />\n" +" <reg name='sp' bitsize='64' type='data_ptr' />\n" +" <reg name='gp' bitsize='64' type='data_ptr' />\n" +" <reg name='tp' bitsize='64' type='data_ptr' />\n" +" <reg name='t0' bitsize='64' type='int' />\n" +" <reg name='t1' bitsize='64' type='int' />\n" +" <reg name='t2' bitsize='64' type='int' />\n" +" <reg name='fp' bitsize='64' type='data_ptr' />\n" +" <reg name='s1' bitsize='64' type='int' />\n" +" <reg name='a0' bitsize='64' type='int' />\n" +" <reg name='a1' bitsize='64' type='int' />\n" +" <reg name='a2' bitsize='64' type='int' />\n" +" <reg name='a3' bitsize='64' type='int' />\n" +" <reg name='a4' bitsize='64' type='int' />\n" +" <reg name='a5' bitsize='64' type='int' />\n" +" <reg name='a6' bitsize='64' type='int' />\n" +" <reg name='a7' bitsize='64' type='int' />\n" +" <reg name='s2' bitsize='64' type='int' />\n" +" <reg name='s3' bitsize='64' type='int' />\n" +" <reg name='s4' bitsize='64' type='int' />\n" +" <reg name='s5' bitsize='64' type='int' />\n" +" <reg name='s6' bitsize='64' type='int' />\n" +" <reg name='s7' bitsize='64' type='int' />\n" +" <reg name='s8' bitsize='64' type='int' />\n" +" <reg name='s9' bitsize='64' type='int' />\n" +" <reg name='s10' bitsize='64' type='int' />\n" +" <reg name='s11' bitsize='64' type='int' />\n" +" <reg name='t3' bitsize='64' type='int' />\n" +" <reg name='t4' bitsize='64' type='int' />\n" +" <reg name='t5' bitsize='64' type='int' />\n" +" <reg name='t6' bitsize='64' type='int' />\n" +" <reg name='pc' bitsize='64' type='code_ptr' />\n" +"</feature>\n" +"<feature name='org.gnu.gdb.riscv.csr'>\n" +"</feature>\n"; + +#endif /* D_cpu_regs_gdb_riscv64 */ diff --git a/agent/machine/riscv64/tcf/cpudefs-mdep.c b/agent/machine/riscv64/tcf/cpudefs-mdep.c index cce0ea90..cadbcd33 100644 --- a/agent/machine/riscv64/tcf/cpudefs-mdep.c +++ b/agent/machine/riscv64/tcf/cpudefs-mdep.c @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2019. +* Copyright (c) 2019-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. @@ -14,31 +14,52 @@ #if ENABLE_DebugContext && !ENABLE_ContextProxy +#include <assert.h> #include <tcf/framework/cpudefs.h> #include <tcf/framework/context.h> #include <tcf/framework/myalloc.h> +#include <tcf/framework/trace.h> +#include <tcf/services/runctrl.h> #if ENABLE_ContextMux #include <tcf/framework/cpudefs-mdep-mux.h> #endif +#include <tcf/disassembler-riscv64.h> +#include <tcf/stack-crawl-riscv64.h> #include <tcf/cpudefs-mdep.h> -unsigned char BREAK_INST[] = {0x02, 0x90}; +typedef struct ContextExtensionRISCV { + int sw_stepping; + char opcode[sizeof(BREAK_INST)]; + unsigned opcode_size; + ContextAddress step_addr; +} ContextExtensionRISCV; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtensionRISCV *)((char *)(ctx) + context_extension_offset)) +unsigned char BREAK_INST[] = {0x02, 0x90}; RegisterDefinition * regs_index; +static RegisterDefinition * reg_pc; +static unsigned regs_cnt; +static unsigned regs_max; + +#define REG_OFFSET(name) offsetof(REG_SET, name) + static const RegisterDefinition rv_regs[] = { - {.name="pc", .description="Program counter", .role="PC"}, - {.name="ra", .description="Return address", .role="RET"}, - {.name="sp", .description="Stack pointer", .role="SP"}, + {.name="zero", .offset = REG_OFFSET(other), .no_write = 1, .description="Zero register"}, + {.name="ra", .role = "RET", .description="Return address"}, + {.name="sp", .role = "SP", .description="Stack pointer"}, {.name="gp", .description="Global pointer"}, {.name="tp", .description="Thread pointer"}, {.name="t0", .description="Temporary register"}, {.name="t1", .description="Temporary register"}, {.name="t2", .description="Temporary register"}, - {.name="s0", .description="Saved register"}, + {.name="s0", .description="Saved register / frame pointer"}, {.name="s1", .description="Saved register"}, - {.name="a0", .description="Function argument / frame pointer"}, - {.name="a1", .description="Function argument / frame pointer"}, + {.name="a0", .description="Function argument / return value"}, + {.name="a1", .description="Function argument"}, {.name="a2", .description="Function argument"}, {.name="a3", .description="Function argument"}, {.name="a4", .description="Function argument"}, @@ -62,28 +83,221 @@ static const RegisterDefinition rv_regs[] = { {NULL} }; +static RegisterDefinition * alloc_reg(void) { + RegisterDefinition * r = regs_index + regs_cnt++; + assert(regs_cnt <= regs_max); + return r; +} + +static RegisterDefinition * alloc_spr(const char * name, size_t offset, size_t size, int16_t id, const char * desc) { + RegisterDefinition * reg = alloc_reg(); + reg->name = loc_strdup(name); + reg->description = loc_strdup(desc); + reg->dwarf_id = id; + reg->eh_frame_id = id; + reg->offset = offset; + reg->size = size; + return reg; +} + +int mdep_get_other_regs(pid_t pid, REG_SET * data, size_t data_offs, size_t data_size, + size_t * done_offs, size_t * done_size) { + assert(data_offs >= REG_OFFSET(other)); + assert(data_offs + data_size <= REG_OFFSET(other) + sizeof(data->other)); + (void)pid; + data->other = 0; + *done_offs = REG_OFFSET(other); + *done_size = sizeof(data->other); + return 0; +} + +int mdep_set_other_regs(pid_t pid, REG_SET * data, size_t data_offs, size_t data_size, + size_t * done_offs, size_t * done_size) { + assert(data_offs >= REG_OFFSET(other)); + assert(data_offs + data_size <= REG_OFFSET(other) + sizeof(data->other)); + (void)pid; + *done_offs = REG_OFFSET(other); + *done_size = sizeof(data->other); + return 0; +} + RegisterDefinition * get_PC_definition(Context * ctx) { if (!context_has_state(ctx)) return NULL; - return regs_index; + return reg_pc; } int crawl_stack_frame(StackFrame * frame, StackFrame * down) { + return crawl_stack_frame_riscv64(frame, down); +} + +#if defined(ENABLE_add_cpudefs_disassembler) && ENABLE_add_cpudefs_disassembler +void add_cpudefs_disassembler(Context * cpu_ctx) { + add_disassembler(cpu_ctx, "Riscv64", disassemble_riscv64); +} +#endif + +#if ENABLE_external_stepping_mode + +static Context * riscv_ctx; +static uint64_t riscv_pc; +static uint32_t riscv_instr; + +static int riscv_read_reg(RegisterDefinition * r, uint64_t * res) { + unsigned i; + uint8_t buf[8]; + *res = 0; + assert(r->size <= sizeof(buf)); + assert(!r->big_endian); + if (context_read_reg(riscv_ctx, r, 0, r->size, buf) < 0) return -1; + for (i = 0; i < r->size; i++) *res |= (uint64_t)buf[i] << (i * 8); + return 0; +} + +static int riscv_read_mem(uint64_t addr, uint32_t * res, unsigned size) { + unsigned i; + uint8_t buf[4]; + *res = 0; + assert(size <= sizeof(buf)); + if (context_read_mem(riscv_ctx, (ContextAddress)addr, buf, size) < 0) return -1; + for (i = 0; i < size; i++) *res |= (uint32_t)buf[i] << (i * 8); + return 0; +} + +static int32_t get_imm_se(const int * bits) { + unsigned i; + uint32_t v = 0; + for (i = 0; i < 32 && bits[i]; i++) { + if (riscv_instr & (1u << bits[i])) v |= 1u << i; + } + if (v & (1u << (i - 1))) v |= ~((1u << i) - 1); + return v; +} + +static int riscv_get_next_address(Context * ctx, ContextExtensionRISCV * ext) { + static const int imm_bits_j[32] = { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 20, 12, 13, 14, 15, 16, 17, 18, 19, 31 }; + static const int imm_bits_jc[32] = { 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12 }; + static const int imm_bits_b[32] = { 8, 9, 10, 11, 25, 26, 27, 28, 29, 30, 7, 31 }; + + riscv_ctx = ctx; + + /* read opcode at PC */ + if (riscv_read_reg(reg_pc, &riscv_pc) < 0) return -1; + if (riscv_read_mem(riscv_pc, &riscv_instr, 4) < 0) return -1; + + if ((riscv_instr & 3) == 3) { + ext->step_addr = riscv_pc + 4; + } + else { + riscv_instr &= 0xffff; + ext->step_addr = riscv_pc + 2; + } + + trace(LOG_CONTEXT, "pc 0x%016" PRIx64 ", opcode 0x%08x", riscv_pc, riscv_instr); + + if ((riscv_instr & 0x0000007f) == 0x0000006f) { /* j, jal */ + int32_t imm = get_imm_se(imm_bits_j); + ext->step_addr = riscv_pc + ((int64_t)imm << 1); + return 0; + } + if ((riscv_instr & 0xe003) == 0x2001) { /* addiw (replaces jal in RV64c) */ + return 0; + } + if ((riscv_instr & 0x6003) == 0x2001) { /* j, jal */ + int32_t imm = get_imm_se(imm_bits_jc); + ext->step_addr = riscv_pc + ((int64_t)imm << 1); + return 0; + } + if ((riscv_instr & 0x0000707f) == 0x00000067) { /* jalr */ + unsigned rs1 = (riscv_instr >> 15) & 0x1f; + int32_t imm = riscv_instr >> 20; + uint64_t addr = 0; + if (riscv_read_reg(regs_index + rs1, &addr) < 0) return -1; + ext->step_addr = (addr + ((int64_t)imm << 1)) & ~(uint64_t)1; + return 0; + } + if ((riscv_instr & 0xe003) == 0x8002) { /* jr, jalr */ + unsigned rd = (riscv_instr >> 7) & 0x1f; + unsigned rs = (riscv_instr >> 2) & 0x1f; + uint64_t addr = 0; + if (rd == 0) return 0; + if (rs != 0) return 0; + if (riscv_read_reg(regs_index + rd, &addr) < 0) return -1; + ext->step_addr = addr & ~(uint64_t)1; + return 0; + } + if ((riscv_instr & 0x0000007f) == 0x00000063) { /* beq, bne, blt, bge, bltu, bgeu */ + int32_t imm = get_imm_se(imm_bits_b); + unsigned rs2 = (riscv_instr >> 20) & 0x1f; + unsigned rs1 = (riscv_instr >> 15) & 0x1f; + uint64_t x = 0, y = 0; + int ok = 0; + if (riscv_read_reg(regs_index + rs1, &x) < 0) return -1; + if (riscv_read_reg(regs_index + rs2, &y) < 0) return -1; + switch ((riscv_instr >> 12) & 7) { + case 0: ok = x == y; break; + case 1: ok = x != y; break; + case 4: ok = (int64_t)x < (int64_t)y; break; + case 5: ok = (int64_t)x >= (int64_t)y; break; + case 6: ok = x < y; break; + case 7: ok = x >= y; break; + } + if (ok) ext->step_addr = riscv_pc + ((int64_t)imm << 1); + return 0; + } + + return 0; +} + +int cpu_enable_stepping_mode(Context * ctx, uint32_t * is_cont) { + Context * grp = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + ContextExtensionRISCV * ext = EXT(grp); + assert(!grp->exited); + assert(!ext->sw_stepping); + if (riscv_get_next_address(ctx, ext) < 0) return -1; + trace(LOG_CONTEXT, "enable_sw_stepping_mode %s 0x%08x", ctx->id, (unsigned)ext->step_addr); + ext->opcode_size = sizeof(BREAK_INST); + if (context_read_mem(grp, ext->step_addr, ext->opcode, ext->opcode_size) < 0) return -1; + if (context_write_mem(grp, ext->step_addr, BREAK_INST, ext->opcode_size) < 0) return -1; + ext->sw_stepping = 1; + run_ctrl_lock(); + *is_cont = 1; + return 0; +} + +int cpu_disable_stepping_mode(Context * ctx) { + Context * grp = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + ContextExtensionRISCV * ext = EXT(grp); + if (ext->sw_stepping) { + trace(LOG_CONTEXT, "disable_sw_stepping_mode %s", ctx->id); + run_ctrl_unlock(); + ext->sw_stepping = 0; + if (grp->exited) return 0; + return context_write_mem(grp, ext->step_addr, ext->opcode, ext->opcode_size); + } return 0; } +#endif -#if ENABLE_ini_cpudefs_mdep void ini_cpudefs_mdep(void) { - regs_index = (RegisterDefinition *)loc_alloc_zero(sizeof(rv_regs)); int i; + + context_extension_offset = context_extension(sizeof(ContextExtensionRISCV)); + + regs_cnt = 0; + regs_max = 128; + regs_index = (RegisterDefinition *)loc_alloc_zero(sizeof(RegisterDefinition) * regs_max); + for (i = 0; rv_regs[i].name != NULL; ++i) { - RegisterDefinition * r = regs_index + i; + RegisterDefinition * r = alloc_reg(); *r = rv_regs[i]; - r->offset = i * 8; r->size = 8; r->dwarf_id = i; r->eh_frame_id = i; - } + if (r->offset == 0) r->offset = i * 8; + } + reg_pc = alloc_spr("pc", REG_OFFSET(gp.pc), 8, -1, "Program counter"); + reg_pc->dwarf_id = reg_pc->eh_frame_id = 0x17b1; + reg_pc->role = "PC"; } -#endif #endif /* ENABLE_DebugContext && !ENABLE_ContextProxy */ diff --git a/agent/machine/riscv64/tcf/cpudefs-mdep.h b/agent/machine/riscv64/tcf/cpudefs-mdep.h index fd54318e..55750eeb 100644 --- a/agent/machine/riscv64/tcf/cpudefs-mdep.h +++ b/agent/machine/riscv64/tcf/cpudefs-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2019. +* Copyright (c) 2019-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. @@ -15,12 +15,25 @@ * This module provides CPU specific definitions for riscv64. */ +#if defined(__riscv) + #include <tcf/regset.h> extern RegisterDefinition * regs_index; extern unsigned char BREAK_INST[2]; +#if !defined(ENABLE_add_cpudefs_disassembler) +#define ENABLE_add_cpudefs_disassembler 1 +extern void add_cpudefs_disassembler(Context * cpu_ctx); +#endif + +#if !defined(ENABLE_external_stepping_mode) +#define ENABLE_external_stepping_mode 1 +#endif + #if !defined(ENABLE_ini_cpudefs_mdep) # define ENABLE_ini_cpudefs_mdep 1 extern void ini_cpudefs_mdep(void); #endif + +#endif diff --git a/agent/machine/riscv64/tcf/disassembler-riscv64.c b/agent/machine/riscv64/tcf/disassembler-riscv64.c new file mode 100644 index 00000000..f85fadb8 --- /dev/null +++ b/agent/machine/riscv64/tcf/disassembler-riscv64.c @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2019 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#include "machine/riscv/tcf/disassembler-riscv.c" diff --git a/agent/machine/riscv64/tcf/disassembler-riscv64.h b/agent/machine/riscv64/tcf/disassembler-riscv64.h new file mode 100644 index 00000000..b09b32a9 --- /dev/null +++ b/agent/machine/riscv64/tcf/disassembler-riscv64.h @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2019 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#include "machine/riscv/tcf/disassembler-riscv.h" diff --git a/agent/machine/riscv64/tcf/dwarfreloc-mdep.h b/agent/machine/riscv64/tcf/dwarfreloc-mdep.h index f938cbe8..708fd3dd 100644 --- a/agent/machine/riscv64/tcf/dwarfreloc-mdep.h +++ b/agent/machine/riscv64/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019. + * Copyright (c) 2019-2021. * 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. @@ -15,44 +15,124 @@ * This module provides CPU specific ELF definitions for riscv64. */ -#define R_RISCV_NONE 0 -#define R_RISCV_32 1 -#define R_RISCV_64 2 +#define R_RISCV_NONE 0 +#define R_RISCV_32 1 +#define R_RISCV_64 2 +#define R_RISCV_ADD8 33 +#define R_RISCV_ADD16 34 +#define R_RISCV_ADD32 35 +#define R_RISCV_ADD64 36 +#define R_RISCV_SUB8 37 +#define R_RISCV_SUB16 38 +#define R_RISCV_SUB32 39 +#define R_RISCV_SUB64 40 +#define R_RISCV_SUB6 52 +#define R_RISCV_SET6 53 +#define R_RISCV_SET8 54 +#define R_RISCV_SET16 55 +#define R_RISCV_SET32 56 +#define R_RISCV_32_PCREL 57 + +static void elf_riscv_check_size(unsigned size) { + if (data_size < size) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); +} static void elf_relocate(void) { if (relocs->type == SHT_REL && reloc_type != R_RISCV_NONE) { if (section->file->type != ET_REL) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); assert(reloc_addend == 0); switch (reloc_type) { - case R_RISCV_64: { - U8_T x = *(U8_T *)((char *)section->data + reloc_offset); - if (section->file->byte_swap) SWAP(x); - reloc_addend = x; + case R_RISCV_SET8: + elf_riscv_check_size(1); + reloc_addend = *(U1_T *)data_buf; break; - } - case R_RISCV_32: { - U4_T x = *(U4_T *)((char *)section->data + reloc_offset); - if (section->file->byte_swap) SWAP(x); - reloc_addend = x; + case R_RISCV_SET16: + elf_riscv_check_size(2); + reloc_addend = *(U2_T *)data_buf; + break; + case R_RISCV_32: + case R_RISCV_32_PCREL: + case R_RISCV_SET32: + elf_riscv_check_size(4); + reloc_addend = *(U4_T *)data_buf; + break; + case R_RISCV_64: + elf_riscv_check_size(8); + reloc_addend = *(U8_T *)data_buf; break; - } default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } switch (reloc_type) { case R_RISCV_NONE: *destination_section = NULL; break; + case R_RISCV_32: + elf_riscv_check_size(4); + *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend); + break; + case R_RISCV_32_PCREL: + elf_riscv_check_size(4); + *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); + break; case R_RISCV_64: - if (data_size < 8) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); + elf_riscv_check_size(8); *(U8_T *)data_buf = (U8_T)(sym_value + reloc_addend); break; - case R_RISCV_32: - if (data_size < 4) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); + case R_RISCV_ADD8: + elf_riscv_check_size(1); + *(U1_T *)data_buf += (U1_T)(sym_value + reloc_addend); + break; + case R_RISCV_ADD16: + elf_riscv_check_size(2); + *(U2_T *)data_buf += (U2_T)(sym_value + reloc_addend); + break; + case R_RISCV_ADD32: + elf_riscv_check_size(4); + *(U4_T *)data_buf += (U4_T)(sym_value + reloc_addend); + break; + case R_RISCV_ADD64: + elf_riscv_check_size(8); + *(U8_T *)data_buf += (U8_T)(sym_value + reloc_addend); + break; + case R_RISCV_SUB8: + elf_riscv_check_size(1); + *(U1_T *)data_buf -= (U1_T)(sym_value + reloc_addend); + break; + case R_RISCV_SUB16: + elf_riscv_check_size(2); + *(U2_T *)data_buf -= (U2_T)(sym_value + reloc_addend); + break; + case R_RISCV_SUB32: + elf_riscv_check_size(4); + *(U4_T *)data_buf -= (U4_T)(sym_value + reloc_addend); + break; + case R_RISCV_SUB64: + elf_riscv_check_size(8); + *(U8_T *)data_buf -= (U8_T)(sym_value + reloc_addend); + break; + case R_RISCV_SUB6: + elf_riscv_check_size(1); + *(U1_T *)data_buf = (*(U1_T *)data_buf & 0xc0) | ((*(U1_T *)data_buf - (U1_T)(sym_value + reloc_addend)) & 0x3f); + break; + case R_RISCV_SET6: + elf_riscv_check_size(1); + *(U1_T *)data_buf = (*(U1_T *)data_buf & 0xc0) | ((U1_T)(sym_value + reloc_addend) & 0x3f); + break; + case R_RISCV_SET8: + elf_riscv_check_size(1); + *(U1_T *)data_buf = (U1_T)(sym_value + reloc_addend); + break; + case R_RISCV_SET16: + elf_riscv_check_size(2); + *(U2_T *)data_buf = (U2_T)(sym_value + reloc_addend); + break; + case R_RISCV_SET32: + elf_riscv_check_size(4); *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/riscv64/tcf/regset-mdep.h b/agent/machine/riscv64/tcf/regset-mdep.h index 8b54b32a..e3aad260 100644 --- a/agent/machine/riscv64/tcf/regset-mdep.h +++ b/agent/machine/riscv64/tcf/regset-mdep.h @@ -26,6 +26,8 @@ struct regset_fp { uint64_t _unused_; }; +#define MDEP_OtherRegisters uint64_t + #endif /* Offset to be applied to the PC after a software trap */ diff --git a/agent/machine/riscv64/tcf/stack-crawl-riscv64.c b/agent/machine/riscv64/tcf/stack-crawl-riscv64.c new file mode 100644 index 00000000..61f2d15c --- /dev/null +++ b/agent/machine/riscv64/tcf/stack-crawl-riscv64.c @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2019 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#include "machine/riscv/tcf/stack-crawl-riscv.c" diff --git a/agent/machine/riscv64/tcf/stack-crawl-riscv64.h b/agent/machine/riscv64/tcf/stack-crawl-riscv64.h new file mode 100644 index 00000000..30befb03 --- /dev/null +++ b/agent/machine/riscv64/tcf/stack-crawl-riscv64.h @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2019 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. + * 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: + * Xilinx - initial API and implementation + *******************************************************************************/ + +#include "machine/riscv/tcf/stack-crawl-riscv.h" diff --git a/agent/machine/sparc/tcf/dwarfreloc-mdep.h b/agent/machine/sparc/tcf/dwarfreloc-mdep.h index fa6b61d3..72fc4b55 100644 --- a/agent/machine/sparc/tcf/dwarfreloc-mdep.h +++ b/agent/machine/sparc/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Cobham Gaisler and others. + * Copyright (c) 2018-2021 Cobham Gaisler 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. @@ -41,6 +41,6 @@ static void elf_relocate(void) { *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend); break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/x86_64/tcf/cpu-regs-gdb.h b/agent/machine/x86_64/tcf/cpu-regs-gdb.h index c5690089..6ef3ee8b 100644 --- a/agent/machine/x86_64/tcf/cpu-regs-gdb.h +++ b/agent/machine/x86_64/tcf/cpu-regs-gdb.h @@ -76,9 +76,9 @@ static const char * cpu_regs_gdb_x86_64 = " <reg name='fstat' bitsize='32' type='int' group='float' id='66'/>\n" " <reg name='ftag' bitsize='32' type='int' group='float'/>\n" " <reg name='fiseg' bitsize='32' type='int' group='float'/>\n" -" <reg name='fioff' bitsize='32' type='int' group='float'/>\n" +" <reg name='fioff' bitsize='64' type='int' group='float'/>\n" " <reg name='foseg' bitsize='32' type='int' group='float'/>\n" -" <reg name='fooff' bitsize='32' type='int' group='float'/>\n" +" <reg name='fooff' bitsize='64' type='int' group='float'/>\n" " <reg name='fop' bitsize='32' type='int' group='float'/>\n" "</feature>\n" "<feature name='org.gnu.gdb.i386.sse'>\n" diff --git a/agent/machine/x86_64/tcf/cpudefs-mdep.c b/agent/machine/x86_64/tcf/cpudefs-mdep.c index 8d8134c4..b46b9261 100644 --- a/agent/machine/x86_64/tcf/cpudefs-mdep.c +++ b/agent/machine/x86_64/tcf/cpudefs-mdep.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. @@ -81,8 +81,8 @@ static RegisterDefinition regs_def[] = { { "st6", REG_OFFSET(FloatSave.RegisterArea) + 60, 10, 39, 39, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 24 }, { "st7", REG_OFFSET(FloatSave.RegisterArea) + 70, 10, 40, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 24 }, - { "control", REG_OFFSET(FloatSave.ControlWord), 2, 65, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 24 }, - { "status", REG_OFFSET(FloatSave.StatusWord), 2, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 24 }, + { "control", REG_OFFSET(FloatSave.ControlWord), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 24 }, + { "status", REG_OFFSET(FloatSave.StatusWord), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 24 }, { "tag", REG_OFFSET(FloatSave.TagWord), 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 24 }, { "xmm", 0, 0, -1, -1, 0, 0, 1, 1 }, /* 36 */ @@ -455,39 +455,44 @@ static RegisterDefinition regs_def[] = { { "swd", REG_OFFSET(fp.swd), 2, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, { "ftw", REG_OFFSET(fp.ftw), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, { "fop", REG_OFFSET(fp.fop), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, - { "rip", REG_OFFSET(fp.rip), 8, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, - { "rdp", REG_OFFSET(fp.rdp), 8, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, + { "fip", REG_OFFSET(fp.rip), 8, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, + { "fcs", REG_OFFSET(user.regs.cs), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, + { "foo", REG_OFFSET(fp.rdp), 8, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, + { "fos", REG_OFFSET(user.regs.ds), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, { "mxcsr", REG_OFFSET(fp.mxcsr), 4, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, { "mxcr_mask", REG_OFFSET(fp.mxcr_mask), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 26 }, { "xmm", 0, 0, -1, -1, 0, 0, 1, 1 }, - { "xmm0", REG_OFFSET(fp.xmm_space) + 0, 16, 17, 17, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm1", REG_OFFSET(fp.xmm_space) + 16, 16, 18, 18, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm2", REG_OFFSET(fp.xmm_space) + 32, 16, 19, 19, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm3", REG_OFFSET(fp.xmm_space) + 48, 16, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm4", REG_OFFSET(fp.xmm_space) + 64, 16, 21, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm5", REG_OFFSET(fp.xmm_space) + 80, 16, 22, 22, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm6", REG_OFFSET(fp.xmm_space) + 96, 16, 23, 23, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm7", REG_OFFSET(fp.xmm_space) + 112, 16, 24, 24, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm8", REG_OFFSET(fp.xmm_space) + 128, 16, 25, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm9", REG_OFFSET(fp.xmm_space) + 144, 16, 26, 26, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm10", REG_OFFSET(fp.xmm_space) + 160, 16, 27, 27, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm11", REG_OFFSET(fp.xmm_space) + 176, 16, 28, 28, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm12", REG_OFFSET(fp.xmm_space) + 192, 16, 29, 29, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm13", REG_OFFSET(fp.xmm_space) + 208, 16, 30, 30, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm14", REG_OFFSET(fp.xmm_space) + 224, 16, 31, 31, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - { "xmm15", REG_OFFSET(fp.xmm_space) + 240, 16, 32, 32, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 43 }, - - { "debug", 0, 0, -1, -1, 0, 0, 1, 1 }, /* 60 */ - - { "dr0", REG_OFFSET(user.u_debugreg[0]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 60 }, - { "dr1", REG_OFFSET(user.u_debugreg[1]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 60 }, - { "dr2", REG_OFFSET(user.u_debugreg[2]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 60 }, - { "dr3", REG_OFFSET(user.u_debugreg[3]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 60 }, - { "dr6", REG_OFFSET(user.u_debugreg[6]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 60 }, - { "dr7", REG_OFFSET(user.u_debugreg[7]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 60 }, + { "xmm0", REG_OFFSET(fp.xmm_space) + 0, 16, 17, 17, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm1", REG_OFFSET(fp.xmm_space) + 16, 16, 18, 18, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm2", REG_OFFSET(fp.xmm_space) + 32, 16, 19, 19, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm3", REG_OFFSET(fp.xmm_space) + 48, 16, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm4", REG_OFFSET(fp.xmm_space) + 64, 16, 21, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm5", REG_OFFSET(fp.xmm_space) + 80, 16, 22, 22, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm6", REG_OFFSET(fp.xmm_space) + 96, 16, 23, 23, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm7", REG_OFFSET(fp.xmm_space) + 112, 16, 24, 24, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm8", REG_OFFSET(fp.xmm_space) + 128, 16, 25, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm9", REG_OFFSET(fp.xmm_space) + 144, 16, 26, 26, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm10", REG_OFFSET(fp.xmm_space) + 160, 16, 27, 27, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm11", REG_OFFSET(fp.xmm_space) + 176, 16, 28, 28, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm12", REG_OFFSET(fp.xmm_space) + 192, 16, 29, 29, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm13", REG_OFFSET(fp.xmm_space) + 208, 16, 30, 30, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm14", REG_OFFSET(fp.xmm_space) + 224, 16, 31, 31, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + { "xmm15", REG_OFFSET(fp.xmm_space) + 240, 16, 32, 32, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 45 }, + + { "debug", 0, 0, -1, -1, 0, 0, 1, 1 }, /* 62 */ + + { "dr0", REG_OFFSET(user.u_debugreg[0]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 62 }, + { "dr1", REG_OFFSET(user.u_debugreg[1]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 62 }, + { "dr2", REG_OFFSET(user.u_debugreg[2]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 62 }, + { "dr3", REG_OFFSET(user.u_debugreg[3]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 62 }, + { "dr6", REG_OFFSET(user.u_debugreg[6]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 62 }, + { "dr7", REG_OFFSET(user.u_debugreg[7]), 8, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 62 }, + + { "fs_base32", REG_OFFSET(other.fs.base), 4, 158, 158, 0, 0, 0, 1 }, + { "gs_base32", REG_OFFSET(other.gs.base), 4, 159, 159, 0, 0, 0, 1 }, #elif defined(__i386__) # define REG_SP user.regs.esp @@ -528,36 +533,36 @@ static RegisterDefinition regs_def[] = { { "fpu", 0, 0, -1, -1, 0, 0, 1, 1 }, - { "st0", REG_OFFSET(other.st_space) + 0, 10, 33, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "st1", REG_OFFSET(other.st_space) + 16, 10, 34, 34, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "st2", REG_OFFSET(other.st_space) + 32, 10, 35, 35, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "st3", REG_OFFSET(other.st_space) + 48, 10, 36, 36, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "st4", REG_OFFSET(other.st_space) + 64, 10, 37, 37, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "st5", REG_OFFSET(other.st_space) + 80, 10, 38, 38, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "st6", REG_OFFSET(other.st_space) + 96, 10, 39, 39, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "st7", REG_OFFSET(other.st_space) + 112, 10, 40, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - - { "cwd", REG_OFFSET(other.cwd), 2, 65, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "swd", REG_OFFSET(other.swd), 2, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "twd", REG_OFFSET(other.twd), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "fop", REG_OFFSET(other.fop), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "fip", REG_OFFSET(other.fip), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "fcs", REG_OFFSET(other.fcs), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "foo", REG_OFFSET(other.foo), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - { "fos", REG_OFFSET(other.fos), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, - - { "mxcsr", REG_OFFSET(other.mxcsr), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st0", REG_OFFSET(other.fpx.st_space) + 0, 10, 33, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st1", REG_OFFSET(other.fpx.st_space) + 16, 10, 34, 34, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st2", REG_OFFSET(other.fpx.st_space) + 32, 10, 35, 35, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st3", REG_OFFSET(other.fpx.st_space) + 48, 10, 36, 36, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st4", REG_OFFSET(other.fpx.st_space) + 64, 10, 37, 37, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st5", REG_OFFSET(other.fpx.st_space) + 80, 10, 38, 38, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st6", REG_OFFSET(other.fpx.st_space) + 96, 10, 39, 39, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "st7", REG_OFFSET(other.fpx.st_space) + 112, 10, 40, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + + { "cwd", REG_OFFSET(other.fpx.cwd), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "swd", REG_OFFSET(other.fpx.swd), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "twd", REG_OFFSET(other.fpx.twd), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "fop", REG_OFFSET(other.fpx.fop), 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "fip", REG_OFFSET(other.fpx.fip), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "fcs", REG_OFFSET(other.fpx.fcs), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "foo", REG_OFFSET(other.fpx.foo), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + { "fos", REG_OFFSET(other.fpx.fos), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, + + { "mxcsr", REG_OFFSET(other.fpx.mxcsr), 4, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 28 }, { "xmm", 0, 0, -1, -1, 0, 0, 1, 1 }, /* 46 */ - { "xmm0", REG_OFFSET(other.xmm_space) + 0, 16, 17, 17, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, - { "xmm1", REG_OFFSET(other.xmm_space) + 16, 16, 18, 18, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, - { "xmm2", REG_OFFSET(other.xmm_space) + 32, 16, 19, 19, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, - { "xmm3", REG_OFFSET(other.xmm_space) + 48, 16, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, - { "xmm4", REG_OFFSET(other.xmm_space) + 64, 16, 21, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, - { "xmm5", REG_OFFSET(other.xmm_space) + 80, 16, 22, 22, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, - { "xmm6", REG_OFFSET(other.xmm_space) + 96, 16, 23, 23, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, - { "xmm7", REG_OFFSET(other.xmm_space) + 112, 16, 24, 24, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm0", REG_OFFSET(other.fpx.xmm_space) + 0, 16, 17, 17, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm1", REG_OFFSET(other.fpx.xmm_space) + 16, 16, 18, 18, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm2", REG_OFFSET(other.fpx.xmm_space) + 32, 16, 19, 19, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm3", REG_OFFSET(other.fpx.xmm_space) + 48, 16, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm4", REG_OFFSET(other.fpx.xmm_space) + 64, 16, 21, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm5", REG_OFFSET(other.fpx.xmm_space) + 80, 16, 22, 22, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm6", REG_OFFSET(other.fpx.xmm_space) + 96, 16, 23, 23, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, + { "xmm7", REG_OFFSET(other.fpx.xmm_space) + 112, 16, 24, 24, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, regs_def + 46 }, { "debug", 0, 0, -1, -1, 0, 0, 1, 1 }, /* 55 */ @@ -568,6 +573,9 @@ static RegisterDefinition regs_def[] = { { "dr6", REG_OFFSET(user.u_debugreg[6]), 4, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 55 }, { "dr7", REG_OFFSET(user.u_debugreg[7]), 4, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, regs_def + 55 }, + { "fs_base", REG_OFFSET(other.fs.base), 4, 58, 58, 0, 0, 0, 1 }, + { "gs_base", REG_OFFSET(other.gs.base), 4, 59, 59, 0, 0, 0, 1 }, + #endif { NULL }, @@ -583,22 +591,34 @@ unsigned char BREAK_INST[] = { 0xcc }; #include <tcf/framework/mdep-ptrace.h> -#if !defined(PTRACE_GETFPXREGS) && !defined(PT_GETFPXREGS) -#define PTRACE_GETFPXREGS 18 -#endif -#if !defined(PTRACE_SETFPXREGS) && !defined(PT_SETFPXREGS) -#define PTRACE_SETFPXREGS 19 -#endif - int mdep_get_other_regs(pid_t pid, REG_SET * data, size_t data_offs, size_t data_size, size_t * done_offs, size_t * done_size) { assert(data_offs >= offsetof(REG_SET, other)); assert(data_offs + data_size <= offsetof(REG_SET, other) + sizeof(data->other)); - if (ptrace(PTRACE_GETFPXREGS, pid, 0, &data->other) < 0) return -1; - *done_offs = offsetof(REG_SET, other); - *done_size = sizeof(data->other); - return 0; +#if defined(__i386__) + if (data_offs >= REG_OFFSET(other.fpx) && data_offs < REG_OFFSET(other.fpx) + sizeof(data->other.fpx)) { + if (ptrace(PTRACE_GETFPXREGS, pid, 0, &data->other.fpx) < 0) return -1; + *done_offs = offsetof(REG_SET, other.fpx); + *done_size = sizeof(data->other.fpx); + return 0; + } +#endif + assert(sizeof(data->other.fs) == 16); + if (data_offs >= REG_OFFSET(other.fs) && data_offs < REG_OFFSET(other.fs) + sizeof(data->other.fs)) { + if (ptrace(PTRACE_GET_THREAD_AREA, pid, 12, &data->other.fs) < 0) return -1; + *done_offs = offsetof(REG_SET, other.fs); + *done_size = sizeof(data->other.fs); + return 0; + } + if (data_offs >= REG_OFFSET(other.gs) && data_offs < REG_OFFSET(other.gs) + sizeof(data->other.gs)) { + if (ptrace(PTRACE_GET_THREAD_AREA, pid, 13, &data->other.gs) < 0) return -1; + *done_offs = offsetof(REG_SET, other.gs); + *done_size = sizeof(data->other.gs); + return 0; + } + errno = ERR_UNSUPPORTED; + return -1; } int mdep_set_other_regs(pid_t pid, REG_SET * data, @@ -606,10 +626,16 @@ int mdep_set_other_regs(pid_t pid, REG_SET * data, size_t * done_offs, size_t * done_size) { assert(data_offs >= offsetof(REG_SET, other)); assert(data_offs + data_size <= offsetof(REG_SET, other) + sizeof(data->other)); - if (ptrace(PTRACE_SETFPXREGS, pid, 0, &data->other) < 0) return -1; - *done_offs = offsetof(REG_SET, other); - *done_size = sizeof(data->other); - return 0; +#if defined(__i386__) + if (data_offs >= REG_OFFSET(other.fpx) && data_offs < REG_OFFSET(other.fpx) + sizeof(data->other.fpx)) { + if (ptrace(PTRACE_SETFPXREGS, pid, 0, &data->other.fpx) < 0) return -1; + *done_offs = offsetof(REG_SET, other.fpx); + *done_size = sizeof(data->other.fpx); + return 0; + } +#endif + errno = ERR_UNSUPPORTED; + return -1; } #endif @@ -628,6 +654,8 @@ RegisterDefinition * get_386_reg_by_id(Context * ctx, unsigned id_type, unsigned case 7: /* edi */ id = 5; break; case 8: /* eip */ id = 16; break; case 9: /* eflags */ id = 49; break; + case 58: /* fs_base */ id = 158; break; + case 59: /* gs_base */ id = 159; break; default: set_errno(ERR_OTHER, "Invalid register ID"); return NULL; @@ -677,6 +705,15 @@ RegisterDefinition * get_386_reg_by_id(Context * ctx, unsigned id_type, unsigned #define POP_EBP 0x5d #endif +static int read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { +#if ENABLE_MemoryAccessModes + static MemoryAccessMode mem_access_mode = { 0, 0, 0, 0, 0, 0, 1 }; + return context_read_mem_ext(ctx, &mem_access_mode, address, buf, size); +#else + return context_read_mem(ctx, address, buf, size); +#endif +} + static int read_stack(Context * ctx, ContextAddress addr, void * buf, size_t size) { if (addr == 0) { errno = ERR_INV_ADDRESS; @@ -691,7 +728,7 @@ static int read_stack(Context * ctx, ContextAddress addr, void * buf, size_t siz } } #endif - return context_read_mem(ctx, addr, buf, size); + return read_mem(ctx, addr, buf, size); } static int read_reg(StackFrame * frame, RegisterDefinition * def, size_t size, ContextAddress * addr) { @@ -736,25 +773,25 @@ static ContextAddress trace_jump(Context * ctx, ContextAddress addr, int x64, ui while (cnt < 100) { unsigned char instr; /* instruction opcode at <addr> */ ContextAddress dest; /* Jump destination address */ - if (context_read_mem(ctx, addr, &instr, 1) < 0) break; + if (read_mem(ctx, addr, &instr, 1) < 0) break; /* If instruction is a JMP, get destination adrs */ if (instr == JMPD08) { signed char disp08; - if (context_read_mem(ctx, addr + 1, &disp08, 1) < 0) break; + if (read_mem(ctx, addr + 1, &disp08, 1) < 0) break; dest = addr + 2 + disp08; } else if (instr == JMPD32) { int32_t disp32 = 0; - if (context_read_mem(ctx, addr + 1, &disp32, 4) < 0) break; + if (read_mem(ctx, addr + 1, &disp32, 4) < 0) break; dest = addr + 5 + disp32; } else if (instr == GRP5) { ContextAddress ptr; - if (context_read_mem(ctx, addr + 1, &instr, 1) < 0) break; + if (read_mem(ctx, addr + 1, &instr, 1) < 0) break; if (instr != JMPN) break; - if (context_read_mem(ctx, addr + 2, &ptr, sizeof(ptr)) < 0) break; - if (context_read_mem(ctx, ptr, &dest, sizeof(dest)) < 0) break; + if (read_mem(ctx, addr + 2, &ptr, sizeof(ptr)) < 0) break; + if (read_mem(ctx, ptr, &dest, sizeof(dest)) < 0) break; } else if (instr == MOVE_rm) { unsigned char modrm = 0; @@ -764,7 +801,7 @@ static ContextAddress trace_jump(Context * ctx, ContextAddress addr, int x64, ui static int reg_to_dwarf_id_32[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; static int reg_to_dwarf_id_64[] = { 0, 2, 1, 3, 7, 6, 4, 5 }; int * reg_to_dwarf_id = x64 ? reg_to_dwarf_id_64 : reg_to_dwarf_id_32; - if (context_read_mem(ctx, addr + 1, &modrm, 1) < 0) break; + if (read_mem(ctx, addr + 1, &modrm, 1) < 0) break; mod = modrm >> 6; reg = (modrm >> 3) & 7u; rm = modrm & 7u; @@ -823,9 +860,9 @@ static int is_func_exit(unsigned char * code) { int crawl_stack_frame(StackFrame * frame, StackFrame * down) { - static RegisterDefinition * pc_def = NULL; - static RegisterDefinition * sp_def = NULL; - static RegisterDefinition * bp_def = NULL; + RegisterDefinition * pc_def = NULL; + RegisterDefinition * sp_def = NULL; + RegisterDefinition * bp_def = NULL; ContextAddress reg_pc = 0; ContextAddress reg_bp = 0; @@ -838,13 +875,17 @@ int crawl_stack_frame(StackFrame * frame, StackFrame * down) { size_t word_size = context_word_size(ctx); int x64 = word_size == 8; - if (pc_def == NULL) { - RegisterDefinition * r; - for (r = get_reg_definitions(ctx); r->name != NULL; r++) { + { + RegisterDefinition * r = get_reg_definitions(ctx); + if (r == NULL) return 0; + for (; r->name != NULL; r++) { if (r->offset == offsetof(REG_SET, REG_IP)) pc_def = r; if (r->offset == offsetof(REG_SET, REG_SP)) sp_def = r; if (r->offset == offsetof(REG_SET, REG_BP)) bp_def = r; } + if (pc_def == NULL) return 0; + if (sp_def == NULL) return 0; + if (bp_def == NULL) return 0; } if (read_reg(frame, pc_def, word_size, ®_pc) < 0) return 0; @@ -903,7 +944,7 @@ int crawl_stack_frame(StackFrame * frame, StackFrame * down) { else { unsigned char code[5]; - if (context_read_mem(ctx, addr - 1, code, sizeof(code)) < 0) return -1; + if (read_mem(ctx, addr - 1, code, sizeof(code)) < 0) return -1; if (code[1] == RET || code[1] == RETADD) { dwn_sp = reg_sp + word_size; @@ -939,7 +980,7 @@ int crawl_stack_frame(StackFrame * frame, StackFrame * down) { if (reg == pc_def || reg == sp_def || reg == bp_def) continue; if (reg->dwarf_id < 32 && (reg_mask & ((uint32_t)1 << reg->dwarf_id))) continue; if (context_read_reg(ctx, reg, 0, reg->size, buf) < 0) continue; - write_reg_bytes(down, reg, 0, reg->size, buf); + if (write_reg_bytes(down, reg, 0, reg->size, buf) < 0) return -1; } } } @@ -1087,7 +1128,10 @@ static void ini_eflags_bits(void) { #if ENABLE_HardwareBreakpoints #define MAX_HW_BPS 4 + +#ifndef ENABLE_BP_ACCESS_INSTRUCTION #define ENABLE_BP_ACCESS_INSTRUCTION 0 +#endif typedef struct ContextExtensionX86 { ContextBreakpoint * triggered_hw_bps[MAX_HW_BPS + 1]; @@ -1120,7 +1164,7 @@ static RegisterDefinition * get_DR_definition(unsigned no) { } static int skip_read_only_breakpoint(Context * ctx, uint8_t dr6, ContextBreakpoint * bp) { - int i; + unsigned i; int read_write_hit = 0; ContextExtensionX86 * bps = EXT(context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT)); @@ -1139,7 +1183,7 @@ static int skip_read_only_breakpoint(Context * ctx, uint8_t dr6, ContextBreakpoi } static int set_debug_regs(Context * ctx, int check_ip, int * step_over_hw_bp) { - int i; + unsigned i; uint32_t dr7 = 0; ContextAddress ip = 0; ContextExtensionX86 * ext = EXT(ctx); @@ -1225,6 +1269,7 @@ int cpu_bp_get_capabilities(Context * ctx) { int cpu_bp_plant(ContextBreakpoint * bp) { Context * ctx = bp->ctx; assert(bp->access_types); + assert(bp->id == 0); if (bp->access_types & CTX_BP_ACCESS_VIRTUAL) { ContextExtensionX86 * bps = EXT(ctx); if (bp->length <= 8 && ((1u << bp->length) & 0x116u)) { @@ -1263,7 +1308,7 @@ int cpu_bp_plant(ContextBreakpoint * bp) { if (bps->hw_bps[i] == NULL) { bps->hw_bps[i] = bp; bps->hw_idx[i] = m++; - bp->id = i; + bp->id |= 1 << i; } } if (m == n) { @@ -1276,6 +1321,7 @@ int cpu_bp_plant(ContextBreakpoint * bp) { for (i = 0; i < MAX_HW_BPS && n > 0; i++) { if (bps->hw_bps[i] == bp) bps->hw_bps[i] = NULL; } + bp->id = 0; return -1; } } @@ -1287,6 +1333,7 @@ int cpu_bp_plant(ContextBreakpoint * bp) { if (bps->hw_bps[i] == bp) bps->hw_bps[i] = NULL; } set_errno(ERR_UNSUPPORTED, "All hardware breakpoints are already in use"); + bp->id = 0; return -1; } } @@ -1295,14 +1342,16 @@ int cpu_bp_plant(ContextBreakpoint * bp) { } int cpu_bp_remove(ContextBreakpoint * bp) { - int i; + unsigned i; LINK * l = NULL; Context * ctx = bp->ctx; ContextExtensionX86 * bps = EXT(ctx); + assert(bp->id != 0); for (i = 0; i < MAX_HW_BPS; i++) { if (bps->hw_bps[i] == bp) { bps->hw_bps[i] = NULL; bps->hw_bps_generation++; + assert(bp->id & (1 << i)); } } l = context_root.next; @@ -1313,6 +1362,7 @@ int cpu_bp_remove(ContextBreakpoint * bp) { } l = l->next; } + bp->id = 0; return 0; } @@ -1334,13 +1384,14 @@ int cpu_bp_on_suspend(Context * ctx, int * triggered) { if (context_read_reg(ctx, get_DR_definition(6), 0, sizeof(dr6), &dr6) < 0) return -1; if (dr6 & 0xfu) { - int i; + unsigned i; ContextExtensionX86 * ext = EXT(ctx); ContextExtensionX86 * bps = EXT(context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT)); for (i = 0; i < MAX_HW_BPS; i++) { if (dr6 & ((uint32_t)1 << i)) { ContextBreakpoint * bp = bps->hw_bps[i]; if (bp == NULL) continue; + assert(bp->id != 0); if (bp->access_types == (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_VIRTUAL)) { if (skip_read_only_breakpoint(ctx, dr6, bp)) continue; } diff --git a/agent/machine/x86_64/tcf/cpudefs-mdep.h b/agent/machine/x86_64/tcf/cpudefs-mdep.h index 227f010f..6ae1f0b6 100644 --- a/agent/machine/x86_64/tcf/cpudefs-mdep.h +++ b/agent/machine/x86_64/tcf/cpudefs-mdep.h @@ -51,8 +51,10 @@ extern void add_cpudefs_disassembler(Context * cpu_ctx); extern RegisterDefinition * regs_index; extern unsigned char BREAK_INST[1]; +#if !defined(ENABLE_ini_cpudefs_mdep) #define ENABLE_ini_cpudefs_mdep 1 extern void ini_cpudefs_mdep(void); +#endif #if defined(__x86_64__) extern RegisterDefinition * get_386_reg_by_id(Context * ctx, unsigned id_type, unsigned id); diff --git a/agent/machine/x86_64/tcf/disassembler-x86_64.c b/agent/machine/x86_64/tcf/disassembler-x86_64.c index 9158f016..327221f3 100644 --- a/agent/machine/x86_64/tcf/disassembler-x86_64.c +++ b/agent/machine/x86_64/tcf/disassembler-x86_64.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Xilinx, Inc. and others. + * Copyright (c) 2015-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. @@ -23,23 +23,38 @@ #include <tcf/services/symbols.h> #include <machine/x86_64/tcf/disassembler-x86_64.h> +#define MODE_16 0 +#define MODE_32 1 +#define MODE_64 2 + #define PREFIX_LOCK 0x0001 -#define PREFIX_REPNZ 0x0002 -#define PREFIX_REPZ 0x0004 -#define PREFIX_CS 0x0008 +#define PREFIX_REPNZ 0x0002 /* 0xf2 */ +#define PREFIX_REPZ 0x0004 /* 0xf3 */ +#define PREFIX_CS 0x0008 /* Also "Branch not taken" hint */ #define PREFIX_SS 0x0010 -#define PREFIX_DS 0x0020 +#define PREFIX_DS 0x0020 /* Also "Branch taken" hint */ #define PREFIX_ES 0x0040 #define PREFIX_FS 0x0080 #define PREFIX_GS 0x0100 #define PREFIX_DATA_SIZE 0x0200 #define PREFIX_ADDR_SIZE 0x0400 +#define PREFIX_FWAIT 0x0800 /* 0x9b */ #define REX_W 0x08 #define REX_R 0x04 #define REX_X 0x02 #define REX_B 0x01 +#define REG_SIZE_ST 10 +#define REG_SIZE_MMX 11 +#define REG_SIZE_XMM 12 +#define REG_SIZE_YMM 13 +#define REG_SIZE_SEG 14 +#define REG_SIZE_CR 15 +#define REG_SIZE_DR 16 + +#define op_size(modrm) (((modrm >> 6) & 3) == 3 ? 0 : data_size) + static char buf[128]; static size_t buf_pos = 0; static DisassemblerParams * params = NULL; @@ -51,8 +66,12 @@ static uint32_t prefix = 0; static uint32_t vex = 0; static uint8_t rex = 0; static unsigned data_size = 0; +static unsigned push_size = 0; static unsigned addr_size = 0; -static int x86_64 = 0; +static int x86_mode = 0; +static uint8_t modrm = 0; +static uint8_t modrm_sib = 0; +static uint32_t modrm_offs = 0; static uint8_t get_code(void) { uint8_t c = 0; @@ -61,15 +80,88 @@ static uint8_t get_code(void) { return c; } +static uint32_t get_disp8(void) { + uint32_t disp = get_code(); + if (disp >= 0x80) { + disp |= 0xffffff00; + } + return disp; +} + +static uint32_t get_disp16(void) { + uint32_t disp = get_code(); + disp |= (uint32_t)get_code() << 8; + return disp; +} + +static uint32_t get_disp32(void) { + uint32_t disp = get_code(); + disp |= (uint32_t)get_code() << 8; + disp |= (uint32_t)get_code() << 16; + disp |= (uint32_t)get_code() << 24; + return disp; +} + +static void get_modrm(void) { + unsigned mod = 0; + unsigned rm = 0; + modrm = get_code(); + modrm_sib = 0; + modrm_offs = 0; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (mod == 3) return; + if (addr_size >= 4 && rm == 4) modrm_sib = get_code(); + switch (mod) { + case 0: + if (addr_size == 2 && rm == 6) modrm_offs = get_disp16(); + if (addr_size == 4 && rm == 5) modrm_offs = get_disp32(); + if (addr_size == 8 && rm == 5) modrm_offs = get_disp32(); + break; + case 1: + modrm_offs = get_disp8(); + break; + case 2: + if (addr_size <= 2) modrm_offs = get_disp16(); + else modrm_offs = get_disp32(); + break; + } + if (addr_size >= 4 && rm == 4) { + unsigned base = modrm_sib & 7; + if (base == 5 && mod == 0 && rm != 5) { + modrm_offs = get_disp32(); + } + } +} + static void add_char(char ch) { if (buf_pos >= sizeof(buf) - 1) return; buf[buf_pos++] = ch; + if (ch == ' ') { + if (buf_pos >= 4 && strncmp(buf, "bnd ", 4) == 0) return; + if (buf_pos >= 4 && strncmp(buf, "rep ", 4) == 0) return; + if (buf_pos >= 5 && strncmp(buf, "repz ", 5) == 0) return; + if (buf_pos >= 6 && strncmp(buf, "repnz ", 6) == 0) return; + while (buf_pos < 8) buf[buf_pos++] = ch; + } } static void add_str(const char * s) { while (*s) add_char(*s++); } +static void add_cmd(const char * s, unsigned size) { + while (*s) add_char(*s++); + switch (size) { + case 1: add_char('b'); break; + case 2: add_char('w'); break; + case 4: add_char('l'); break; + case 8: add_char('q'); break; + } + add_char(' '); +} + static void add_dec_uint32(uint32_t n) { char s[32]; size_t i = 0; @@ -118,6 +210,26 @@ static void add_hex_uint64(uint64_t n) { while (i > 0) add_char(s[--i]); } +static void add_0x_hex_uint32(uint32_t n) { + add_str("0x"); + add_hex_uint32(n); +} + +static void add_0x_hex_int32(int32_t n) { + if (n < 0) { + add_char('-'); + add_0x_hex_uint32(-n); + } + else { + add_0x_hex_uint32(n); + } +} + +static void add_0x_hex_uint64(uint64_t n) { + add_str("0x"); + add_hex_uint64(n); +} + #if 0 /* Not used yet */ static void add_flt_uint32(uint32_t n) { char buf[32]; @@ -143,8 +255,6 @@ static void add_flt_uint64(uint64_t n) { #endif static void add_addr(uint64_t addr) { - while (buf_pos < 16) add_char(' '); - add_str("; addr=0x"); add_hex_uint64(addr); #if ENABLE_Symbols if (params->ctx != NULL) { @@ -155,29 +265,70 @@ static void add_addr(uint64_t addr) { if (get_symbol_name(sym, &name) < 0 || name == NULL) return; if (get_symbol_address(sym, &sym_addr) < 0) return; if (sym_addr <= addr) { - add_str(": "); + add_str(" <"); add_str(name); if (sym_addr < addr) { - add_str(" + 0x"); - add_hex_uint64(addr - (uint64_t)sym_addr); + add_char('+'); + add_0x_hex_uint64(addr - (uint64_t)sym_addr); } + add_str(">"); } } #endif } static void add_reg(unsigned reg, unsigned size) { + add_char('%'); + switch (size) { + case REG_SIZE_ST: + add_str("st"); + add_dec_uint32(reg & 7); + return; + case REG_SIZE_MMX: + add_str("mm"); + add_dec_uint32(reg & 7); + return; + case REG_SIZE_XMM: + add_str("xmm"); + add_dec_uint32(reg); + return; + case REG_SIZE_YMM: + add_str("ymm"); + add_dec_uint32(reg); + return; + case REG_SIZE_SEG: + switch (reg & 7) { + case 0: add_str("es"); break; + case 1: add_str("cs"); break; + case 2: add_str("ss"); break; + case 3: add_str("ds"); break; + case 4: add_str("fs"); break; + case 5: add_str("gs"); break; + case 6: add_str("s6"); break; + case 7: add_str("s7"); break; + } + return; + case REG_SIZE_CR: + add_str("cr"); + add_dec_uint32(reg); + return; + case REG_SIZE_DR: + add_str("dr"); + add_dec_uint32(reg); + return; + } + assert(size <= 8); if (reg >= 8) { add_char('r'); add_dec_uint32(reg); switch (size) { - case 1: add_char('l'); break; + case 1: add_char('b'); break; case 2: add_char('w'); break; case 4: add_char('d'); break; } return; } - if (x86_64 && size == 1 && reg >= 4 && reg <= 7) { + if (rex && size == 1 && reg >= 4 && reg <= 7) { switch (reg) { case 4: add_str("spl"); break; case 5: add_str("bpl"); break; @@ -216,31 +367,6 @@ static void add_reg(unsigned reg, unsigned size) { } } -static void add_seg_reg(unsigned reg) { - switch (reg) { - case 0: add_str("es"); break; - case 1: add_str("cs"); break; - case 2: add_str("ss"); break; - case 3: add_str("ds"); break; - case 4: add_str("fs"); break; - case 5: add_str("gs"); break; - case 6: add_str("s6"); break; - case 7: add_str("s7"); break; - } -} - -#if 0 -static void add_ctrl_reg(unsigned reg) { - add_str("cr"); - add_dec_uint32(reg); -} - -static void add_dbg_reg(unsigned reg) { - add_str("dr"); - add_dec_uint32(reg); -} -#endif - static void add_ttt(unsigned ttt) { switch (ttt) { case 0: add_str("o"); break; @@ -253,8 +379,8 @@ static void add_ttt(unsigned ttt) { case 7: add_str("a"); break; case 8: add_str("s"); break; case 9: add_str("ns"); break; - case 10: add_str("pe"); break; - case 11: add_str("po"); break; + case 10: add_str("p"); break; + case 11: add_str("np"); break; case 12: add_str("l"); break; case 13: add_str("ge"); break; case 14: add_str("le"); break; @@ -262,46 +388,23 @@ static void add_ttt(unsigned ttt) { } } -static void add_disp8(void) { - uint32_t disp = get_code(); - if (disp < 0x80) { - add_char('+'); - } - else { - add_char('-'); - disp = (disp ^ 0xff) + 1; - } - add_str("0x"); - add_hex_uint32(disp); -} - -static void add_disp16(void) { - uint32_t disp = get_code(); - disp |= (uint32_t)get_code() << 8; - add_str("0x"); - add_hex_uint32(disp); -} - -static void add_disp32(void) { - uint32_t disp = get_code(); - disp |= (uint32_t)get_code() << 8; - disp |= (uint32_t)get_code() << 16; - disp |= (uint32_t)get_code() << 24; - add_str("0x"); - add_hex_uint32(disp); -} - -static void add_imm8(void) { +static void add_imm8(unsigned size) { uint32_t imm = get_code(); - add_str("0x"); + add_str("$0x"); + if (imm & 0x80) { + while (size > 1) { + add_str("ff"); + size--; + } + } add_hex_uint32(imm); } static void add_imm16(void) { uint32_t imm = get_code(); imm |= (uint32_t)get_code() << 8; - add_str("0x"); - add_hex_uint32(imm); + add_char('$'); + add_0x_hex_uint32(imm); } static void add_imm32(void) { @@ -309,11 +412,25 @@ static void add_imm32(void) { imm |= (uint32_t)get_code() << 8; imm |= (uint32_t)get_code() << 16; imm |= (uint32_t)get_code() << 24; - add_str("0x"); + add_char('$'); + add_0x_hex_uint32(imm); +} + +static void add_imm32s(unsigned size) { + uint32_t imm = get_code(); + imm |= (uint32_t)get_code() << 8; + imm |= (uint32_t)get_code() << 16; + imm |= (uint32_t)get_code() << 24; + add_str("$0x"); + if (imm & 0x80000000) { + while (size > 4) { + add_str("ff"); + size--; + } + } add_hex_uint32(imm); } -#if 0 /* Not used yet */ static void add_imm64(void) { uint64_t imm = get_code(); imm |= (uint64_t)get_code() << 8; @@ -323,10 +440,9 @@ static void add_imm64(void) { imm |= (uint64_t)get_code() << 40; imm |= (uint64_t)get_code() << 48; imm |= (uint64_t)get_code() << 56; - add_str("0x"); - add_hex_uint64(imm); + add_char('$'); + add_0x_hex_uint64(imm); } -#endif static void add_moffs(int wide) { uint64_t addr = 0; @@ -337,9 +453,14 @@ static void add_moffs(int wide) { i++; } - add_str("[0x"); - add_hex_uint64(addr); - add_char(']'); + if (prefix & PREFIX_CS) add_str("%cs:"); + if (prefix & PREFIX_SS) add_str("%ss:"); + if (prefix & PREFIX_DS) add_str("%ds:"); + if (prefix & PREFIX_ES) add_str("%es:"); + if (prefix & PREFIX_FS) add_str("%fs:"); + if (prefix & PREFIX_GS) add_str("%gs:"); + + add_0x_hex_uint64(addr); } static void add_rel(unsigned size) { @@ -355,74 +476,48 @@ static void add_rel(unsigned size) { if (offs & sign) { offs = (offs ^ (sign | mask)) + 1; - add_str("-0x"); - add_hex_uint64(offs); add_addr(instr_addr + code_pos - offs); } else { - add_str("+0x"); - add_hex_uint64(offs); add_addr(instr_addr + code_pos + offs); } } -static void add_modrm(unsigned modrm, unsigned size) { +static void add_modrm_reg(unsigned size) { + unsigned rm = (modrm >> 3) & 7; + if (rex & REX_R) rm += 8; + add_reg(rm, size); +} + +static void add_modrm_mem(unsigned size) { unsigned mod = (modrm >> 6) & 3; unsigned rm = modrm & 7; if (mod == 3) { + if (rex & REX_B) rm += 8; add_reg(rm, size); } else { - switch (size) { - case 1: add_str("byte"); break; - case 2: add_str("word"); break; - case 4: add_str("dword"); break; - case 8: add_str("qword"); break; - } - add_char('['); - if (addr_size == 4) { - switch (rm) { - case 0: add_str("eax"); break; - case 1: add_str("acx"); break; - case 2: add_str("edx"); break; - case 3: add_str("ebx"); break; - case 4: - { - uint8_t sib = get_code(); - unsigned base = sib & 7; - unsigned index = (sib >> 3) & 7; - unsigned scale = (sib >> 6) & 3; - int bs = 0; - if ((mod == 0 && base != 5) || mod == 1 || mod == 2) { - add_reg(base, 4); - bs = 1; - } - if (index != 4) { - if (bs) add_char('+'); - add_reg(index, 4); - switch (scale) { - case 1: add_str("*2"); break; - case 2: add_str("*4"); break; - case 3: add_str("*8"); break; - } - bs = 1; - } - if ((mod == 0 && base == 5) || mod == 2) { - if (bs) add_char('+'); - add_disp32(); - } - else if (mod == 1) { - add_disp8(); - } - add_char(']'); - } - return; - case 5: if (mod != 0) add_str("ebp"); break; - case 6: add_str("esi"); break; - case 7: add_str("edi"); break; - } + if (prefix & PREFIX_CS) add_str("%cs:"); + if (prefix & PREFIX_SS) add_str("%ss:"); + if (prefix & PREFIX_DS) add_str("%ds:"); + if (prefix & PREFIX_ES) add_str("%es:"); + if (prefix & PREFIX_FS) add_str("%fs:"); + if (prefix & PREFIX_GS) add_str("%gs:"); + switch (mod) { + case 0: + if (addr_size == 2 && rm == 6) add_0x_hex_int32(modrm_offs); + if (addr_size == 4 && rm == 5) add_0x_hex_int32(modrm_offs); + if (addr_size == 8 && rm == 5) add_0x_hex_int32(modrm_offs); + break; + case 1: + add_0x_hex_int32(modrm_offs); + break; + case 2: + add_0x_hex_int32(modrm_offs); + break; } - else { + if (addr_size < 4) { + add_char('('); switch (rm) { case 0: add_str("bx+si"); break; case 1: add_str("bx+di"); break; @@ -433,76 +528,629 @@ static void add_modrm(unsigned modrm, unsigned size) { case 6: if (mod != 0) add_str("bp"); break; case 7: add_str("bx"); break; } + add_char(')'); } - switch (mod) { - case 0: - if (addr_size == 2 && rm == 6) add_disp16(); - if (addr_size == 4 && rm == 5) add_disp32(); - if (addr_size == 8 && rm == 5) add_disp32(); - break; - case 1: - add_disp8(); - break; - case 2: - add_char('+'); - if (addr_size <= 2) add_disp16(); - else add_disp32(); - break; + else { + if (rm == 5 && mod == 0) { + if (x86_mode == MODE_64) { + add_char('('); + add_str(addr_size > 4 ? "%rip" : "%eip"); + add_char(')'); + } + } + else if (rm == 4) { + unsigned base = modrm_sib & 7; + unsigned index = (modrm_sib >> 3) & 7; + unsigned scale = (modrm_sib >> 6) & 3; + int bs = 0; + if (base == 5 && mod == 0) { + if (index == 4 && (rex & REX_X) == 0) { + /* Absolute address */ + if (addr_size == 8) add_0x_hex_uint64((int32_t)modrm_offs); + else add_0x_hex_uint32(modrm_offs); + } + else { + add_0x_hex_int32(modrm_offs); + } + } + if (base != 5 || mod == 1 || mod == 2) { + add_char('('); + if (rex & REX_B) add_reg(base + 8, addr_size); + else add_reg(base, addr_size); + bs = 1; + } + if (index != 4 || (rex & REX_X) != 0) { + if (!bs) add_char('('); + add_char(','); + if (rex & REX_X) add_reg(index + 8, addr_size); + else add_reg(index, addr_size); + add_char(','); + switch (scale) { + case 1: add_char('2'); break; + case 2: add_char('4'); break; + case 3: add_char('8'); break; + default: add_char('1'); break; + } + bs = 1; + } + if (bs) add_char(')'); + } + else { + add_char('('); + if (rex & REX_B) rm += 8; + add_reg(rm, addr_size); + add_char(')'); + } } - add_char(']'); } } -static void add_a_op(unsigned op) { +static void add_modrm(unsigned reg_size, unsigned mem_size, int swap) { + get_modrm(); + if (swap) { + add_modrm_mem(mem_size); + add_char(','); + add_modrm_reg(reg_size); + } + else { + add_modrm_reg(reg_size); + add_char(','); + add_modrm_mem(mem_size); + } +} + +static void add_a_op(unsigned op, unsigned size) { switch (op) { - case 0: add_str("add "); break; - case 1: add_str("or "); break; - case 2: add_str("adc "); break; - case 3: add_str("sbb "); break; - case 4: add_str("and "); break; - case 5: add_str("sub "); break; - case 6: add_str("xor "); break; - case 7: add_str("cmp "); break; + case 0: add_cmd("add", size); break; + case 1: add_cmd("or", size); break; + case 2: add_cmd("adc", size); break; + case 3: add_cmd("sbb", size); break; + case 4: add_cmd("and", size); break; + case 5: add_cmd("sub", size); break; + case 6: add_cmd("xor", size); break; + case 7: add_cmd("cmp", size); break; } } -static int shift_op(unsigned op) { +static int shift_op(unsigned op, unsigned size) { switch (op) { - case 0: add_str("rol "); return 1; - case 1: add_str("ror "); return 1; - case 2: add_str("rcl "); return 1; - case 3: add_str("rcr "); return 1; - case 4: add_str("shl "); return 1; - case 5: add_str("shr "); return 1; - case 7: add_str("sar "); return 1; + case 0: add_cmd("rol", size); return 1; + case 1: add_cmd("ror", size); return 1; + case 2: add_cmd("rcl", size); return 1; + case 3: add_cmd("rcr", size); return 1; + case 4: add_cmd("shl", size); return 1; + case 5: add_cmd("shr", size); return 1; + case 7: add_cmd("sar", size); return 1; } return 0; } static void disassemble_0f(void) { uint8_t opcode = get_code(); - uint8_t modrm = 0; switch (opcode) { + case 0x08: + add_str("invd"); + return; + case 0x09: + add_str("wbind"); + return; + case 0x0b: + add_str("ud2"); + return; + case 0x10: + case 0x11: + add_str("mov"); + if (prefix & PREFIX_REPZ) { + add_str("ss "); + add_modrm(REG_SIZE_XMM, 4, (opcode & 1) == 0); + return; + } + if (prefix & PREFIX_REPNZ) { + add_str("sd "); + add_modrm(REG_SIZE_XMM, 8, (opcode & 1) == 0); + return; + } + if (prefix & PREFIX_DATA_SIZE) { + add_str("upd "); + add_modrm(REG_SIZE_XMM, 16, (opcode & 1) == 0); + return; + } + add_str("ups "); + add_modrm(REG_SIZE_XMM, 16, (opcode & 1) == 0); + return; + case 0x17: + add_str("mov"); + if (prefix & PREFIX_DATA_SIZE) { + add_str("hpd "); + add_modrm(REG_SIZE_YMM, 8, (opcode & 1) != 0); + return; + } + add_str("hps "); + add_modrm(REG_SIZE_XMM, 4, 1); + return; + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + get_modrm(); + if (prefix & PREFIX_REPZ) { + if (opcode == 0x1e) { + if (modrm == 0xfa) { + add_str("endbr64"); + return; + } + if (modrm == 0xfb) { + add_str("endbr32"); + return; + } + } + } + add_str("hint_nop "); + add_modrm_mem(data_size); + return; case 0x1f: - modrm = get_code(); - add_str("nop "); - add_modrm(modrm, data_size); + get_modrm(); + add_cmd("nop", data_size); + add_modrm_mem(data_size); + return; + case 0x28: + case 0x29: + add_str("mov"); + if (prefix & PREFIX_DATA_SIZE) { + add_str("apd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, (opcode & 1) == 0); + return; + } + add_str("aps "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, (opcode & 1) == 0); + return; + case 0x2a: + if (prefix & PREFIX_REPNZ) { + get_modrm(); + add_cmd("cvtsi2sd", op_size(modrm)); + add_modrm_mem(data_size); + add_char(','); + add_modrm_reg(REG_SIZE_XMM); + return; + } + if (prefix & PREFIX_REPZ) { + get_modrm(); + add_cmd("cvtsi2ss", op_size(modrm)); + add_modrm_mem(data_size); + add_char(','); + add_modrm_reg(REG_SIZE_XMM); + return; + } + if (prefix & PREFIX_DATA_SIZE) { + add_str("cvtpi2pd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_str("cvtpi2ps "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + case 0x2c: + case 0x2d: + switch (opcode) { + case 0x2c: add_str("cvtt"); break; + case 0x2d: add_str("cvt"); break; + } + if (prefix & PREFIX_REPNZ) { + add_str("sd2si "); + add_modrm(data_size, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_REPZ) { + add_str("ss2si "); + add_modrm(data_size, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_DATA_SIZE) { + add_str("pd2pi "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_str("ps2pi "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + case 0x2e: + case 0x2f: + switch (opcode) { + case 0x2e: add_str("ucomi"); break; + case 0x2f: add_str("comi"); break; + } + if (prefix & PREFIX_DATA_SIZE) { + add_str("sd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_str("ss "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); return; case 0x38: switch (get_code()) { + case 0x1c: + add_str("pabsb "); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_modrm(REG_SIZE_MMX, REG_SIZE_MMX, 1); + return; + case 0x1d: + add_str("pabsw "); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_modrm(REG_SIZE_MMX, REG_SIZE_MMX, 1); + return; + case 0x1e: + add_str("pabsd "); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_modrm(REG_SIZE_MMX, REG_SIZE_MMX, 1); + return; + case 0x2b: + if (prefix & PREFIX_DATA_SIZE) { + add_str("packusdw "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + break; + case 0x38: + if (prefix & PREFIX_DATA_SIZE) { + add_str("pminsb "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + break; + case 0x39: + if (prefix & PREFIX_DATA_SIZE) { + add_str("pminsd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + break; + case 0x3c: + if (prefix & PREFIX_DATA_SIZE) { + add_str("pmaxsb "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + break; + case 0x3d: + if (prefix & PREFIX_DATA_SIZE) { + add_str("pmaxsd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + break; + case 0x3e: + if (prefix & PREFIX_DATA_SIZE) { + add_str("pmaxuw "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + break; case 0xf6: if (prefix & PREFIX_DATA_SIZE) { - modrm = get_code(); add_str("adcx "); - add_reg((modrm >> 3) & 7, data_size); - add_char(','); - add_modrm(modrm, 1); + add_modrm(data_size, 1, 0); return; } break; } break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + add_str("cmov"); + add_ttt(opcode & 0xf); + add_char(' '); + add_modrm(data_size, data_size, 1); + return; + case 0x51: + case 0x58: + case 0x59: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + switch (opcode) { + case 0x51: add_str("sqrt"); break; + case 0x58: add_str("add"); break; + case 0x59: add_str("mul"); break; + case 0x5c: add_str("sub"); break; + case 0x5d: add_str("min"); break; + case 0x5e: add_str("div"); break; + case 0x5f: add_str("max"); break; + } + if (prefix & PREFIX_DATA_SIZE) { + add_str("pd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_REPNZ) { + add_str("sd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_REPZ) { + add_str("ss "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_str("ps "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + case 0x54: + case 0x55: + case 0x56: + case 0x57: + switch (opcode) { + case 0x54: add_str("and"); break; + case 0x55: add_str("andn"); break; + case 0x56: add_str("or"); break; + case 0x57: add_str("xor"); break; + } + if (prefix & PREFIX_DATA_SIZE) { + add_str("pd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_str("ps "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + case 0x5a: + if (prefix & PREFIX_DATA_SIZE) { + add_str("cvtpd2ps "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_REPZ) { + add_str("cvtss2sd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_REPNZ) { + add_str("cvtsd2ss "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_str("cvtps2pd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + case 0x5b: + if (prefix & PREFIX_DATA_SIZE) { + add_str("cvtps2dq "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_REPZ) { + add_str("cvttps2dq "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_str("cvtdq2ps "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + { + static const char * nm[] = { + "punpcklbw", "punpcklwd", "punpckldq", "packsswb", + "pcmpgtb", "pcmpgtw", "pcmpgtd", "packuswb", + "punpckhbw", "punpckhwd", "punpckhdq", "packssdw", + "punpcklqdq", "punpckhqdq", + }; + add_str(nm[opcode - 0x60]); + add_char(' '); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_modrm(REG_SIZE_MMX, REG_SIZE_MMX, 1); + } + return; + case 0x6e: + if (rex & REX_W) add_str("movq "); + else add_str("movd "); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm(REG_SIZE_XMM, data_size, 1); + return; + } + add_modrm(REG_SIZE_MMX, data_size, 1); + return; + case 0x6f: + case 0x7f: + add_str("mov"); + if (prefix & PREFIX_DATA_SIZE) { + add_str("dqa "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, (opcode & 0x10) == 0); + return; + } + if (prefix & PREFIX_REPZ) { + add_str("dqu "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, (opcode & 0x10) == 0); + return; + } + add_str("q "); + add_modrm(REG_SIZE_MMX, REG_SIZE_MMX, (opcode & 0x10) == 0); + return; + case 0x70: + add_str("pshuf"); + get_modrm(); + if (prefix & PREFIX_REPNZ) { + add_str("lw "); + add_imm8(0); + add_char(','); + add_modrm_mem(REG_SIZE_XMM); + add_char(','); + add_modrm_reg(REG_SIZE_XMM); + return; + } + if (prefix & PREFIX_REPZ) { + add_str("hw "); + add_imm8(0); + add_char(','); + add_modrm_mem(REG_SIZE_XMM); + add_char(','); + add_modrm_reg(REG_SIZE_XMM); + return; + } + if (prefix & PREFIX_DATA_SIZE) { + add_str("d "); + add_imm8(0); + add_char(','); + add_modrm_mem(REG_SIZE_XMM); + add_char(','); + add_modrm_reg(REG_SIZE_XMM); + return; + } + add_str("w "); + add_imm8(0); + add_char(','); + add_modrm_mem(REG_SIZE_MMX); + add_char(','); + add_modrm_reg(REG_SIZE_MMX); + return; + case 0x71: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 2: add_str("psrlw"); break; + case 4: add_str("psraw"); break; + case 6: add_str("psllw"); break; + default: buf_pos = 0; return; + } + add_char(' '); + add_imm8(0); + add_char(','); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm_mem(REG_SIZE_XMM); + } + else { + add_modrm_mem(REG_SIZE_MMX); + } + return; + case 0x72: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 2: add_str("psrld"); break; + case 4: add_str("psrad"); break; + case 6: add_str("pslld"); break; + default: buf_pos = 0; return; + } + add_char(' '); + add_imm8(0); + add_char(','); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm_mem(REG_SIZE_XMM); + } + else { + add_modrm_mem(REG_SIZE_MMX); + } + return; + case 0x73: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 2: add_str("psrlq"); break; + case 3: add_str("psrldq"); break; + case 6: add_str("psllq"); break; + case 7: add_str("pslldq"); break; + default: buf_pos = 0; return; + } + add_char(' '); + add_imm8(0); + add_char(','); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm_mem(REG_SIZE_XMM); + } + else { + add_modrm_mem(REG_SIZE_MMX); + } + return; + case 0x74: + add_str("pcmpeqb "); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_modrm(REG_SIZE_MMX, REG_SIZE_MMX, 1); + return; + case 0x76: + add_str("pcmpeqd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + case 0x77: + add_str("emms"); + return; + case 0x78: + add_str("vmread "); + add_modrm(8, 8, 1); + return; + case 0x79: + add_str("vmwrite "); + add_modrm(8, 8, 1); + return; + case 0x7c: + case 0x7d: + add_str((opcode & 1) == 0 ? "hadd" : "hsub"); + if (prefix & PREFIX_DATA_SIZE) { + add_str("pd "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + if (prefix & PREFIX_REPNZ) { + add_str("ps "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + break; + case 0x7e: + if (prefix & PREFIX_REPZ) { + add_str("movq "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + if (rex & REX_W) { + add_str("movq "); + add_modrm(REG_SIZE_XMM, 8, 0); + return; + } + add_str("movd "); + add_modrm(REG_SIZE_XMM, 4, 0); + return; case 0x80: case 0x81: case 0x82: @@ -524,28 +1172,54 @@ static void disassemble_0f(void) { add_char(' '); add_rel(4); return; + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + get_modrm(); + add_str("set"); + add_ttt(opcode & 0xf); + add_char(' '); + add_modrm_mem(1); + return; case 0xa0: add_str("push fs"); return; case 0xa1: add_str("pop fs"); return; + case 0xa2: + add_str("cpuid"); + return; + case 0xa3: + add_str("bt "); + add_modrm(data_size, data_size, 0); + return; case 0xa4: + get_modrm(); add_str("shld "); - modrm = get_code(); - add_modrm(modrm, data_size); + add_imm8(0); add_char(','); - add_reg((modrm >> 3) & 7, data_size); + add_modrm_reg(data_size); add_char(','); - add_imm8(); + add_modrm_mem(data_size); return; case 0xa5: add_str("shld "); - modrm = get_code(); - add_modrm(modrm, data_size); - add_char(','); - add_reg((modrm >> 3) & 7, data_size); - add_str(",cl"); + add_str("%cl,"); + add_modrm(data_size, data_size, 0); return; case 0xa8: add_str("push gs"); @@ -553,34 +1227,234 @@ static void disassemble_0f(void) { case 0xa9: add_str("pop gs"); return; - case 0xb6: - add_str("movzx "); - modrm = get_code(); - add_reg((modrm >> 3) & 7, data_size); + case 0xac: + get_modrm(); + add_str("shrd "); + add_imm8(0); + add_char(','); + add_modrm_reg(data_size); add_char(','); - add_modrm(modrm, 1); + add_modrm_mem(data_size); + return; + case 0xae: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 0: add_str("fxsave "); break; + case 1: add_str("fxrstor "); break; + case 2: add_str("ldmxcsr "); break; + case 3: add_str("stmxcsr "); break; + case 4: add_str("xszve "); break; + case 5: add_str("lfence"); break; + case 6: add_str("mfence"); break; + case 7: add_str("sfence"); break; + } + return; + case 0xaf: + add_str("imul "); + add_modrm(data_size, data_size, 1); + return; + case 0xb0: + add_str("cmpxchg "); + add_modrm(1, 1, 1); + return; + case 0xb1: + add_str("cmpxchg "); + add_modrm(data_size, data_size, 1); + return; + case 0xb3: + add_str("btr "); + add_modrm(data_size, data_size, 1); + return; + case 0xb6: + add_cmd("movzb", data_size); + add_modrm(data_size, 1, 1); return; case 0xb7: - add_str("movzx "); - modrm = get_code(); - add_reg((modrm >> 3) & 7, data_size); + add_cmd("movzw", data_size); + add_modrm(data_size, 2, 1); + return; + case 0xba: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 0: buf_pos = 0; return; + case 1: buf_pos = 0; return; + case 2: buf_pos = 0; return; + case 3: buf_pos = 0; return; + case 4: add_cmd("bt", op_size(modrm)); break; + case 5: add_cmd("bts", op_size(modrm)); break; + case 6: add_cmd("btr", op_size(modrm)); break; + case 7: add_cmd("btc", op_size(modrm)); break; + } + add_imm8(0); add_char(','); - add_modrm(modrm, 2); + add_modrm_mem(data_size); + return; + case 0xbb: + add_str("btc "); + add_modrm(data_size, data_size, 1); + return; + case 0xbc: + add_str("bfr "); + add_modrm(data_size, data_size, 1); + return; + case 0xbd: + add_str("bsr "); + add_modrm(data_size, data_size, 1); return; case 0xbe: - add_str("movsx "); - modrm = get_code(); - add_reg((modrm >> 3) & 7, data_size); - add_char(','); - add_modrm(modrm, 1); + add_cmd("movsb", data_size); + add_modrm(data_size, 1, 1); return; case 0xbf: - add_str("movsx "); - modrm = get_code(); - add_reg((modrm >> 3) & 7, data_size); + add_cmd("movsw", data_size); + add_modrm(data_size, 2, 1); + return; + case 0xc2: + get_modrm(); + add_str("cmp"); + switch (get_code()) { + case 0x00: add_str("lq"); break; + case 0x01: add_str("lt"); break; + case 0x02: add_str("le"); break; + case 0x03: add_str("unord"); break; + case 0x04: add_str("neq"); break; + case 0x05: add_str("nlt"); break; + case 0x06: add_str("nle"); break; + case 0x07: add_str("ord"); break; + case 0x08: add_str("eq_uq"); break; + case 0x09: add_str("nge"); break; + case 0x0a: add_str("ngt"); break; + case 0x0b: add_str("false"); break; + case 0x0c: add_str("neq_oq"); break; + case 0x0d: add_str("ge"); break; + case 0x0e: add_str("gt"); break; + case 0x0f: add_str("true"); break; + case 0x10: add_str("eq_os"); break; + case 0x11: add_str("lt_oq"); break; + case 0x12: add_str("le_oq"); break; + case 0x13: add_str("unord_s"); break; + case 0x14: add_str("neq_us"); break; + case 0x15: add_str("nlt_uq"); break; + case 0x16: add_str("nle_uq"); break; + case 0x17: add_str("ord_s"); break; + case 0x18: add_str("eq_us"); break; + case 0x19: add_str("nge_uq"); break; + case 0x1a: add_str("ngt_uq"); break; + case 0x1b: add_str("false_os"); break; + case 0x1c: add_str("neq_os"); break; + case 0x1d: add_str("ge_oq"); break; + case 0x1e: add_str("gt_oq"); break; + case 0x1f: add_str("true_us"); break; + default: buf_pos = 0; return; + } + if (prefix & PREFIX_DATA_SIZE) add_str("pd "); + else if (prefix & PREFIX_REPZ) add_str("ss "); + else if (prefix & PREFIX_REPNZ) add_str("sd "); + else add_str("ps "); + add_modrm_mem(REG_SIZE_XMM); add_char(','); - add_modrm(modrm, 2); + add_modrm_reg(REG_SIZE_XMM); + return; + case 0xc8: + case 0xc9: + case 0xca: + case 0xcb: + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: + add_str("bswap "); + if (rex & REX_B) add_reg((opcode & 7) + 8, data_size); + else add_reg(opcode & 7, data_size); + return; + case 0xd1: + case 0xd2: + case 0xd3: + case 0xd4: + case 0xd5: + case 0xd8: + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + case 0xe0: + case 0xe1: + case 0xe2: + case 0xe3: + case 0xe4: + case 0xe5: + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: + case 0xec: + case 0xed: + case 0xee: + case 0xef: + case 0xf1: + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfb: + case 0xfc: + case 0xfd: + case 0xfe: + { + static const char * nm[] = { + NULL, "psrlw", "psrld", "psrlq", "paddq", "pmullw", NULL, NULL, + "psubusb", "psubusw", "pminub", "pand", "paddusb", "paddusw", "pmaxb ", "pandn ", + "pavgb", "psraw", "psrad", "pavgw", "pmulhuw", "pmulhw", NULL, NULL, + "psubsb", "psubsw", "pminsw", "por", "paddsb", "paddsw", "pmaxsw", "pxor", + "psllw", "pslld", "psllq", "pmuludq", "pmaddwd", "psadbw", NULL, "psubb", + NULL, "psubw", "psubd", "psubq", "paddb", "paddw", "paddd", NULL, + }; + const char * s = nm[opcode - 0xd0]; + if (s != NULL) { + add_str(s); + add_char(' '); + if (prefix & PREFIX_DATA_SIZE) { + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 1); + return; + } + add_modrm(REG_SIZE_MMX, REG_SIZE_MMX, 1); + return; + } + } + break; + case 0xe7: + if (prefix & PREFIX_DATA_SIZE) { + add_str("movntdq "); + add_modrm(REG_SIZE_XMM, data_size, 0); + return; + } + add_str("movntq "); + add_modrm(REG_SIZE_MMX, data_size, 0); return; + case 0xd6: + if (prefix & PREFIX_DATA_SIZE) { + add_str("movq "); + add_modrm(REG_SIZE_XMM, REG_SIZE_XMM, 0); + return; + } + if (prefix & PREFIX_REPZ) { + add_str("movq2dq "); + add_modrm(REG_SIZE_MMX, REG_SIZE_XMM, 0); + return; + } + if (prefix & PREFIX_REPNZ) { + add_str("movdq2q "); + add_modrm(REG_SIZE_XMM, REG_SIZE_MMX, 0); + return; + } + break; } buf_pos = 0; @@ -588,7 +1462,6 @@ static void disassemble_0f(void) { static void disassemble_instr(void) { uint8_t opcode = 0; - uint8_t modrm = 0; uint8_t imm = 0; opcode = get_code(); @@ -601,11 +1474,8 @@ static void disassemble_instr(void) { case 0x28: case 0x30: case 0x38: - modrm = get_code(); - add_a_op((opcode >> 3) & 7); - add_modrm(modrm, 1); - add_char(','); - add_reg((modrm >> 3) & 7, 1); + add_a_op((opcode >> 3) & 7, 0); + add_modrm(1, 1, 0); return; case 0x01: case 0x09: @@ -615,11 +1485,8 @@ static void disassemble_instr(void) { case 0x29: case 0x31: case 0x39: - modrm = get_code(); - add_a_op((opcode >> 3) & 7); - add_modrm(modrm, data_size); - add_char(','); - add_reg((modrm >> 3) & 7, data_size); + add_a_op((opcode >> 3) & 7, 0); + add_modrm(data_size, data_size, 0); return; case 0x02: case 0x0a: @@ -629,11 +1496,8 @@ static void disassemble_instr(void) { case 0x2a: case 0x32: case 0x3a: - modrm = get_code(); - add_a_op((opcode >> 3) & 7); - add_reg((modrm >> 3) & 7, 1); - add_char(','); - add_modrm(modrm, 1); + add_a_op((opcode >> 3) & 7, 0); + add_modrm(1, 1, 1); return; case 0x03: case 0x0b: @@ -643,11 +1507,8 @@ static void disassemble_instr(void) { case 0x2b: case 0x33: case 0x3b: - modrm = get_code(); - add_a_op((opcode >> 3) & 7); - add_reg((modrm >> 3) & 7, data_size); - add_char(','); - add_modrm(modrm, data_size); + add_a_op((opcode >> 3) & 7, 0); + add_modrm(data_size, data_size, 1); return; case 0x04: case 0x0c: @@ -657,9 +1518,9 @@ static void disassemble_instr(void) { case 0x2c: case 0x34: case 0x3c: - add_a_op((opcode >> 3) & 7); - add_str("al,"); - add_imm8(); + add_a_op((opcode >> 3) & 7, 0); + add_imm8(0); + add_str(",%al"); return; case 0x05: case 0x0d: @@ -669,11 +1530,11 @@ static void disassemble_instr(void) { case 0x2d: case 0x35: case 0x3d: - add_a_op((opcode >> 3) & 7); - add_reg(0, data_size); - add_char(','); + add_a_op((opcode >> 3) & 7, 0); if (data_size <= 2) add_imm16(); - else add_imm32(); + else add_imm32s(data_size); + add_char(','); + add_reg(0, data_size); return; case 0x06: add_str("push es"); @@ -736,7 +1597,8 @@ static void disassemble_instr(void) { case 0x56: case 0x57: add_str("push "); - add_reg(opcode & 7, data_size); + if (rex & REX_B) add_reg((opcode & 7) + 8, addr_size); + else add_reg(opcode & 7, addr_size); return; case 0x58: case 0x59: @@ -747,16 +1609,48 @@ static void disassemble_instr(void) { case 0x5e: case 0x5f: add_str("pop "); - add_reg(opcode & 7, data_size); + if (rex & REX_B) add_reg((opcode & 7) + 8, addr_size); + else add_reg(opcode & 7, addr_size); + return; + case 0x63: + if (x86_mode == MODE_64) { + add_cmd("movsl", data_size); + add_modrm(data_size, 4, 1); + } + else { + add_cmd("movsw", data_size); + add_modrm(data_size, 2, 1); + } return; case 0x68: - add_str("push "); + if (x86_mode == MODE_64) add_str("pushq "); + else add_str("push "); if (data_size == 2) add_imm16(); else add_imm32(); return; + case 0x69: + add_str("imul "); + get_modrm(); + if (data_size <= 2) add_imm16(); + else add_imm32s(data_size); + add_char(','); + add_modrm_mem(data_size); + add_char(','); + add_modrm_reg(data_size); + return; case 0x6a: - add_str("push "); - add_imm8(); + if (x86_mode == MODE_64) add_str("pushq "); + else add_str("push "); + add_imm8(push_size); + return; + case 0x6b: + add_str("imul "); + get_modrm(); + add_imm8(data_size); + add_char(','); + add_modrm_mem(data_size); + add_char(','); + add_modrm_reg(data_size); return; case 0x70: case 0x71: @@ -780,114 +1674,97 @@ static void disassemble_instr(void) { add_rel(1); return; case 0x80: - modrm = get_code(); - add_a_op((modrm >> 3) & 7); - add_modrm(modrm, data_size); + get_modrm(); + data_size = 1; + add_a_op((modrm >> 3) & 7, op_size(modrm)); + add_imm8(0); add_char(','); - add_imm8(); + add_modrm_mem(1); return; case 0x81: - modrm = get_code(); - add_a_op((modrm >> 3) & 7); - add_modrm(modrm, data_size); - add_char(','); + get_modrm(); + add_a_op((modrm >> 3) & 7, op_size(modrm)); if (data_size == 2) add_imm16(); - else add_imm32(); + else add_imm32s(data_size); + add_char(','); + add_modrm_mem(data_size); return; case 0x83: - modrm = get_code(); - add_a_op((modrm >> 3) & 7); - add_modrm(modrm, data_size); + get_modrm(); + add_a_op((modrm >> 3) & 7, op_size(modrm)); + add_imm8(data_size); add_char(','); - add_imm8(); + add_modrm_mem(data_size); return; case 0x84: - modrm = get_code(); add_str("test "); - add_modrm(modrm, 1); - add_char(','); - add_reg((modrm >> 3) & 7, 1); + add_modrm(1, 1, 0); return; case 0x85: - modrm = get_code(); add_str("test "); - add_modrm(modrm, data_size); - add_char(','); - add_reg((modrm >> 3) & 7, data_size); + add_modrm(data_size, data_size, 0); + return; + case 0x86: + add_str("xchg "); + add_modrm(1, 1, 0); + return; + case 0x87: + add_str("xchg "); + add_modrm(data_size, data_size, 0); return; case 0x88: - modrm = get_code(); add_str("mov "); - add_modrm(modrm, 1); - add_char(','); - add_reg((modrm >> 3) & 7, 1); + add_modrm(1, 1, 0); return; case 0x89: - modrm = get_code(); add_str("mov "); - add_modrm(modrm, data_size); - add_char(','); - add_reg((modrm >> 3) & 7, data_size); + add_modrm(data_size, data_size, 0); return; case 0x8a: - modrm = get_code(); add_str("mov "); - add_reg((modrm >> 3) & 7, 1); - add_char(','); - add_modrm(modrm, 1); + add_modrm(1, 1, 1); return; case 0x8b: - modrm = get_code(); add_str("mov "); - add_reg((modrm >> 3) & 7, data_size); - add_char(','); - add_modrm(modrm, data_size); + add_modrm(data_size, data_size, 1); return; case 0x8c: - modrm = get_code(); add_str("mov "); - add_modrm(modrm, data_size); - add_char(','); - add_seg_reg((modrm >> 3) & 7); + add_modrm(REG_SIZE_SEG, data_size, 1); return; case 0x8d: - modrm = get_code(); add_str("lea "); - add_reg((modrm >> 3) & 7, data_size); - add_char(','); - add_modrm(modrm, 0); + add_modrm(data_size, 0, 1); return; case 0x8e: - modrm = get_code(); add_str("mov "); - add_seg_reg((modrm >> 3) & 7); - add_char(','); - add_modrm(modrm, data_size); + add_modrm(REG_SIZE_SEG, data_size, 0); return; case 0x8f: - modrm = get_code(); + get_modrm(); switch ((modrm >> 3) & 7) { case 0: add_str("pop "); - add_modrm(modrm, data_size); + add_modrm_mem(data_size); return; } break; case 0x90: - add_str("nop"); + if (prefix & PREFIX_DATA_SIZE) add_str("xchg %ax,%ax"); + else add_str("nop"); return; case 0x98: switch (data_size) { - case 2: add_str("cbw"); return; - case 4: add_str("cwde"); return; - case 8: add_str("cdqe"); return; + case 2: add_str("cbtw"); return; + case 4: add_str("cwtl"); return; + case 8: add_str("cltq"); return; } break; case 0x99: switch (data_size) { - case 2: add_str("cwd"); return; - case 4: add_str("cdq"); return; - case 8: add_str("cqo"); return; + case 2: add_str("cwtl"); return; + case 4: add_str("cltd"); return; + case 8: add_str("cqto"); return; } break; case 0x9a: @@ -903,9 +1780,9 @@ static void disassemble_instr(void) { return; case 0xa1: add_str("mov "); - add_reg(0, data_size); - add_char(','); add_moffs(1); + add_char(','); + add_reg(0, data_size); return; case 0xa2: add_str("mov "); @@ -919,16 +1796,87 @@ static void disassemble_instr(void) { add_char(','); add_reg(0, data_size); return; + case 0xa4: + case 0xa5: + if ((opcode & 1) == 0) data_size = 1; + if (prefix & PREFIX_REPNZ) add_str("repnz "); + if (prefix & PREFIX_REPZ) add_str("rep "); + add_cmd("movs", data_size); + add_char('%'); + if (prefix & PREFIX_CS) add_char('c'); + else if (prefix & PREFIX_SS) add_char('s'); + else if (prefix & PREFIX_DS) add_char('d'); + else if (prefix & PREFIX_ES) add_char('e'); + else if (prefix & PREFIX_FS) add_char('f'); + else if (prefix & PREFIX_GS) add_char('g'); + else add_char('d'); + add_str("s:("); + add_reg(6, addr_size); + add_str("),%es:("); + add_reg(7, addr_size); + add_char(')'); + return; + case 0xa6: + case 0xa7: + if ((opcode & 1) == 0) data_size = 1; + if (prefix & PREFIX_REPNZ) add_str("repnz "); + if (prefix & PREFIX_REPZ) add_str("repz "); + add_cmd("cmps", data_size); + add_str("%es:("); + add_reg(7, addr_size); + add_str("),%"); + if (prefix & PREFIX_CS) add_char('c'); + else if (prefix & PREFIX_SS) add_char('s'); + else if (prefix & PREFIX_DS) add_char('d'); + else if (prefix & PREFIX_ES) add_char('e'); + else if (prefix & PREFIX_FS) add_char('f'); + else if (prefix & PREFIX_GS) add_char('g'); + else add_char('d'); + add_str("s:("); + add_reg(6, addr_size); + add_char(')'); + return; case 0xa8: - add_str("test al,"); - add_imm8(); + add_str("test "); + add_imm8(0); + add_str(",%al"); return; case 0xa9: add_str("test "); - add_reg(0, data_size); - add_char(','); if (data_size <= 2) add_imm16(); else add_imm32(); + add_char(','); + add_reg(0, data_size); + return; + case 0xaa: + case 0xab: + if (prefix & PREFIX_REPNZ) add_str("repnz "); + if (prefix & PREFIX_REPZ) add_str("rep "); + add_str("stos "); + add_reg(0, (opcode & 1) ? data_size : 1); + add_str(",%es:("); + add_reg(7, addr_size); + add_char(')'); + return; + case 0xac: + case 0xad: + if (prefix & PREFIX_REPNZ) add_str("repnz "); + if (prefix & PREFIX_REPZ) add_str("rep "); + add_str("lods "); + add_reg(0, (opcode & 1) ? data_size : 1); + add_str(",%es:("); + add_reg(7, addr_size); + add_char(')'); + return; + case 0xae: + case 0xaf: + if (prefix & PREFIX_REPNZ) add_str("repnz "); + if (prefix & PREFIX_REPZ) add_str("rep "); + add_str("scas "); + add_str("%es:("); + add_reg(7, addr_size); + add_str("),"); + add_reg(0, (opcode & 1) ? data_size : 1); return; case 0xb0: case 0xb1: @@ -939,9 +1887,10 @@ static void disassemble_instr(void) { case 0xb6: case 0xb7: add_str("mov "); - add_reg(opcode & 7, 1); + add_imm8(0); add_char(','); - add_imm8(); + if (rex & REX_B) add_reg((opcode & 7) + 8, 1); + else add_reg(opcode & 7, 1); return; case 0xb8: case 0xb9: @@ -952,46 +1901,53 @@ static void disassemble_instr(void) { case 0xbe: case 0xbf: add_str("mov "); - add_reg(opcode & 7, data_size); + if (data_size <= 2) add_imm16(); + else if (data_size <= 4) add_imm32(); + else add_imm64(); add_char(','); - if (addr_size <= 2) add_imm16(); - else add_imm32(); + if (rex & REX_B) add_reg((opcode & 7) + 8, data_size); + else add_reg(opcode & 7, data_size); return; case 0xc0: case 0xc1: - modrm = get_code(); - if (!shift_op((modrm >> 3) & 7)) break; - add_modrm(modrm, data_size); + get_modrm(); + if ((opcode & 1) == 0) data_size = 1; + if (!shift_op((modrm >> 3) & 7, op_size(modrm))) break; + add_imm8(0); add_char(','); - add_imm8(); + add_modrm_mem(data_size); return; case 0xc2: add_str("ret "); add_imm16(); return; case 0xc3: + if (prefix & PREFIX_REPNZ) add_str("repnz "); + if (prefix & PREFIX_REPZ) add_str("repz "); add_str("ret"); + if (addr_size == 8) add_char('q'); return; case 0xc6: - modrm = get_code(); + get_modrm(); switch ((modrm >> 3) & 7) { case 0: - add_str("mov "); - add_modrm(modrm, 1); + data_size = 1; + add_cmd("mov", op_size(modrm)); + add_imm8(0); add_char(','); - add_imm8(); + add_modrm_mem(1); return; } break; case 0xc7: - modrm = get_code(); + get_modrm(); switch ((modrm >> 3) & 7) { case 0: - add_str("mov "); - add_modrm(modrm, data_size); + add_cmd("mov", op_size(modrm)); + if (data_size <= 2) add_imm16(); + else add_imm32s(data_size); add_char(','); - if (addr_size <= 2) add_imm16(); - else add_imm32(); + add_modrm_mem(data_size); return; } break; @@ -999,10 +1955,10 @@ static void disassemble_instr(void) { add_str("enter "); add_imm16(); add_char(','); - add_imm8(); + add_imm8(0); return; case 0xc9: - add_str("leave"); + add_cmd("leave", addr_size == 8 ? 8 : 0); return; case 0xca: add_str("ret "); @@ -1011,20 +1967,204 @@ static void disassemble_instr(void) { case 0xcb: add_str("ret"); return; + case 0xcc: + add_str("int3"); + return; + case 0xcd: + add_str("int "); + add_imm8(0); + return; + case 0xce: + add_str("into"); + return; + case 0xcf: + if (addr_size == 8) add_str("iretq"); + else if (addr_size == 4) add_str("iretd"); + else add_str("iret"); + return; case 0xd0: case 0xd1: - modrm = get_code(); - if (!shift_op((modrm >> 3) & 7)) break; - add_modrm(modrm, data_size); - add_str(",1"); + get_modrm(); + if ((opcode & 1) == 0) data_size = 1; + if (!shift_op((modrm >> 3) & 7, op_size(modrm))) break; + add_modrm_mem(data_size); return; case 0xd2: case 0xd3: - modrm = get_code(); - if (!shift_op((modrm >> 3) & 7)) break; - add_modrm(modrm, data_size); - add_str(",cl"); + get_modrm(); + if ((opcode & 1) == 0) data_size = 1; + if (!shift_op((modrm >> 3) & 7, op_size(modrm))) break; + add_str("%cl,"); + add_modrm_mem(data_size); + return; + case 0xd9: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 0: + if ((modrm & 0xc0) == 0xc0) { + add_str("fld st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fldw "); + add_modrm_mem(4); + return; + case 2: + if (modrm == 0xd0) { + add_str("fnop"); + return; + } + add_str("fstw "); + add_modrm_mem(4); + return; + } + break; + case 0xdb: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 0: + if ((modrm & 0xc0) == 0xc0) { + add_str("fcmovnb st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fild "); + add_modrm_mem(4); + return; + case 1: + if ((modrm & 0xc0) == 0xc0) { + add_str("fcmovne st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fisttp "); + add_modrm_mem(4); + return; + case 2: + if ((modrm & 0xc0) == 0xc0) { + add_str("fcmovnbe st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fist "); + add_modrm_mem(4); + return; + case 3: + if ((modrm & 0xc0) == 0xc0) { + add_str("fcmovnu st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fistp "); + add_modrm_mem(4); + return; + case 4: + if (modrm == 0xe2) { + if (prefix & PREFIX_FWAIT) add_str("fclex"); + else add_str("fnclex"); + return; + } + if (modrm == 0xe3) { + if (prefix & PREFIX_FWAIT) add_str("finit"); + else add_str("fninit"); + return; + } + if (modrm == 0xe4) { + add_str("fnsetpm"); + return; + } + return; + case 5: + if ((modrm & 0xc0) == 0xc0) { + add_str("fucomi st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fldt "); + add_modrm_mem(10); + return; + case 6: + add_str("fcomi st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + case 7: + add_str("fstpt "); + add_modrm_mem(10); + return; + } + break; + case 0xdc: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 0: add_str("fadd "); break; + case 1: add_str("fmul "); break; + case 2: add_str("fcom "); break; + case 3: add_str("fcomp "); break; + case 4: add_str("fsub "); break; + case 5: add_str("fsubr "); break; + case 6: add_str("fdiv "); break; + case 7: add_str("fdivr "); break; + } + if ((modrm & 0xc0) == 0xc0) { + add_str("st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_modrm_mem(8); return; + case 0xdd: + get_modrm(); + switch ((modrm >> 3) & 7) { + case 0: + if ((modrm & 0xc0) == 0xc0) { + add_str("ffree st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fldl "); + add_modrm_mem(8); + return; + case 1: + if ((modrm & 0xc0) == 0xc0) { + add_str("fxch4 st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fisttp "); + add_modrm_mem(8); + return; + case 2: + if ((modrm & 0xc0) == 0xc0) { + add_str("fst st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fst "); + add_modrm_mem(8); + return; + case 3: + if ((modrm & 0xc0) == 0xc0) { + add_str("fstp st("); + add_dec_uint32(modrm & 0x3f); + add_char(')'); + return; + } + add_str("fstp "); + add_modrm_mem(8); + return; + } + break; case 0xe3: switch (data_size) { case 2: @@ -1042,91 +2182,129 @@ static void disassemble_instr(void) { } break; case 0xe8: - add_str("call "); - add_rel(addr_size <= 2 ? 2: 4); + add_cmd("call", addr_size == 8 ? 8 : 0); + add_rel(addr_size <= 2 ? 2 : 4); return; case 0xd4: add_str("aam"); imm = get_code(); if (imm != 0x0a) { - add_str(" 0x"); - add_hex_uint32(imm); + add_char(' '); + add_0x_hex_uint32(imm); } return; case 0xd5: add_str("aad"); imm = get_code(); if (imm != 0x0a) { - add_str(" 0x"); - add_hex_uint32(imm); + add_char(' '); + add_0x_hex_uint32(imm); } return; case 0xe9: - add_str("jmp "); - add_rel(4); + if (prefix & PREFIX_REPNZ) add_str("bnd "); + add_cmd("jmp", addr_size == 8 ? 8 : 0); + add_rel(addr_size <= 2 ? 2 : 4); return; case 0xeb: add_str("jmp "); add_rel(1); return; + case 0xf1: + add_str("int1"); + return; + case 0xf4: + add_str("hlt"); + return; case 0xf6: - modrm = get_code(); - switch ((modrm >> 3) & 7) { - case 0: - add_str("test "); - add_modrm(modrm, 1); - add_char(','); - add_imm8(); - return; - } - break; case 0xf7: - modrm = get_code(); + get_modrm(); + if (opcode == 0xf6) data_size = 1; switch ((modrm >> 3) & 7) { case 0: - add_str("test "); - add_modrm(modrm, data_size); + case 1: + add_cmd("test", op_size(modrm)); + if (data_size <= 1) add_imm8(0); + else if (data_size <= 2) add_imm16(); + else add_imm32s(data_size); add_char(','); - if (data_size <= 2) add_imm16(); - else add_imm32(); + add_modrm_mem(data_size); + return; + case 2: + add_cmd("not", op_size(modrm)); + add_modrm_mem(data_size); + return; + case 3: + add_cmd("neg", op_size(modrm)); + add_modrm_mem(data_size); + return; + case 4: + add_cmd("mul", op_size(modrm)); + add_modrm_mem(data_size); + return; + case 5: + add_cmd("imul", op_size(modrm)); + add_modrm_mem(data_size); + return; + case 6: + add_cmd("div", op_size(modrm)); + add_modrm_mem(data_size); + return; + case 7: + add_cmd("idiv", op_size(modrm)); + add_modrm_mem(data_size); return; } break; + case 0xfc: + add_str("cld"); + return; + case 0xfd: + add_str("std"); + return; case 0xfe: - modrm = get_code(); + get_modrm(); + data_size = 1; switch ((modrm >> 3) & 7) { case 0: - add_str("inc "); - add_modrm(modrm, 1); + add_cmd("inc", op_size(modrm)); + add_modrm_mem(1); return; case 1: - add_str("dec "); - add_modrm(modrm, 1); + add_cmd("dec", op_size(modrm)); + add_modrm_mem(1); return; } break; case 0xff: - modrm = get_code(); + get_modrm(); switch ((modrm >> 3) & 7) { case 0: - add_str("inc "); - add_modrm(modrm, data_size); + add_cmd("inc", op_size(modrm)); + add_modrm_mem(data_size); return; case 1: - add_str("dec "); - add_modrm(modrm, data_size); + add_cmd("dec", op_size(modrm)); + add_modrm_mem(data_size); return; case 2: - add_str("call "); - add_modrm(modrm, data_size); + if (prefix & PREFIX_REPNZ) add_str("bnd "); + if (prefix & PREFIX_DS) add_str("notrack "); + if (x86_mode == MODE_64) add_str("callq *"); + else add_str("call *"); + add_modrm_mem(addr_size); return; case 4: - add_str("jmp "); - add_modrm(modrm, data_size); + if (prefix & PREFIX_REPNZ) add_str("bnd "); + if (prefix & PREFIX_DS) add_str("notrack "); + if (x86_mode == MODE_64) add_str("jmpq *"); + else add_str("jmp *"); + add_modrm_mem(addr_size); return; case 6: - add_str("push "); - add_modrm(modrm, data_size); + if (x86_mode == MODE_64) add_str("pushq "); + else add_str("pushl "); + add_modrm_mem(data_size); return; } break; @@ -1136,7 +2314,7 @@ static void disassemble_instr(void) { } static DisassemblyResult * disassemble_x86(uint8_t * code, - ContextAddress addr, ContextAddress size, int i64, + ContextAddress addr, ContextAddress size, int mode, DisassemblerParams * disass_params) { static DisassemblyResult dr; @@ -1149,7 +2327,7 @@ static DisassemblyResult * disassemble_x86(uint8_t * code, instr_addr = addr; params = disass_params; - x86_64 = i64; + x86_mode = mode; prefix = 0; vex = 0; rex = 0; @@ -1164,12 +2342,10 @@ static DisassemblyResult * disassemble_x86(uint8_t * code, continue; case 0xf2: prefix |= PREFIX_REPNZ; - add_str("repnz "); code_pos++; continue; case 0xf3: prefix |= PREFIX_REPZ; - add_str("repz "); code_pos++; continue; case 0x2e: @@ -1204,11 +2380,15 @@ static DisassemblyResult * disassemble_x86(uint8_t * code, prefix |= PREFIX_ADDR_SIZE; code_pos++; continue; + case 0x9b: + prefix |= PREFIX_FWAIT; + code_pos++; + continue; } break; } - if (i64) { + if (x86_mode == MODE_64) { if (code_pos + 1 < code_len && code_buf[code_pos] == 0xc5) { /* Two byte VEX */ vex = code_buf[code_pos++]; vex |= (uint32_t)code_buf[code_pos++] << 8; @@ -1223,8 +2403,29 @@ static DisassemblyResult * disassemble_x86(uint8_t * code, } } - data_size = rex & REX_W ? 8 : 4; - addr_size = x86_64 ? 8 : 4; + switch (x86_mode) { + case MODE_16: + data_size = prefix & PREFIX_DATA_SIZE ? 4 : 2; + push_size = prefix & PREFIX_DATA_SIZE ? 4 : 2; + addr_size = prefix & PREFIX_ADDR_SIZE ? 4 : 2; + break; + case MODE_32: + data_size = prefix & PREFIX_DATA_SIZE ? 2 : 4; + push_size = prefix & PREFIX_DATA_SIZE ? 2 : 4; + addr_size = prefix & PREFIX_ADDR_SIZE ? 2 : 4; + break; + case MODE_64: + if (rex & REX_W) { + data_size = 8; + push_size = 8; + } + else { + data_size = prefix & PREFIX_DATA_SIZE ? 2 : 4; + push_size = prefix & PREFIX_DATA_SIZE ? 4 : 8; + } + addr_size = prefix & PREFIX_ADDR_SIZE ? 4 : 8; + break; + } disassemble_instr(); @@ -1240,16 +2441,22 @@ static DisassemblyResult * disassemble_x86(uint8_t * code, return &dr; } +DisassemblyResult * disassemble_x86_16(uint8_t * code, + ContextAddress addr, ContextAddress size, + DisassemblerParams * disass_params) { + return disassemble_x86(code, addr, size, MODE_16, disass_params); +} + DisassemblyResult * disassemble_x86_32(uint8_t * code, ContextAddress addr, ContextAddress size, DisassemblerParams * disass_params) { - return disassemble_x86(code, addr, size, 0, disass_params); + return disassemble_x86(code, addr, size, MODE_32, disass_params); } DisassemblyResult * disassemble_x86_64(uint8_t * code, ContextAddress addr, ContextAddress size, DisassemblerParams * disass_params) { - return disassemble_x86(code, addr, size, 1, disass_params); + return disassemble_x86(code, addr, size, MODE_64, disass_params); } #endif /* SERVICE_Disassembly */ diff --git a/agent/machine/x86_64/tcf/disassembler-x86_64.h b/agent/machine/x86_64/tcf/disassembler-x86_64.h index 8b025e29..984f6d8b 100644 --- a/agent/machine/x86_64/tcf/disassembler-x86_64.h +++ b/agent/machine/x86_64/tcf/disassembler-x86_64.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Xilinx, Inc. and others. + * Copyright (c) 2015-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. @@ -20,6 +20,9 @@ #include <tcf/services/disassembly.h> +extern DisassemblyResult * disassemble_x86_16(uint8_t * buf, + ContextAddress addr, ContextAddress size, DisassemblerParams * params); + extern DisassemblyResult * disassemble_x86_32(uint8_t * buf, ContextAddress addr, ContextAddress size, DisassemblerParams * params); diff --git a/agent/machine/x86_64/tcf/dwarfreloc-mdep.h b/agent/machine/x86_64/tcf/dwarfreloc-mdep.h index 1dd7036d..3cacbf5f 100644 --- a/agent/machine/x86_64/tcf/dwarfreloc-mdep.h +++ b/agent/machine/x86_64/tcf/dwarfreloc-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010-2018 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. @@ -22,6 +22,7 @@ #define R_X86_64_PC32 2 #define R_X86_64_32 10 #define R_X86_64_32S 11 +#define R_X86_64_PC64 24 static void elf_relocate(void) { if (relocs->type == SHT_REL && reloc_type != R_X86_64_NONE) { @@ -29,6 +30,7 @@ static void elf_relocate(void) { assert(reloc_addend == 0); switch (reloc_type) { case R_X86_64_64: + case R_X86_64_PC64: { U8_T x = *(U8_T *)((char *)section->data + reloc_offset); if (section->file->byte_swap) SWAP(x); @@ -61,7 +63,11 @@ static void elf_relocate(void) { if (data_size < 4) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); break; + case R_X86_64_PC64: + if (data_size < 8) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); + *(U8_T *)data_buf = (U8_T)(sym_value + reloc_addend - (section->addr + reloc_offset)); + break; default: - str_exception(ERR_INV_FORMAT, "Unsupported relocation type"); + str_fmt_exception(ERR_INV_FORMAT, "Unsupported relocation type %u", (unsigned)reloc_type); } } diff --git a/agent/machine/x86_64/tcf/regset-mdep.h b/agent/machine/x86_64/tcf/regset-mdep.h index 2cf760d4..077d852f 100644 --- a/agent/machine/x86_64/tcf/regset-mdep.h +++ b/agent/machine/x86_64/tcf/regset-mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2017 Wind River Systems, Inc. and others. + * Copyright (c) 2012-2019 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. @@ -13,8 +13,50 @@ * Wind River Systems - initial API and implementation *******************************************************************************/ +#if defined(__linux__) + +#include <elf.h> +#include <tcf/framework/mdep-ptrace.h> + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +struct i386_user_desc { + uint32_t entry; + uint32_t base; + uint32_t limit; + uint32_t status; +}; + #if defined(__i386__) /* Building 32-bit agent on a 64-bit machine */ -/* additional CPU registers */ -# define MDEP_OtherRegisters struct user_fpxregs_struct + +#if !defined(PTRACE_GETFPXREGS) && !defined(PT_GETFPXREGS) +#define PTRACE_GETFPXREGS 18 +#endif + +#if !defined(PTRACE_SETFPXREGS) && !defined(PT_SETFPXREGS) +#define PTRACE_SETFPXREGS 19 +#endif + +struct i386_regset_extra { + struct user_fpxregs_struct fpx; + struct i386_user_desc fs; + struct i386_user_desc gs; +}; + +#define MDEP_OtherRegisters struct i386_regset_extra + +#else + +struct x86_64_regset_extra { + struct i386_user_desc fs; + struct i386_user_desc gs; +}; + +#define MDEP_OtherRegisters struct x86_64_regset_extra + +#endif + #endif diff --git a/agent/msvc/agent-vc2015.vcxproj b/agent/msvc/agent-vc2015.vcxproj index c8e7f319..a50814e2 100644 --- a/agent/msvc/agent-vc2015.vcxproj +++ b/agent/msvc/agent-vc2015.vcxproj @@ -305,6 +305,20 @@ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
+ <ClCompile Include="..\machine\riscv64\tcf\disassembler-riscv64.c">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="..\machine\riscv64\tcf\stack-crawl-riscv64.c">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="..\machine\riscv\tcf\disassembler-riscv.c" />
+ <ClCompile Include="..\machine\riscv\tcf\stack-crawl-riscv.c" />
<ClCompile Include="..\machine\x86_64\tcf\disassembler-x86_64.c" />
<ClCompile Include="..\tcf\framework\asyncreq.c" />
<ClCompile Include="..\tcf\framework\base64.c" />
@@ -381,8 +395,14 @@ <ClInclude Include="..\machine\ppc64\tcf\cpu-regs-gdb.h" />
<ClInclude Include="..\machine\ppc64\tcf\dwarfreloc-mdep.h" />
<ClInclude Include="..\machine\riscv64\tcf\cpudefs-mdep.h" />
+ <ClInclude Include="..\machine\riscv64\tcf\disassembler-riscv64.h" />
<ClInclude Include="..\machine\riscv64\tcf\dwarfreloc-mdep.h" />
<ClInclude Include="..\machine\riscv64\tcf\regset-mdep.h" />
+ <ClInclude Include="..\machine\riscv64\tcf\stack-crawl-riscv64.h" />
+ <ClInclude Include="..\machine\riscv\tcf\disassembler-riscv.h" />
+ <ClInclude Include="..\machine\riscv\tcf\stack-crawl-riscv.h" />
+ <ClInclude Include="..\machine\riscv\tcf\uxlen.h" />
+ <ClInclude Include="..\machine\sparc\tcf\dwarfreloc-mdep.h" />
<ClInclude Include="..\machine\x86_64\tcf\cpu-regs-gdb.h" />
<ClInclude Include="..\tcf\framework\channel_lws.h" />
<ClInclude Include="..\tcf\framework\channel_lws_ext.h" />
diff --git a/agent/msvc/agent-vc2015.vcxproj.filters b/agent/msvc/agent-vc2015.vcxproj.filters index eb7c7bb1..b6f7b1ee 100644 --- a/agent/msvc/agent-vc2015.vcxproj.filters +++ b/agent/msvc/agent-vc2015.vcxproj.filters @@ -73,6 +73,12 @@ <Filter Include="machine\riscv64">
<UniqueIdentifier>{33878318-fdc6-4e2e-9642-182293971a42}</UniqueIdentifier>
</Filter>
+ <Filter Include="machine\riscv">
+ <UniqueIdentifier>{6c2e59c7-2deb-4834-b754-0f5e47f6b7e2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="machine\sparc">
+ <UniqueIdentifier>{3813d491-7900-4d3f-97af-ff981226b75c}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\tcf\framework\asyncreq.c">
@@ -414,6 +420,18 @@ <ClCompile Include="..\machine\riscv64\tcf\cpudefs-mdep.c">
<Filter>machine\riscv64</Filter>
</ClCompile>
+ <ClCompile Include="..\machine\riscv\tcf\disassembler-riscv.c">
+ <Filter>machine\riscv</Filter>
+ </ClCompile>
+ <ClCompile Include="..\machine\riscv\tcf\stack-crawl-riscv.c">
+ <Filter>machine\riscv</Filter>
+ </ClCompile>
+ <ClCompile Include="..\machine\riscv64\tcf\disassembler-riscv64.c">
+ <Filter>machine\riscv64</Filter>
+ </ClCompile>
+ <ClCompile Include="..\machine\riscv64\tcf\stack-crawl-riscv64.c">
+ <Filter>machine\riscv64</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tcf\framework\asyncreq.h">
@@ -888,5 +906,23 @@ <ClInclude Include="..\machine\riscv64\tcf\regset-mdep.h">
<Filter>machine\riscv64</Filter>
</ClInclude>
+ <ClInclude Include="..\machine\riscv\tcf\disassembler-riscv.h">
+ <Filter>machine\riscv</Filter>
+ </ClInclude>
+ <ClInclude Include="..\machine\riscv\tcf\stack-crawl-riscv.h">
+ <Filter>machine\riscv</Filter>
+ </ClInclude>
+ <ClInclude Include="..\machine\riscv64\tcf\disassembler-riscv64.h">
+ <Filter>machine\riscv64</Filter>
+ </ClInclude>
+ <ClInclude Include="..\machine\riscv64\tcf\stack-crawl-riscv64.h">
+ <Filter>machine\riscv64</Filter>
+ </ClInclude>
+ <ClInclude Include="..\machine\riscv\tcf\uxlen.h">
+ <Filter>machine\riscv</Filter>
+ </ClInclude>
+ <ClInclude Include="..\machine\sparc\tcf\dwarfreloc-mdep.h">
+ <Filter>machine\sparc</Filter>
+ </ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/agent/system/GNU/Linux/tcf/context-linux.c b/agent/system/GNU/Linux/tcf/context-linux.c index c3d8d6c3..197c80de 100644 --- a/agent/system/GNU/Linux/tcf/context-linux.c +++ b/agent/system/GNU/Linux/tcf/context-linux.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 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. @@ -73,6 +73,9 @@ static const int PTRACE_FLAGS = PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACEEXIT; +/* Note: the agent must be compiled with same word size os the kernel */ +#define PTRACE_WORD_SIZE sizeof(long) + #define PROFILER_SAMPLE_PERIOD 40000 typedef struct ContextExtensionLinux { @@ -97,10 +100,16 @@ typedef struct ContextExtensionLinux { int sigkill_posted; int detach_req; int crt0_done; + BreakpointInfo * bp_loader; + BreakpointInfo * bp_main; #if ENABLE_ProfilerSST int prof_armed; int prof_fired; #endif +#if ENABLE_ContextExtraProperties + char * thread_name; + char * additional_info; +#endif } ContextExtensionLinux; static size_t context_extension_offset = 0; @@ -203,6 +212,8 @@ int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int mod ctx->mem_access |= MEM_ACCESS_INSTRUCTION; ctx->mem_access |= MEM_ACCESS_DATA; ctx->mem_access |= MEM_ACCESS_USER; + ctx->mem_access |= MEM_ACCESS_RD_STOP; + ctx->mem_access |= MEM_ACCESS_WR_STOP; ctx->big_endian = big_endian_host(); ext = EXT(ctx); ext->pid = pid; @@ -374,11 +385,7 @@ static int flush_regs(Context * ctx) { } #else if (i >= offsetof(REG_SET, fp) && i < offsetof(REG_SET, fp) + sizeof(ext->regs->fp)) { -#if defined(__arm__) || defined(__aarch64__) - if (ptrace(PTRACE_SETVFPREGS, ext->pid, 0, &ext->regs->fp) < 0) { -#else if (ptrace(PTRACE_SETFPREGS, ext->pid, 0, &ext->regs->fp) < 0) { -#endif error = errno; break; } @@ -399,12 +406,14 @@ static int flush_regs(Context * ctx) { if (error) { RegisterDefinition * def = get_reg_definitions(ctx); - while (def->name != NULL && (def->offset > i || def->offset + def->size <= i)) def++; - if (error != ESRCH || !ext->sigkill_posted) { - trace(LOG_ALWAYS, "error: writing register %s failed: ctx %#" PRIxPTR ", id %s, error %d %s", - def->name ? def->name : "?", (uintptr_t)ctx, ctx->id, error, errno_to_str(error)); + if (def != NULL) { + while (def->name != NULL && (def->offset > i || def->offset + def->size <= i)) def++; + if (error != ESRCH || !EXT(ctx->parent)->sigkill_posted) { + trace(LOG_ALWAYS, "error: writing register %s failed: ctx %#" PRIxPTR ", id %s, error %d %s", + def->name ? def->name : "?", (uintptr_t)ctx, ctx->id, error, errno_to_str(error)); + } + if (def->name) error = set_fmt_errno(error, "Cannot write register %s", def->name); } - if (def->name) error = set_fmt_errno(error, "Cannot write register %s", def->name); errno = error; return -1; } @@ -423,6 +432,7 @@ static void free_regs(Context * ctx) { } static void send_process_exited_event(Context * prs) { + ContextExtensionLinux * ext = EXT(prs); LINK * l = prs->children.next; assert(prs->parent == NULL); assert(prs->exited == 0); @@ -435,6 +445,14 @@ static void send_process_exited_event(Context * prs) { } prs->exiting = 1; send_context_exited_event(prs); + if (ext->bp_loader != NULL) { + destroy_eventpoint(ext->bp_loader); + ext->bp_loader = NULL; + } + if (ext->bp_main != NULL) { + destroy_eventpoint(ext->bp_main); + ext->bp_main = NULL; + } } #if ENABLE_Trace @@ -466,7 +484,7 @@ static int try_single_step(Context * ctx) { if (is_cont) cmd = PTRACE_CONT; if (!error && ptrace(cmd, ext->pid, 0, 0) < 0) { error = errno; - if (error != ESRCH || !ext->sigkill_posted) { + if (error != ESRCH || !EXT(ctx->parent)->sigkill_posted) { trace(LOG_ALWAYS, "error: ptrace(%s, ...) failed: ctx %#" PRIxPTR ", id %s, error %d %s", get_ptrace_cmd_name(cmd), (uintptr_t)ctx, ctx->id, error, errno_to_str(error)); } @@ -576,7 +594,7 @@ int context_continue(Context * ctx) { sigset_is_empty(&ctx->pending_signals)) cmd = PTRACE_DETACH; if (!error && ptrace(cmd, ext->pid, 0, signal) < 0) { error = errno; - if (error != ESRCH || !ext->sigkill_posted) { + if (error != ESRCH || !EXT(ctx->parent)->sigkill_posted) { trace(LOG_ALWAYS, "error: ptrace(%s, ...) failed: ctx %#" PRIxPTR ", id %s, error %d %s", get_ptrace_cmd_name(cmd), (uintptr_t)ctx, ctx->id, error, errno_to_str(error)); } @@ -594,7 +612,7 @@ int context_continue(Context * ctx) { } sigset_set(&ctx->pending_signals, signal, 0); if (signal == SIGKILL) { - ext->sigkill_posted = 1; + EXT(ctx->parent)->sigkill_posted = 1; ctx->exiting = 1; } if (syscall_never_returns(ctx)) { @@ -685,11 +703,10 @@ int context_write_mem_ext(Context * ctx, MemoryAccessMode * mode, ContextAddress int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { ContextAddress word_addr; - unsigned word_size = context_word_size(ctx); ContextExtensionLinux * ext = EXT(ctx); int error = 0; - assert(word_size <= sizeof(unsigned long)); + assert(PTRACE_WORD_SIZE <= sizeof(unsigned long)); assert(is_dispatch_thread()); assert(!ctx->exited); trace(LOG_CONTEXT, @@ -705,9 +722,9 @@ int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t return -1; } if (check_breakpoints_on_memory_write(ctx, address, buf, size) < 0) return -1; - for (word_addr = address & ~((ContextAddress)word_size - 1); word_addr < address + size; word_addr += word_size) { + for (word_addr = address & ~((ContextAddress)PTRACE_WORD_SIZE - 1); word_addr < address + size; word_addr += PTRACE_WORD_SIZE) { unsigned long word = 0; - if (word_addr < address || word_addr + word_size > address + size) { + if (word_addr < address || word_addr + PTRACE_WORD_SIZE > address + size) { unsigned i = 0; errno = 0; word = ptrace(PTRACE_PEEKDATA, ext->pid, (void *)word_addr, 0); @@ -720,14 +737,14 @@ int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t } break; } - for (i = 0; i < word_size; i++) { + for (i = 0; i < PTRACE_WORD_SIZE; i++) { if (word_addr + i >= address && word_addr + i < address + size) { ((char *)&word)[i] = ((char *)buf)[word_addr + i - address]; } } } else { - memcpy(&word, (char *)buf + (word_addr - address), word_size); + memcpy(&word, (char *)buf + (word_addr - address), PTRACE_WORD_SIZE); } if (ptrace(PTRACE_POKEDATA, ext->pid, (void *)word_addr, word) < 0) { error = errno; @@ -756,7 +773,7 @@ int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t if (error) { #if ENABLE_ExtendedMemoryErrorReports size_t size_valid = 0; - size_t size_error = word_size; + size_t size_error = PTRACE_WORD_SIZE; if (word_addr > address) size_valid = (size_t)(word_addr - address); /* Find number of invalid bytes */ /* Note: cannot write memory here, read instead */ @@ -764,7 +781,7 @@ int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t errno = 0; ptrace(PTRACE_PEEKDATA, ext->pid, (void *)(word_addr + size_error), 0); if (errno != error) break; - size_error += word_size; + size_error += PTRACE_WORD_SIZE; } mem_err_info.error = error; mem_err_info.size_valid = size_valid; @@ -784,12 +801,11 @@ int context_read_mem_ext(Context * ctx, MemoryAccessMode * mode, ContextAddress int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { ContextAddress word_addr; - unsigned word_size = context_word_size(ctx); ContextExtensionLinux * ext = EXT(ctx); size_t size_valid = 0; int error = 0; - assert(word_size <= sizeof(unsigned long)); + assert(PTRACE_WORD_SIZE <= sizeof(unsigned long)); assert(is_dispatch_thread()); assert(!ctx->exited); trace(LOG_CONTEXT, @@ -804,7 +820,7 @@ int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t s errno = EFAULT; return -1; } - for (word_addr = address & ~((ContextAddress)word_size - 1); word_addr < address + size; word_addr += word_size) { + for (word_addr = address & ~((ContextAddress)PTRACE_WORD_SIZE - 1); word_addr < address + size; word_addr += PTRACE_WORD_SIZE) { unsigned long word = 0; errno = 0; word = ptrace(PTRACE_PEEKDATA, ext->pid, (void *)word_addr, 0); @@ -817,16 +833,16 @@ int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t s } break; } - if (word_addr < address || word_addr + word_size > address + size) { + if (word_addr < address || word_addr + PTRACE_WORD_SIZE > address + size) { unsigned i = 0; - for (i = 0; i < word_size; i++) { + for (i = 0; i < PTRACE_WORD_SIZE; i++) { if (word_addr + i >= address && word_addr + i < address + size) { ((char *)buf)[word_addr + i - address] = ((char *)&word)[i]; } } } else { - memcpy((char *)buf + (word_addr - address), &word, word_size); + memcpy((char *)buf + (word_addr - address), &word, PTRACE_WORD_SIZE); } } if (error == ESRCH && ctx == ctx->mem) { @@ -847,13 +863,13 @@ int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t s if (check_breakpoints_on_memory_read(ctx, address, buf, size_valid) < 0) return -1; if (error) { #if ENABLE_ExtendedMemoryErrorReports - size_t size_error = word_size; + size_t size_error = PTRACE_WORD_SIZE; /* Find number of unreadable bytes */ while (size_error < 0x1000 && size_valid + size_error < size) { errno = 0; ptrace(PTRACE_PEEKDATA, ext->pid, (void *)(word_addr + size_error), 0); if (errno != error) break; - size_error += word_size; + size_error += PTRACE_WORD_SIZE; } mem_err_info.error = error; mem_err_info.size_valid = size_valid; @@ -959,11 +975,7 @@ int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, uns /* Did not work, use PTRACE_PEEKUSER to get one register at a time */ } if (i >= offsetof(REG_SET, fp) && i < offsetof(REG_SET, fp) + sizeof(ext->regs->fp)) { -#if defined(__arm__) || defined(__aarch64__) - if (ptrace(PTRACE_GETVFPREGS, ext->pid, 0, &ext->regs->fp) < 0 && errno != ESRCH) { -#else if (ptrace(PTRACE_GETFPREGS, ext->pid, 0, &ext->regs->fp) < 0 && errno != ESRCH) { -#endif error = errno; break; } @@ -991,7 +1003,11 @@ int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, uns } unsigned context_word_size(Context * ctx) { +#ifdef MDEP_WordSize + return MDEP_WordSize(ctx); +#else return sizeof(void *); +#endif } int context_get_canonical_addr(Context * ctx, ContextAddress addr, @@ -1059,11 +1075,13 @@ int context_get_memory_map(Context * ctx, MemoryMap * map) { unsigned long inode = 0; char permissions[16]; char file_name[FILE_PATH_SIZE]; + static char * fscanf_fmt = NULL; unsigned i = 0; int flags = 0; + int cnt; - int cnt = fscanf(file, "%lx-%lx %s %lx %lx:%lx %ld", - &addr0, &addr1, permissions, &offset, &dev_ma, &dev_mi, &inode); + if (fscanf_fmt == NULL) fscanf_fmt = loc_printf("%%lx-%%lx %%%us %%lx %%lx:%%lx %%ld", (unsigned)(sizeof(permissions) - 1)); + cnt = fscanf(file, fscanf_fmt, &addr0, &addr1, permissions, &offset, &dev_ma, &dev_mi, &inode); if (cnt == 0 || cnt == EOF) break; for (i = 0;;) { @@ -1164,12 +1182,16 @@ int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { isa->def = "MicroBlaze"; #elif defined(__MICROBLAZE64__) isa->def = "MicroBlaze64"; +#elif defined(__riscv) && __riscv_xlen == 32 + isa->def = "Riscv32"; #elif defined(__riscv) && __riscv_xlen == 64 isa->def = "Riscv64"; +#elif defined(__riscv) && __riscv_xlen == 128 + isa->def = "Riscv128"; #else isa->def = NULL; #endif -#if SERVICE_Symbols +#if ENABLE_Symbols if (cache_channel() != NULL) { if (get_context_isa(ctx, addr, &isa->isa, &isa->addr, &isa->size) < 0) return -1; } @@ -1183,6 +1205,14 @@ int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { isa->max_instruction_size = 15; } else if (strcmp(s, "ARM") == 0) { +#if defined(__aarch64__) + static uint8_t bp_arm[] = { 0x70, 0xbe, 0x20, 0xe1 }; +#else + /* Note: don't use BKPT instruction - it is not supported by 32-bit Linux kernel */ + static uint8_t bp_arm[] = { 0xf0, 0x01, 0xf0, 0xe7 }; +#endif + isa->bp_encoding = bp_arm; + isa->bp_size = sizeof(bp_arm); isa->max_instruction_size = 4; isa->alignment = 4; } @@ -1191,9 +1221,14 @@ int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { isa->alignment = 4; } else if (strcmp(s, "Thumb") == 0 || strcmp(s, "ThumbEE") == 0) { - static uint8_t bp_thumb[] = { 0x00, 0xbe }; +#if defined(__aarch64__) + static uint8_t bp_thumb[] = { 0x70, 0xbe }; +#else + /* Note: don't use BKPT instruction - it is not supported by 32-bit Linux kernel */ + static uint8_t bp_thumb[] = { 0x01, 0xde }; +#endif isa->bp_encoding = bp_thumb; - isa->bp_size = 2; + isa->bp_size = sizeof(bp_thumb); isa->max_instruction_size = 4; isa->alignment = 2; } @@ -1205,7 +1240,15 @@ int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { isa->max_instruction_size = 4; isa->alignment = 4; } - else if (strcmp(s, "Riscv64") == 0) { + else if (strcmp(s, "Riscv32") == 0) { + isa->max_instruction_size = 4; + isa->alignment = 2; + } + else if (strcmp(s, "Riscv64") == 0) { + isa->max_instruction_size = 4; + isa->alignment = 2; + } + else if (strcmp(s, "Riscv128") == 0) { isa->max_instruction_size = 4; isa->alignment = 2; } @@ -1215,10 +1258,111 @@ int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { #endif #if ENABLE_ContextExtraProperties + +static const char ** ctx_props_names = NULL; +static const char ** ctx_props_values = NULL; +static int ctx_props_cnt = 0; +static int ctx_props_max = 0; + +static void add_context_property(const char * name, const char * value) { + int i; + for (i = 0; i < ctx_props_cnt; i++) { + if (strcmp(ctx_props_names[i], name) == 0) { + ctx_props_values[i] = value; + return; + } + } + if (ctx_props_cnt >= ctx_props_max) { + ctx_props_max += 8; + ctx_props_names = (const char **)tmp_realloc((void *)ctx_props_names, sizeof(char *) * ctx_props_max); + ctx_props_values = (const char **)tmp_realloc((void *)ctx_props_values, sizeof(char *) * ctx_props_max); + } + ctx_props_names[ctx_props_cnt] = name; + ctx_props_values[ctx_props_cnt] = value; + ctx_props_cnt++; +} + +static char * get_thread_name(pid_t pid, pid_t tid) { + char * res = NULL; + FILE * file = NULL; + char file_name[FILE_PATH_SIZE]; + snprintf(file_name, sizeof(file_name), "/proc/%d/task/%d/comm", pid, tid); + if ((file = fopen(file_name, "r")) != NULL) { + char s[128]; + if (fgets(s, sizeof(s), file) != NULL) { + size_t l = strlen(s); + while (l > 0 && s[l - 1] <= ' ') s[--l] = 0; + if (l > 0) res = tmp_strdup(s); + } + fclose(file); + } + return res; +} + +static void update_thread_name(Context * ctx) { + ContextExtensionLinux * ext = EXT(ctx); + char * name = get_thread_name(EXT(ctx->mem)->pid, ext->pid); + int notify = 0; + assert(!ctx->exited); + assert(!ctx->stopped); + if (name != NULL) { + if (ext->thread_name == NULL || strcmp(ext->thread_name, name) != 0) { + loc_free(ext->thread_name); + ext->thread_name = loc_strdup(name); + notify = 1; + } + } + else { + if (ext->thread_name != NULL) { + loc_free(ext->thread_name); + ext->thread_name = NULL; + notify = 1; + } + } + if (notify && ctx->mem != ctx) { + loc_free(ext->additional_info); + if (ext->thread_name != NULL) { + ByteArrayOutputStream buf; + OutputStream * out = create_byte_array_output_stream(&buf); + json_write_string(out, tmp_printf(" %s", ext->thread_name)); + write_stream(out, 0); + get_byte_array_output_stream_data(&buf, &ext->additional_info, NULL); + } + else { + ext->additional_info = NULL; + } + if (!list_is_empty(&ctx->ctxl)) send_context_changed_event(ctx); + } +} + +static void thread_name_timer(void * args) { + LINK * l; + for (l = context_root.next; l != &context_root; l = l->next) { + Context * ctx = ctxl2ctxp(l); + if (!ctx->exited) { + ContextExtensionLinux * ext = EXT(ctx); + if (ext->pid == 0) continue; + if (!ctx->stopped && ctx->mem != ctx) update_thread_name(ctx); + } + } + post_event_with_delay(thread_name_timer, NULL, 2000000); +} + int context_get_extra_properties(Context * ctx, const char *** names, const char *** values, int * cnt) { - *cnt = 0; + ContextExtensionLinux * ext = EXT(ctx); + ctx_props_names = NULL; + ctx_props_values = NULL; + ctx_props_cnt = 0; + ctx_props_max = 0; + if (ext->additional_info != NULL) { + add_context_property("AdditionalInfo", ext->additional_info); + } + *names = ctx_props_names; + *values = ctx_props_values; + *cnt = ctx_props_cnt; return 0; } + #endif #if ENABLE_ContextMemoryProperties @@ -1368,6 +1512,124 @@ static pid_t get_thread_group_id(pid_t pid) { return res; } +#if SERVICE_Expressions && ENABLE_ELF + +static void get_debug_structure_address(Context * ctx, Value * v) { + ELF_File * file = NULL; + v->address = elf_get_debug_structure_address(ctx, &file); + if (v->address == 0) str_exception(ERR_OTHER, "Cannot access loader data"); + v->type_class = TYPE_CLASS_POINTER; + v->big_endian = ctx->big_endian; + v->size = file && file->elf64 ? 8 : 4; +} + +static int expression_identifier_callback(Context * ctx, int frame, char * name, Value * v) { + if (ctx == NULL) return 0; + if (EXT(ctx)->pid == 0) return 0; + if (strcmp(name, "$loader_brk") == 0) { + get_debug_structure_address(ctx, v); + switch (v->size) { + case 4: v->address += 8; break; + case 8: v->address += 16; break; + default: assert(0); + } + v->remote = 1; +#if defined(__arm__) + { + /* On ARM, r_debug.r_brk can have bit 0 set to 1 to indicate Thumb ISA. + * We need to clear the bit to make a valid breakpoint address. */ + size_t size = (size_t)v->size; + uint8_t * buf = (uint8_t *)tmp_alloc(size); + if (context_read_mem(ctx, v->address, buf, size) < 0) exception(errno); + buf[v->big_endian ? size - 1 : 0] &= ~1; + v->value = buf; + v->remote = 0; + } +#endif + return 1; + } + if (strcmp(name, "$loader_state") == 0) { + get_debug_structure_address(ctx, v); + switch (v->size) { + case 4: v->address += 12; break; + case 8: v->address += 24; break; + default: assert(0); + } + v->type_class = TYPE_CLASS_INTEGER; + v->remote = 1; + return 1; + } + return 0; +} + +static void eventpoint_at_loader(Context * ctx, void * args) { + enum r_state { RT_CONSISTENT, RT_ADD, RT_DELETE }; + ELF_File * file = NULL; + ContextAddress addr = 0; + unsigned size = 0; + ContextAddress state = 0; + ContextExtensionLinux * ext = NULL; + + assert(!is_intercepted(ctx)); + if (EXT(ctx)->pid == 0) return; + addr = elf_get_debug_structure_address(ctx, &file); + size = file && file->elf64 ? 8 : 4; + if (ctx->parent != NULL) ctx = ctx->parent; + ext = EXT(ctx); + + if (addr != 0) { + switch (size) { + case 4: addr += 12; break; + case 8: addr += 24; break; + default: assert(0); + } + if (elf_read_memory_word(ctx, file, addr, &state) < 0) { + trace(LOG_ALWAYS, "Can't read loader state flag: %s", errno_to_str(errno)); + ctx->pending_intercept = 1; + ext->loader_state = 0; + return; + } + } + + switch (state) { + case RT_CONSISTENT: + if (ext->loader_state == RT_ADD) { + memory_map_event_module_loaded(ctx); + } + else if (ext->loader_state == RT_DELETE) { + memory_map_event_module_unloaded(ctx); + } + break; + case RT_ADD: + break; + case RT_DELETE: + /* TODO: need to call memory_map_event_code_section_ummapped() */ + break; + } + ext->loader_state = state; +} + +#endif /* SERVICE_Expressions && ENABLE_ELF */ + +static void eventpoint_at_main(Context * ctx, void * args) { + if (EXT(ctx)->pid == 0) return; + EXT(ctx->mem)->crt0_done = 1; + send_context_changed_event(ctx->mem); + memory_map_event_mapping_changed(ctx->mem); + if ((EXT(ctx)->attach_mode & CONTEXT_ATTACH_NO_MAIN) == 0) { + suspend_by_breakpoint(ctx, ctx, NULL, 1); + } +} + +static void create_eventpoints(Context * ctx) { + ContextExtensionLinux * ext = EXT(ctx); + assert(context_get_group(ctx, CONTEXT_GROUP_PROCESS) == ctx); +#if SERVICE_Expressions && ENABLE_ELF + ext->bp_loader = create_eventpoint("$loader_brk", ctx, eventpoint_at_loader, NULL); +#endif /* SERVICE_Expressions && ENABLE_ELF */ + ext->bp_main = create_eventpoint("main", ctx, eventpoint_at_main, NULL); +} + static Context * add_thread(Context * parent, Context * creator, pid_t pid) { Context * ctx; assert (parent != NULL); @@ -1377,7 +1639,10 @@ static Context * add_thread(Context * parent, Context * creator, pid_t pid) { EXT(ctx)->sigstop_posted = 1; alloc_regs(ctx); ctx->mem = parent; + ctx->name = loc_printf("%d", pid); ctx->big_endian = parent->big_endian; + ctx->reg_access |= REG_ACCESS_RD_STOP; + ctx->reg_access |= REG_ACCESS_WR_STOP; ctx->creator = creator; if (creator) { sigset_copy(&ctx->sig_dont_stop, &creator->sig_dont_stop); @@ -1393,6 +1658,9 @@ static Context * add_thread(Context * parent, Context * creator, pid_t pid) { ctx->pending_intercept = 1; } list_add_last(&ctx->cldl, &parent->children); +#if ENABLE_ContextExtraProperties + update_thread_name(ctx); +#endif link_context(ctx); #if ENABLE_ProfilerSST profiler_sst_add(ctx); @@ -1424,8 +1692,12 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { int * pids = NULL; assert(prs->ref_count == 0); assert(!EXT(prs)->detach_req); +#if ENABLE_ELF + elf_invalidate(); +#endif link_context(prs); send_context_created_event(prs); + create_eventpoints(prs); ctx = add_thread(prs, NULL, pid); if (signal == SIGTRAP && (EXT(prs)->attach_mode & CONTEXT_ATTACH_SELF) != 0) { /* In case of self-attach, tracee can be stopped by SIGTRAP instead of SIGSTOP */ @@ -1526,6 +1798,8 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { prs2->mem_access |= MEM_ACCESS_INSTRUCTION; prs2->mem_access |= MEM_ACCESS_DATA; prs2->mem_access |= MEM_ACCESS_USER; + prs2->mem_access |= MEM_ACCESS_RD_STOP; + prs2->mem_access |= MEM_ACCESS_WR_STOP; prs2->big_endian = ctx->parent->big_endian; (prs2->creator = ctx)->ref_count++; sigset_copy(&prs2->sig_dont_stop, &ctx->sig_dont_stop); @@ -1537,8 +1811,12 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { break; } prs2->ref_count--; +#if ENABLE_ELF + elf_invalidate(); +#endif link_context(prs2); send_context_created_event(prs2); + create_eventpoints(prs2); } add_thread(prs2, ctx, msg); } @@ -1549,30 +1827,14 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { memory_map_event_mapping_changed(ctx->mem); break; case PTRACE_EVENT_EXIT: - if (ext->sigkill_posted) { + if (EXT(ctx->parent)->sigkill_posted) { /* SIGKILL can override PTRACE_EVENT_CLONE event with PTRACE_EVENT_EXIT */ unsigned long child_pid = get_child_pid(EXT(ctx->parent)->pid); if (child_pid) { int state = get_process_state(child_pid); if (state != EOF) { - Context * prs = ctx->parent; - Context * ctx2 = create_context(pid2id(child_pid, EXT(prs)->pid)); - EXT(ctx2)->pid = child_pid; - EXT(ctx2)->attach_mode = EXT(prs)->attach_mode; - EXT(ctx2)->detach_req = EXT(prs)->detach_req; - EXT(ctx2)->sigstop_posted = 1; - alloc_regs(ctx2); - ctx2->mem = prs; - ctx2->big_endian = prs->big_endian; - sigset_copy(&ctx2->sig_dont_stop, &ctx->sig_dont_stop); - sigset_copy(&ctx2->sig_dont_pass, &ctx->sig_dont_pass); + Context * ctx2 = add_thread(ctx->parent, ctx, child_pid); ctx2->exiting = 1; - (ctx2->creator = ctx)->ref_count++; - (ctx2->parent = prs)->ref_count++; - list_add_last(&ctx2->cldl, &prs->children); - link_context(ctx2); - trace(LOG_EVENTS, "event: new context %#" PRIxPTR ", id %s", (uintptr_t)ctx2, ctx2->id); - send_context_created_event(ctx2); if (state == 't' || state == 'T') { event_pid_stopped(child_pid, SIGSTOP, 0, 0); } @@ -1591,9 +1853,8 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { if (signal != SIGSTOP && signal != SIGTRAP) { sigset_set(&ctx->pending_signals, signal, 1); #if defined(__arm__) - /* On ARM, Linux kernel appears to use SIGILL to lazily enable vector registers */ if (signal == SIGILL && !EXT(ctx->mem)->crt0_done) { - /* Ignore */ + /* On ARM, Linux kernel appears to use SIGILL to lazily enable vector registers */ } else #endif @@ -1605,6 +1866,10 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { assert(!ctx->stopped); +#if ENABLE_ContextExtraProperties + update_thread_name(ctx); +#endif + ext->end_of_step = 0; ext->ptrace_event = event; ctx->signal = signal; @@ -1615,12 +1880,12 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { get_PC(ctx, &pc0); + memset(ext->regs_valid, 0, sizeof(REG_SET)); #if defined(__powerpc__) || defined(__powerpc64__) /* Don't retrieve registers from an exiting process, causes kernel critical messages */ if (event != PTRACE_EVENT_EXIT) #endif - memset(ext->regs_valid, 0, sizeof(REG_SET)); get_PC(ctx, &pc1); if (syscall) { @@ -1708,113 +1973,14 @@ static void waitpid_listener(int pid, int exited, int exit_code, int signal, int } } -#if SERVICE_Expressions && ENABLE_ELF - -static void get_debug_structure_address(Context * ctx, Value * v) { - ELF_File * file = NULL; - v->address = elf_get_debug_structure_address(ctx, &file); - if (v->address == 0) str_exception(ERR_OTHER, "Cannot access loader data"); - v->type_class = TYPE_CLASS_POINTER; - v->big_endian = ctx->big_endian; - v->size = file && file->elf64 ? 8 : 4; -} - -static int expression_identifier_callback(Context * ctx, int frame, char * name, Value * v) { - if (ctx == NULL) return 0; - if (EXT(ctx)->pid == 0) return 0; - if (strcmp(name, "$loader_brk") == 0) { - get_debug_structure_address(ctx, v); - switch (v->size) { - case 4: v->address += 8; break; - case 8: v->address += 16; break; - default: assert(0); - } - v->remote = 1; -#if defined(__arm__) - { - /* On ARM, r_debug.r_brk can have bit 0 set to 1 to indicate Thumb ISA. - * We need to clear the bit to make a valid breakpoint address. */ - size_t size = (size_t)v->size; - uint8_t * buf = (uint8_t *)tmp_alloc(size); - if (context_read_mem(ctx, v->address, buf, size) < 0) exception(errno); - buf[v->big_endian ? size - 1 : 0] &= ~1; - v->value = buf; - v->remote = 0; - } +static void event_context_disposed(Context * ctx, void * args) { +#if ENABLE_ContextExtraProperties + ContextExtensionLinux * ext = EXT(ctx); + loc_free(ext->additional_info); + loc_free(ext->thread_name); + ext->additional_info = NULL; + ext->thread_name = NULL; #endif - return 1; - } - if (strcmp(name, "$loader_state") == 0) { - get_debug_structure_address(ctx, v); - switch (v->size) { - case 4: v->address += 12; break; - case 8: v->address += 24; break; - default: assert(0); - } - v->type_class = TYPE_CLASS_INTEGER; - v->remote = 1; - return 1; - } - return 0; -} - -static void eventpoint_at_loader(Context * ctx, void * args) { - enum r_state { RT_CONSISTENT, RT_ADD, RT_DELETE }; - ELF_File * file = NULL; - ContextAddress addr = 0; - unsigned size = 0; - ContextAddress state = 0; - ContextExtensionLinux * ext = NULL; - - assert(!is_intercepted(ctx)); - if (EXT(ctx)->pid == 0) return; - addr = elf_get_debug_structure_address(ctx, &file); - size = file && file->elf64 ? 8 : 4; - if (ctx->parent != NULL) ctx = ctx->parent; - ext = EXT(ctx); - - if (addr != 0) { - switch (size) { - case 4: addr += 12; break; - case 8: addr += 24; break; - default: assert(0); - } - if (elf_read_memory_word(ctx, file, addr, &state) < 0) { - trace(LOG_ALWAYS, "Can't read loader state flag: %s", errno_to_str(errno)); - ctx->pending_intercept = 1; - ext->loader_state = 0; - return; - } - } - - switch (state) { - case RT_CONSISTENT: - if (ext->loader_state == RT_ADD) { - memory_map_event_module_loaded(ctx); - } - else if (ext->loader_state == RT_DELETE) { - memory_map_event_module_unloaded(ctx); - } - break; - case RT_ADD: - break; - case RT_DELETE: - /* TODO: need to call memory_map_event_code_section_ummapped() */ - break; - } - ext->loader_state = state; -} - -#endif /* SERVICE_Expressions && ENABLE_ELF */ - -static void eventpoint_at_main(Context * ctx, void * args) { - if (EXT(ctx)->pid == 0) return; - EXT(ctx->mem)->crt0_done = 1; - send_context_changed_event(ctx->mem); - memory_map_event_mapping_changed(ctx->mem); - if ((EXT(ctx)->attach_mode & CONTEXT_ATTACH_NO_MAIN) == 0) { - suspend_by_breakpoint(ctx, ctx, NULL, 1); - } } static int cmp_linux_pid(Context * ctx, const char * v) { @@ -1827,25 +1993,30 @@ static int cmp_linux_tid(Context * ctx, const char * v) { } static int cmp_linux_kernel_name(Context * ctx, const char * v) { - struct utsname un; - if (uname(&un) != 0) { - return 0; + if (EXT(ctx)->pid != 0) { + struct utsname buf; + if (uname(&buf) != 0) return 0; + return strcmp(buf.sysname, v) == 0; } - return (strcmp(un.sysname, v)== 0); + return 0; } void init_contexts_sys_dep(void) { + static ContextEventListener listener = { NULL }; + listener.context_disposed = event_context_disposed; + add_context_event_listener(&listener, NULL); context_extension_offset = context_extension(sizeof(ContextExtensionLinux)); add_waitpid_listener(waitpid_listener, NULL); ini_context_pid_hash(); #if SERVICE_Expressions && ENABLE_ELF add_identifier_callback(expression_identifier_callback); - create_eventpoint("$loader_brk", NULL, eventpoint_at_loader, NULL); #endif /* SERVICE_Expressions && ENABLE_ELF */ add_context_query_comparator("pid", cmp_linux_pid); add_context_query_comparator("tid", cmp_linux_tid); add_context_query_comparator("KernelName", cmp_linux_kernel_name); - create_eventpoint("main", NULL, eventpoint_at_main, NULL); +#if ENABLE_ContextExtraProperties + post_event(thread_name_timer, NULL); +#endif } #endif /* if ENABLE_DebugContext */ diff --git a/agent/system/Windows/tcf/context-win32.c b/agent/system/Windows/tcf/context-win32.c index 722beb99..ba45b0e2 100644 --- a/agent/system/Windows/tcf/context-win32.c +++ b/agent/system/Windows/tcf/context-win32.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2017 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. @@ -670,6 +670,8 @@ static void debug_event_handler(DebugEvent * debug_event) { prs->mem_access |= MEM_ACCESS_INSTRUCTION; prs->mem_access |= MEM_ACCESS_DATA; prs->mem_access |= MEM_ACCESS_USER; + prs->mem_access |= MEM_ACCESS_RD_STOP; + prs->mem_access |= MEM_ACCESS_WR_STOP; prs->big_endian = big_endian_host(); ext->pid = win32_event->dwProcessId; ext->handle = win32_event->u.CreateProcessInfo.hProcess; @@ -1517,7 +1519,7 @@ static void eventpoint_at_main(Context * ctx, void * args) { } } -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) { } void init_contexts_sys_dep(void) { diff --git a/agent/system/Windows/tcf/pthreads-win32.c b/agent/system/Windows/tcf/pthreads-win32.c index 1f2aa1bd..c33f61b4 100644 --- a/agent/system/Windows/tcf/pthreads-win32.c +++ b/agent/system/Windows/tcf/pthreads-win32.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2015 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. @@ -169,29 +169,15 @@ int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const uint64_t t0, t1; PThreadUserspaceCond * p = NULL; typedef BOOL WINAPI ProcType(void *, void *, DWORD, ULONG); - typedef ULONGLONG WINAPI ClockProcType(void); static ProcType * proc = NULL; - static ClockProcType * clock_proc = NULL; - FILETIME ft; + struct timespec timenow; if (proc == NULL) { if (use_old_api()) return windows_cond_timedwait(cond, mutex, abstime); proc = (ProcType *)GetProcAddress(kernel_module, "SleepConditionVariableSRW"); - clock_proc = (ClockProcType *)GetProcAddress(kernel_module, "GetTickCount64"); } p = (PThreadUserspaceCond *)*cond; - if (p->clock_id == CLOCK_MONOTONIC) { - t0 = clock_proc(); - } - else if (p->clock_id == CLOCK_REALTIME) { - GetSystemTimeAsFileTime(&ft); - t0 = (uint64_t)ft.dwHighDateTime << 32; - t0 |= ft.dwLowDateTime; - t0 /= 10000u; /* from 100 nano-sec periods to msec */ - t0 -= 11644473600000ull; /* from Win epoch to Unix epoch */ - } - else { - return ERR_UNSUPPORTED; - } + if (clock_gettime(p->clock_id, &timenow) < 0) return errno; + t0 = (uint64_t)timenow.tv_sec * 1000 + timenow.tv_nsec / 1000000; t1 = (uint64_t)abstime->tv_sec * 1000 + (abstime->tv_nsec + 999999) / 1000000; if (t1 > t0) return proc(&p->var, mutex, (DWORD)(t1 - t0), 0) ? 0 : ETIMEDOUT; return ETIMEDOUT; @@ -308,10 +294,20 @@ int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) { p->waiters_count = 0; p->was_broadcast = 0; p->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); - if (p->sema == NULL) return set_win32_errno(GetLastError()); + if (p->sema == NULL) { + DWORD last_error = GetLastError(); + loc_free(p); + return set_win32_errno(last_error); + } InitializeCriticalSection(&p->waiters_count_lock); p->waiters_done = CreateEvent(NULL, FALSE, FALSE, NULL); - if (p->waiters_done == NULL) return set_win32_errno(GetLastError()); + if (p->waiters_done == NULL) { + DWORD last_error = GetLastError(); + CloseHandle(p->sema); + DeleteCriticalSection(&p->waiters_count_lock); + loc_free(p); + return set_win32_errno(last_error); + } *cond = (pthread_cond_t)p; return 0; } diff --git a/agent/system/Windows/tcf/pthreads-win32.h b/agent/system/Windows/tcf/pthreads-win32.h index 87c31a12..62939106 100644 --- a/agent/system/Windows/tcf/pthreads-win32.h +++ b/agent/system/Windows/tcf/pthreads-win32.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2017 Wind River Systems, Inc. and others. + * Copyright (c) 2011-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. diff --git a/agent/system/Windows/tcf/windbgcache.c b/agent/system/Windows/tcf/windbgcache.c index 462f12ab..55877ede 100644 --- a/agent/system/Windows/tcf/windbgcache.c +++ b/agent/system/Windows/tcf/windbgcache.c @@ -146,11 +146,13 @@ static ContextEventListener ctx_listener = { event_context_exited, }; +#if ENABLE_MemoryMap static MemoryMapEventListener map_listener = { event_module_loaded, NULL, event_module_unloaded }; +#endif #endif @@ -227,8 +229,10 @@ static FARPROC GetProc(char * name) { CheckDLLVersion(); #if ENABLE_PE add_context_event_listener(&ctx_listener, NULL); +#if ENABLE_MemoryMap add_memory_map_event_listener(&map_listener, NULL); #endif +#endif } return GetProcAddress(dbghelp_dll, name); } diff --git a/agent/system/Windows/tcf/windbgcache.h b/agent/system/Windows/tcf/windbgcache.h index 3a02e23f..2d07e3aa 100644 --- a/agent/system/Windows/tcf/windbgcache.h +++ b/agent/system/Windows/tcf/windbgcache.h @@ -199,7 +199,7 @@ enum SymTagEnum { SymTagMax }; -#if defined(__MINGW32__) +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) typedef struct _IMAGEHLP_LINE64 { DWORD SizeOfStruct; 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/asyncreq.c b/agent/tcf/framework/asyncreq.c index 6a039ee6..abac8a34 100644 --- a/agent/tcf/framework/asyncreq.c +++ b/agent/tcf/framework/asyncreq.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. @@ -48,19 +48,21 @@ #define EVENTS_TIMER_RESOLUTION 50 #endif -static LINK wtlist = TCF_LIST_INIT(wtlist); -static int wtlist_size = 0; -static int wtrunning_count = 0; +static LINK worker_all = TCF_LIST_INIT(worker_all); +static LINK worker_idle = TCF_LIST_INIT(worker_idle); +static unsigned worker_count = 0; +static unsigned idle_count = 0; static pthread_mutex_t wtlock; typedef struct WorkerThread { - LINK wtlink; + LINK link_all; + LINK link_idle; AsyncReqInfo * req; pthread_cond_t cond; pthread_t thread; } WorkerThread; -#define wtlink2wt(A) ((WorkerThread *)((char *)(A) - offsetof(WorkerThread, wtlink))) +#define idle2worker(link) ((WorkerThread *)((char *)(link) - offsetof(WorkerThread, link_idle))) #define AsyncReqTimer -1 @@ -69,10 +71,10 @@ static AsyncReqInfo timer_req; static void trigger_async_shutdown(ShutdownInfo * obj) { check_error(pthread_mutex_lock(&wtlock)); - while (!list_is_empty(&wtlist)) { - WorkerThread * wt = wtlink2wt(wtlist.next); - list_remove(&wt->wtlink); - wtlist_size--; + while (!list_is_empty(&worker_idle)) { + WorkerThread * wt = idle2worker(worker_idle.next); + list_remove(&wt->link_idle); + idle_count--; assert(wt->req == NULL); wt->req = &shutdown_req; check_error(pthread_cond_signal(&wt->cond)); @@ -89,8 +91,10 @@ static void worker_thread_exit(void * x) { check_error(pthread_cond_destroy(&wt->cond)); pthread_join(wt->thread, NULL); check_error(pthread_mutex_lock(&wtlock)); - if (--wtrunning_count == 0) shutdown_set_stopped(&async_shutdown); - trace(LOG_ASYNCREQ, "worker_thread_exit %p running threads %d", wt, wtrunning_count); + assert(worker_count > 0); + list_remove(&wt->link_all); + if (--worker_count == 0) shutdown_set_stopped(&async_shutdown); + trace(LOG_ASYNCREQ, "worker_thread_exit %p running threads %d", wt, worker_count); check_error(pthread_mutex_unlock(&wtlock)); loc_free(wt); } @@ -98,6 +102,8 @@ static void worker_thread_exit(void * x) { static void * worker_thread_handler(void * x) { WorkerThread * wt = (WorkerThread *)x; + tcf_set_thread_name("Async Worker"); + for (;;) { AsyncReqInfo * req = wt->req; @@ -388,10 +394,12 @@ static void * worker_thread_handler(void * x) { { int cnt = 0; while (cnt < req->u.dio.max_files) { - char path[FILE_PATH_SIZE]; + char path_buf[FILE_PATH_SIZE]; + char * path = path_buf; struct DirFileNode * file = req->u.dio.files + cnt; struct dirent * e; struct stat st; + int r = 0; errno = 0; e = readdir((DIR *)req->u.dio.dir); if (e == NULL) { @@ -403,7 +411,8 @@ static void * worker_thread_handler(void * x) { if (strcmp(e->d_name, "..") == 0) continue; file->path = loc_strdup(e->d_name); memset(&st, 0, sizeof(st)); - snprintf(path, sizeof(path), "%s/%s", req->u.dio.path, e->d_name); + r = snprintf(path_buf, sizeof(path_buf), "%s/%s", req->u.dio.path, e->d_name); + if (r < 0 || r >= (int)sizeof(path_buf)) path = loc_printf("%s/%s", req->u.dio.path, e->d_name); if (stat(path, &st) == 0) { #if defined(_WIN32) || defined(__CYGWIN__) file->win32_attrs = GetFileAttributes(path); @@ -411,6 +420,7 @@ static void * worker_thread_handler(void * x) { file->statbuf = (struct stat *)loc_alloc(sizeof(struct stat)); memcpy(file->statbuf, &st, sizeof(struct stat)); } + if (path != path_buf) loc_free(path); cnt++; } } @@ -520,12 +530,12 @@ static void * worker_thread_handler(void * x) { /* Post event inside lock to make sure a new worker thread is not created unnecessarily */ post_event(req->done, req); wt->req = NULL; - if (wtlist_size >= MAX_WORKER_THREADS || async_shutdown.state == SHUTDOWN_STATE_PENDING) { + if (idle_count >= MAX_WORKER_THREADS || async_shutdown.state == SHUTDOWN_STATE_PENDING) { check_error(pthread_mutex_unlock(&wtlock)); break; } - list_add_last(&wt->wtlink, &wtlist); - wtlist_size++; + list_add_last(&wt->link_idle, &worker_idle); + idle_count++; for (;;) { check_error(pthread_cond_wait(&wt->cond, &wtlock)); if (wt->req != NULL) break; @@ -541,12 +551,13 @@ static void worker_thread_add(AsyncReqInfo * req) { WorkerThread * wt; assert(is_dispatch_thread()); - wt = (WorkerThread *)loc_alloc_zero(sizeof *wt); + wt = (WorkerThread *)loc_alloc_zero(sizeof(WorkerThread)); wt->req = req; + list_add_last(&wt->link_all, &worker_all); check_error(pthread_cond_init(&wt->cond, NULL)); check_error(pthread_create(&wt->thread, &pthread_create_attr, worker_thread_handler, wt)); - if (wtrunning_count++ == 0) shutdown_set_normal(&async_shutdown); - trace(LOG_ASYNCREQ, "worker_thread_add %p running threads %d", wt, wtrunning_count); + if (worker_count++ == 0) shutdown_set_normal(&async_shutdown); + trace(LOG_ASYNCREQ, "worker_thread_add %p running threads %d", wt, worker_count); } static void worker_thread_add_deferred(void * x) { @@ -599,8 +610,8 @@ void async_req_post(AsyncReqInfo * req) { } #endif check_error(pthread_mutex_lock(&wtlock)); - if (list_is_empty(&wtlist)) { - assert(wtlist_size == 0); + if (list_is_empty(&worker_idle)) { + assert(idle_count == 0); if (is_dispatch_thread()) { worker_thread_add(req); } @@ -609,9 +620,10 @@ void async_req_post(AsyncReqInfo * req) { } } else { - wt = wtlink2wt(wtlist.next); - list_remove(&wt->wtlink); - wtlist_size--; + assert(idle_count > 0); + wt = idle2worker(worker_idle.next); + list_remove(&wt->link_idle); + idle_count--; assert(wt->req == NULL); wt->req = req; check_error(pthread_cond_signal(&wt->cond)); diff --git a/agent/tcf/framework/cache.c b/agent/tcf/framework/cache.c index 62fb03dc..bd268a39 100644 --- a/agent/tcf/framework/cache.c +++ b/agent/tcf/framework/cache.c @@ -174,16 +174,25 @@ void cache_exit(void) { } #ifdef NDEBUG + void cache_wait(AbstractCache * cache) { + if (current_client.client != NULL) { + current_cache = cache; + cache_miss_cnt++; + } + exception(ERR_CACHE_MISS); +} + #else + +void (cache_wait)(AbstractCache * cache) { cache_wait(cache); } + void cache_wait_dbg(const char * file, int line, AbstractCache * cache) { -#endif assert(is_dispatch_thread()); assert(current_client.client != NULL); if (current_client.client != NULL) { current_cache = cache; cache_miss_cnt++; -#ifndef NDEBUG current_client.file = file; current_client.line = line; current_client.time_stamp = time(NULL); @@ -191,16 +200,15 @@ void cache_wait_dbg(const char * file, int line, AbstractCache * cache) { post_event_with_delay(cache_timer, NULL, 5000000); cache_timer_posted = 1; } -#endif } -#ifndef NDEBUG else { trace(LOG_ALWAYS, "Illegal cache access at %s:%d", file, line); } -#endif exception(ERR_CACHE_MISS); } +#endif + void cache_notify(AbstractCache * cache) { unsigned i; unsigned cnt = cache->wait_list_cnt; diff --git a/agent/tcf/framework/cache.h b/agent/tcf/framework/cache.h index 590f6888..4f389241 100644 --- a/agent/tcf/framework/cache.h +++ b/agent/tcf/framework/cache.h @@ -133,9 +133,8 @@ extern void cache_exit(void); * Cache data handling code call cache_wait() to suspend current client * until cache validation is done. */ -#ifdef NDEBUG extern void cache_wait(AbstractCache * cache); -#else +#ifndef NDEBUG #define cache_wait(cache) cache_wait_dbg(__FILE__, __LINE__, cache) extern void cache_wait_dbg(const char * file, int line, AbstractCache * cache); #endif diff --git a/agent/tcf/framework/channel.c b/agent/tcf/framework/channel.c index 8caab4f3..b5ef6a45 100644 --- a/agent/tcf/framework/channel.c +++ b/agent/tcf/framework/channel.c @@ -204,6 +204,7 @@ static void client_connection_ucb(ClientConnection * c) { void notify_channel_created(Channel * c) { unsigned i; + assert(channel_created); assert(client2channel(&c->client) == c); c->client.lock = client_connection_lcb; c->client.unlock = client_connection_ucb; @@ -214,6 +215,7 @@ void notify_channel_created(Channel * c) { void notify_channel_opened(Channel * c) { unsigned i; + assert(channel_created); assert(!is_channel_closed(c)); assert(c->state == ChannelStateConnected); if (c->notified_open) return; @@ -228,6 +230,7 @@ void notify_channel_opened(Channel * c) { void notify_channel_closed(Channel * c) { unsigned i; + assert(channel_created); assert(c->state != ChannelStateConnected); if (!c->notified_open) return; c->notified_open = 0; @@ -297,10 +300,12 @@ void channel_clear_broadcast_group(Channel * c) { } void channel_lock(Channel * c) { + assert(channel_created); c->lock(c); } void channel_unlock(Channel * c) { + assert(channel_created); c->unlock(c); } @@ -338,6 +343,7 @@ static void lock_timer_event(void * args) { #endif void channel_lock_with_msg(Channel * c, const char * msg) { + assert(channel_created); c->lock(c); #ifndef NDEBUG if (msg != NULL) { @@ -373,6 +379,7 @@ void channel_lock_with_msg(Channel * c, const char * msg) { void channel_unlock_with_msg(Channel * c, const char * msg) { #ifndef NDEBUG + assert(channel_created); if (msg != NULL) { int ok = 0; ChannelLock * l = NULL; @@ -573,6 +580,7 @@ Channel * channel_alloc(void) { * Release a buffer allocated using channel_alloc(). */ void channel_free(Channel * c) { + assert(channel_created); loc_free(c); } diff --git a/agent/tcf/framework/channel_lws.c b/agent/tcf/framework/channel_lws.c index 850cdbfd..1b028298 100644 --- a/agent/tcf/framework/channel_lws.c +++ b/agent/tcf/framework/channel_lws.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016-2019 Wind River Systems, Inc. and others. + * Copyright (c) 2016-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. @@ -1252,6 +1252,8 @@ static void * lws_service_thread(void * x) { struct lws_context_creation_info context_creation_info; int vhost_created = 0; + tcf_set_thread_name("LWS Service"); + memset(&context_creation_info, 0, sizeof context_creation_info); context_creation_info.gid = -1; context_creation_info.uid = -1; diff --git a/agent/tcf/framework/channel_tcp.c b/agent/tcf/framework/channel_tcp.c index a5d0d0c3..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; @@ -88,6 +88,13 @@ # endif #endif +#ifndef SOCKET_SEND_BUFFER_MINSIZE +# define SOCKET_SEND_BUFFER_MINSIZE 200 * 1024 +#endif +#ifndef SOCKET_RECV_BUFFER_MINSIZE +# define SOCKET_RECV_BUFFER_MINSIZE 120 * 1024 +#endif + typedef struct ChannelTCP ChannelTCP; struct ChannelTCP { @@ -244,11 +251,46 @@ static int certificate_verify_callback(int preverify_ok, X509_STORE_CTX * ctx) { return err == 0 && found; } -/* Created by: openssl dhparam -5 -C 1024 */ -/* Note: Java prior to 1.7 does not support Diffie-Hellman parameters longer than 1024 bits */ -/* Note: Bug in OpenSSL 1.0.2: If generator is not 2 or 5, dh->g=generator is not a usable generator */ -static DH * get_dh1024(void) { - static unsigned char dhp_1024[] = { +static DH * get_dh_key(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10101000 + /* In OpenSSL 1.1.1, required key-length for the Diffie-Hellman parameters was increased to 2048 bits */ + /* Note: Java prior to 1.7 does not support Diffie-Hellman parameters longer than 1024 bits */ + /* Created by: openssl dhparam -5 -C 2048 */ + static const unsigned char dhp_buf[] = { + 0xFA, 0xCB, 0x30, 0x26, 0x0F, 0x29, 0xE0, 0x54, 0xEF, 0x45, + 0xD7, 0x5D, 0x31, 0xA3, 0xFA, 0xD8, 0xD1, 0x42, 0xD5, 0x42, + 0x15, 0x87, 0x33, 0x95, 0x41, 0x11, 0x85, 0xC1, 0x06, 0x47, + 0x28, 0xBF, 0x42, 0xCD, 0xF7, 0x83, 0x50, 0x03, 0xF8, 0xBC, + 0xA6, 0xB6, 0xC1, 0xDB, 0x0A, 0x29, 0xB9, 0xD1, 0x59, 0x48, + 0x2C, 0x3A, 0x0B, 0x3B, 0x55, 0x7F, 0x44, 0x8D, 0x61, 0xAB, + 0xF0, 0x7A, 0x6B, 0x78, 0x5D, 0x52, 0x7C, 0xC4, 0xCB, 0x77, + 0x89, 0xFF, 0x0D, 0x41, 0xA2, 0x7E, 0x19, 0xCC, 0x2E, 0xA9, + 0xCD, 0x1E, 0x9E, 0x04, 0xC7, 0xAD, 0x70, 0xF9, 0xBA, 0x5E, + 0xE1, 0xA1, 0x25, 0xA7, 0xFB, 0xB4, 0xF5, 0xE9, 0x4E, 0xBB, + 0x44, 0x6E, 0x6B, 0xE4, 0xD4, 0xE6, 0x08, 0x78, 0x96, 0x3C, + 0x95, 0x61, 0xF0, 0x10, 0x77, 0x33, 0x8A, 0x6D, 0x61, 0xB6, + 0x2A, 0xB9, 0x2B, 0x64, 0xFF, 0x91, 0xA6, 0x89, 0x9F, 0xD5, + 0xDA, 0x70, 0xC4, 0x15, 0x96, 0xE4, 0xF4, 0x46, 0x3B, 0x1E, + 0x91, 0x0A, 0xA1, 0x42, 0xE7, 0x90, 0x97, 0xA8, 0x71, 0xD9, + 0x52, 0x12, 0xC5, 0x21, 0x6D, 0x48, 0x72, 0x46, 0x5D, 0xC2, + 0xAA, 0x6C, 0x42, 0xA6, 0x19, 0xD1, 0x3E, 0xCC, 0x04, 0x3D, + 0xDB, 0xA7, 0x09, 0x45, 0xCC, 0x9A, 0xB8, 0x32, 0xB7, 0x46, + 0xB9, 0x39, 0x53, 0x53, 0x79, 0xB7, 0xFB, 0xAF, 0x1E, 0xE3, + 0xD8, 0x44, 0x57, 0xCF, 0x50, 0x97, 0x22, 0x9D, 0xBB, 0xD3, + 0x08, 0xB9, 0x9F, 0x30, 0x4D, 0x2D, 0x50, 0x8F, 0xFA, 0x63, + 0x48, 0x99, 0x98, 0x46, 0x67, 0xAB, 0x06, 0xEC, 0x0E, 0xDF, + 0x4C, 0xEE, 0x3A, 0x8E, 0x95, 0xF1, 0x18, 0xFB, 0x10, 0x30, + 0x28, 0x95, 0xF3, 0xDF, 0x59, 0x11, 0x4B, 0xC2, 0x7D, 0x7C, + 0x78, 0x4D, 0xF4, 0x71, 0x93, 0xDF, 0xE7, 0xD3, 0x2B, 0xCC, + 0x21, 0x4A, 0x50, 0xA4, 0x6B, 0x7F + }; + static const unsigned char dhg_buf[] = { + 0x05 + }; +#else + /* Created by: openssl dhparam -5 -C 1024 */ + /* Note: Bug in OpenSSL 1.0.2: If generator is not 2 or 5, dh->g=generator is not a usable generator */ + static unsigned char dhp_buf[] = { 0xD0, 0x8E, 0x12, 0x70, 0x45, 0x22, 0x7D, 0x83, 0x06, 0xB5, 0x49, 0xD8, 0x86, 0x34, 0x3A, 0x8E, 0x1D, 0xE9, 0x6C, 0x84, 0x3A, 0x83, 0x2E, 0x0E, 0xD0, 0x7B, 0x5F, 0x69, 0x65, 0xFD, @@ -263,17 +305,16 @@ static DH * get_dh1024(void) { 0x7F, 0xA8, 0xEA, 0x68, 0x2E, 0x19, 0x06, 0x26, 0x3F, 0x9F, 0x29, 0x07, 0x30, 0xD7, 0xFA, 0xB7, 0xD6, 0xCF }; - static unsigned char dhg_1024[] = { + static unsigned char dhg_buf[] = { 0x05 }; - +#endif BIGNUM * dhp_bn = NULL; BIGNUM * dhg_bn = NULL; DH * dh = DH_new(); - if (dh == NULL) return NULL; - dhp_bn = BN_bin2bn(dhp_1024, sizeof(dhp_1024), NULL); - dhg_bn = BN_bin2bn(dhg_1024, sizeof(dhg_1024), NULL); + dhp_bn = BN_bin2bn(dhp_buf, sizeof(dhp_buf), NULL); + dhg_bn = BN_bin2bn(dhg_buf, sizeof(dhg_buf), NULL); if (dhp_bn == NULL || dhg_bn == NULL || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) { BN_free(dhp_bn); BN_free(dhg_bn); @@ -884,6 +925,30 @@ static ChannelTCP * create_channel(int sock, int en_ssl, int server, int unix_do } } + { + /* Buffer sizes need to be large enough to avoid deadlocking when agent connects to itself */ + int snd_org = 0; + int rcv_org = 0; + socklen_t snd_len = sizeof(snd_org); + socklen_t rcv_len = sizeof(rcv_org); + int snd_buf = SOCKET_SEND_BUFFER_MINSIZE; + int rcv_buf = SOCKET_RECV_BUFFER_MINSIZE; + + if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&snd_org, &snd_len) < 0) { + trace(LOG_ALWAYS, "getsockopt(SOL_SOCKET,SO_SNDBUF,...) error: %s", errno_to_str(errno)); + } + else if (snd_org < snd_buf && setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&snd_buf, sizeof(snd_buf)) < 0) { + trace(LOG_ALWAYS, "setsockopt(SOL_SOCKET,SO_SNDBUF,%d) error: %s", snd_buf, errno_to_str(errno)); + } + + if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcv_org, &rcv_len) < 0) { + trace(LOG_ALWAYS, "getsockopt(SOL_SOCKET,SO_RCVBUF,...) error: %s", errno_to_str(errno)); + } + else if (rcv_org < rcv_buf && setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcv_buf, sizeof(rcv_buf)) < 0) { + trace(LOG_ALWAYS, "setsockopt(SOL_SOCKET,SO_RCVBUF,%d) error: %s", rcv_buf, errno_to_str(errno)); + } + } + if (en_ssl) { #if ENABLE_SSL if (ssl_ctx == NULL) { @@ -904,7 +969,7 @@ static ChannelTCP * create_channel(int sock, int en_ssl, int server, int unix_do agent_id++; } if (!SSL_CTX_set_session_id_context(ssl_ctx, buf, buf_pos)) err = set_ssl_errno(); - if (!err && (ssl_dh = get_dh1024()) == NULL) err = set_ssl_errno(); + if (!err && (ssl_dh = get_dh_key()) == NULL) err = set_ssl_errno(); if (!err) { int codes = 0; if (!DH_check(ssl_dh, &codes)) { @@ -1201,18 +1266,6 @@ static void server_close(ChannelServer * serv) { /* TODO: free server struct */ } -static void set_socket_buffer_sizes(int sock) { - /* Buffer sizes need to be large enough to avoid deadlocking when agent connects to itself */ - int snd_buf = 4 * BUF_SIZE; - int rcv_buf = 8 * BUF_SIZE; - if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&snd_buf, sizeof(snd_buf)) < 0) { - trace(LOG_ALWAYS, "setsockopt(SOL_SOCKET,SO_SNDBUF,%d) error: %s", snd_buf, errno_to_str(errno)); - } - if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcv_buf, sizeof(rcv_buf)) < 0) { - trace(LOG_ALWAYS, "setsockopt(SOL_SOCKET,SO_RCVBUF,%d) error: %s", rcv_buf, errno_to_str(errno)); - } -} - static ChannelServer * channel_server_create(PeerServer * ps, int sock) { ServerTCP * si = (ServerTCP *)loc_alloc_zero(sizeof *si); /* TODO: need to investigate usage of sizeof(sockaddr_storage) for address buffer size */ @@ -1492,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); @@ -1499,7 +1553,6 @@ void channel_tcp_connect(PeerServer * ps, ChannelConnectCallBack callback, void error = errno; } else { - set_socket_buffer_sizes(info->sock); error = 0; break; } @@ -1539,7 +1592,6 @@ void channel_unix_connect(PeerServer * ps, ChannelConnectCallBack callback, void info->addr_buf = (struct sockaddr *)loc_alloc(sizeof(struct sockaddr_un)); error = setup_unix_sockaddr(ps, (struct sockaddr_un *)info->addr_buf); if (!error && (info->sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) error = errno; - if (!error) set_socket_buffer_sizes(info->sock); if (error) { if (info->sock >= 0) closesocket(info->sock); diff --git a/agent/tcf/framework/compression.c b/agent/tcf/framework/compression.c index 34fa1931..73c4c661 100644 --- a/agent/tcf/framework/compression.c +++ b/agent/tcf/framework/compression.c @@ -231,7 +231,7 @@ static void decode_tables(unsigned type) { } } -static void decode_data_block() { +static void decode_data_block(void) { static const unsigned length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, diff --git a/agent/tcf/framework/config.h b/agent/tcf/framework/config.h index 1172e68d..4015a966 100644 --- a/agent/tcf/framework/config.h +++ b/agent/tcf/framework/config.h @@ -305,7 +305,7 @@ #endif #if !defined(ENABLE_ContextExtraProperties) -# define ENABLE_ContextExtraProperties (TARGET_WINDOWS) +# define ENABLE_ContextExtraProperties (TARGET_UNIX || TARGET_WINDOWS) #endif #if !defined(ENABLE_ContextStateProperties) 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/context.h b/agent/tcf/framework/context.h index c24a8fb7..5f3df720 100644 --- a/agent/tcf/framework/context.h +++ b/agent/tcf/framework/context.h @@ -109,6 +109,10 @@ extern const char * REASON_ERROR; #define MEM_ACCESS_PHYSICAL 0x0080 /* Context uses physical addresses */ #define MEM_ACCESS_CACHE 0x0100 /* Context is a cache */ #define MEM_ACCESS_TLB 0x0200 /* Context is a TLB memory */ +#define MEM_ACCESS_RD_RUNNING 0x0400 /* Context supports reading memory while running */ +#define MEM_ACCESS_WR_RUNNING 0x0800 /* Context supports writing memory while running */ +#define MEM_ACCESS_RD_STOP 0x1000 /* Debugger should stop the context to read memory */ +#define MEM_ACCESS_WR_STOP 0x2000 /* Debugger should stop the context to write memory */ /* * Values of "reg_access". @@ -414,6 +418,8 @@ typedef struct MemoryAccessMode { int bypass_addr_check; int bypass_cache_sync; int verify; + int dont_stop; + int memory_only; /* Access to memory mapped I/O should be blocked and return error */ } MemoryAccessMode; /* Optional memory access function that take additional argument: access mode. */ diff --git a/agent/tcf/framework/cpudefs-ext.h b/agent/tcf/framework/cpudefs-ext.h index d425abef..20bc46ff 100644 --- a/agent/tcf/framework/cpudefs-ext.h +++ b/agent/tcf/framework/cpudefs-ext.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2017 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. @@ -36,11 +36,17 @@ typedef struct SysRegisterData { } SysRegisterData; RegisterDefinition * get_reg_definitions(Context * ctx) { - if (context_has_state(ctx)) return regs_index; - return NULL; + if (!context_has_state(ctx)) return NULL; +#ifdef ENABLE_cpu_alt_isa_mode + if (is_alt_isa_thread(ctx)) return get_alt_reg_definitions(ctx); +#endif + return regs_index; } uint8_t * get_break_instruction(Context * ctx, size_t * size) { +#ifdef ENABLE_cpu_alt_isa_mode + if (is_alt_isa_thread(ctx)) return get_alt_break_instruction(ctx, size); +#endif *size = sizeof(BREAK_INST); return BREAK_INST; } @@ -85,6 +91,9 @@ RegisterDefinition * get_reg_by_id(Context * ctx, unsigned id, RegisterIdScope * GET_REG_BY_ID_HOOK; #endif if (context_has_state(ctx)) { +#ifdef ENABLE_cpu_alt_isa_mode + if (is_alt_isa_thread(ctx)) return get_alt_reg_by_id(ctx, id, scope); +#endif switch (scope->id_type) { case REGNUM_DWARF: def = get_sys_reg_by_dwarf_id(id); break; case REGNUM_EH_FRAME: def = get_sys_reg_by_eh_frame_id(id); break; @@ -105,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 0615739a..fec3cacb 100644 --- a/agent/tcf/framework/cpudefs.c +++ b/agent/tcf/framework/cpudefs.c @@ -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. @@ -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; } } @@ -242,12 +268,16 @@ int id2reg_num(const char * id, const char ** ctx_id, int * frame, unsigned * re int id2register(const char * id, Context ** ctx, int * frame, RegisterDefinition ** reg_def) { const char * ctx_id = NULL; + RegisterDefinition * defs = NULL; unsigned reg_num = 0; *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) { @@ -258,10 +288,25 @@ int id2register(const char * id, Context ** ctx, int * frame, RegisterDefinition errno = ERR_ALREADY_EXITED; return -1; } - *reg_def = get_reg_definitions(*ctx) + reg_num; + defs = get_reg_definitions(*ctx); + if (defs == NULL) { + 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"); } @@ -520,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; @@ -544,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' */ @@ -556,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); @@ -567,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; @@ -596,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); @@ -608,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) { @@ -733,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 ddee358c..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; } @@ -657,6 +658,8 @@ void check_error(int error) { #else /* NDEBUG */ +void (check_error)(int error) { check_error(error); } + void check_error_debug(const char * file, int line, int error) { if (error == 0) return; #if ENABLE_Trace diff --git a/agent/tcf/framework/errors.h b/agent/tcf/framework/errors.h index b7030886..f8e73a76 100644 --- a/agent/tcf/framework/errors.h +++ b/agent/tcf/framework/errors.h @@ -163,9 +163,8 @@ extern void release_error_report(ErrorReport * report); * check_error(): Check error code. * If the code is not zero, add error report into trace log and call exit(1) */ -#ifdef NDEBUG extern void check_error(int error); -#else +#ifndef NDEBUG extern void check_error_debug(const char * file, int line, int error); #define check_error(error) check_error_debug(__FILE__, __LINE__, error) #endif 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 7ca96de1..3901e993 100644 --- a/agent/tcf/framework/inputbuf.c +++ b/agent/tcf/framework/inputbuf.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 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,6 +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); ibuf->post_read(ibuf, ibuf->inp, size); } } @@ -86,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); @@ -172,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 3ca166fa..c0d35531 100644 --- a/agent/tcf/framework/json.c +++ b/agent/tcf/framework/json.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. @@ -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) @@ -705,7 +705,6 @@ void json_read_binary_start(JsonReadBinaryState * state, InputStream * inp) { json_test_char(inp, 'l'); json_test_char(inp, 'l'); state->encoding = ENCODING_BINARY; - state->size_start = 0; } else { exception(ERR_JSON_SYNTAX); @@ -745,7 +744,7 @@ size_t json_read_binary_data(JsonReadBinaryState * state, void * buf, size_t len if (state->rem > sizeof(state->buf)) exception(ERR_JSON_SYNTAX); while (i < state->rem) state->buf[j++] = state->buf[i++]; state->rem = j; - return res; + break; } state->rem = 0; } @@ -997,8 +996,7 @@ static void skip_object(InputStream * inp) { for (;;) { skip_object(inp); skip_whitespace(inp); - ch = skip_char(inp); - check_char(ch, ':'); + check_char(skip_char(inp), ':'); skip_object(inp); skip_whitespace(inp); ch = skip_char(inp); @@ -1009,16 +1007,30 @@ static void skip_object(InputStream * inp) { } return; case '(': + tmp_buf_pos--; { - unsigned long size = json_read_ulong(inp); - ch = skip_char(inp); - check_char(ch, ')'); - while (size) { + size_t i; + size_t size = 0; + char * cbf = NULL; + ByteArrayOutputStream buf; + OutputStream * out = create_byte_array_output_stream(&buf); + for (;;) { ch = read_stream(inp); - if (ch < 0) exception(ERR_JSON_SYNTAX); - tmp_buf_add(ch); - size--; + if (ch < '0' || ch > '9') break; + size = size * 10 + (ch - '0'); } + check_char(ch, ')'); + /* Binary data cannot be stored in tmp_buf and needs to be converted to BASE64 string */ + cbf = (char *)tmp_alloc(size); + for (i = 0; i < size; i++) cbf[i] = (char)read_stream(inp); + write_stream(out, '"'); + write_base64(out, cbf, size); + write_stream(out, '"'); + get_byte_array_output_stream_data(&buf, &cbf, &size); + while (tmp_buf_pos + size > tmp_buf_size) realloc_tmp_buf(); + memcpy(tmp_buf + tmp_buf_pos, cbf, size); + tmp_buf_pos += size; + loc_free(cbf); } return; default: @@ -1102,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 2ffb2d8e..e7688544 100644 --- a/agent/tcf/framework/mdep-inet.h +++ b/agent/tcf/framework/mdep-inet.h @@ -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. @@ -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 @@ -117,9 +117,6 @@ extern int wsa_closesocket(int socket); #define SA_LEN(addr) ((addr)->sa_len) #define MSG_MORE 0 -#if _WRS_VXWORKS_MAJOR < 6 || _WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR < 9 -#define send(s, buf, len, flags) (send)(s, (char *)(buf), len, flags) -#endif extern void loc_freeaddrinfo(struct addrinfo * ai); extern int loc_getaddrinfo(const char * nodename, const char * servname, diff --git a/agent/tcf/framework/mdep-ptrace.h b/agent/tcf/framework/mdep-ptrace.h index e1fd2ebc..1f2f9a5e 100644 --- a/agent/tcf/framework/mdep-ptrace.h +++ b/agent/tcf/framework/mdep-ptrace.h @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2018 Xilinx, Inc. and others. +* Copyright (c) 2018-2019 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. @@ -55,11 +55,4 @@ # define PTRACE_EVENT_EXIT 6 #endif -#if defined(__arm__) || defined(__aarch64__) -# if !defined(PTRACE_GETVFPREGS) -# define PTRACE_GETVFPREGS 27 -# define PTRACE_SETVFPREGS 28 -# endif -#endif - #endif /* D_mdep_ptrace */ diff --git a/agent/tcf/framework/mdep-threads.h b/agent/tcf/framework/mdep-threads.h index abd67a56..bf7a7a10 100644 --- a/agent/tcf/framework/mdep-threads.h +++ b/agent/tcf/framework/mdep-threads.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2012 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. @@ -33,7 +33,7 @@ #include <pthread.h> -#elif defined __SYMBIAN32__ +#elif defined(__SYMBIAN32__) #include <pthreadtypes.h> #include <pthread.h> @@ -44,6 +44,10 @@ #endif +/* Set current thread name - for a better agent debugging experience + * with host debugger that can display thread names. */ +extern int tcf_set_thread_name(const char * name); + extern pthread_attr_t pthread_create_attr; #endif /* D_mdep_threads */ diff --git a/agent/tcf/framework/mdep.c b/agent/tcf/framework/mdep.c index c25701e1..148c9b8e 100644 --- a/agent/tcf/framework/mdep.c +++ b/agent/tcf/framework/mdep.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. @@ -20,6 +20,11 @@ * agent code portable between Linux, Windows, VxWorks and potentially other OSes. */ +#if defined(__GNUC__) && !defined(_GNU_SOURCE) && !defined(__CYGWIN__) +/* pthread_setname_np() needs _GNU_SOURCE */ +# define _GNU_SOURCE +#endif + #include <tcf/config.h> #include <stdlib.h> #include <stdio.h> @@ -259,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) { @@ -314,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; @@ -405,7 +431,9 @@ static wchar_t * str_to_wide_char(const char * str) { } len = MultiByteToWideChar(CP_UTF8, 0, str, -1, res, len); if (len == 0) { - set_win32_errno(GetLastError()); + DWORD last_error = GetLastError(); + free(res); + set_win32_errno(last_error); return NULL; } return res; @@ -655,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 @@ -685,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); @@ -726,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 @@ -794,13 +887,7 @@ int getegid(void) { } const char * get_os_name(void) { -#if _WRS_VXWORKS_MAJOR > 6 || _WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 7 return VXWORKS_VERSION; -#else - static char str[256]; - snprintf(str, sizeof(str), "VxWorks %s", kernelVersion()); - return str; -#endif } const char * get_user_home(void) { @@ -812,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); @@ -847,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); } @@ -976,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, ""); @@ -1313,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 @@ -1366,16 +1481,16 @@ static NTSTATUS disable_handle_inheritance(void) { return status; } -static char *make_cmd_from_args(char **args) { +static char * make_cmd_from_args(char ** args) { int i = 0; int cmd_size = 0; int cmd_pos = 0; - char *cmd = NULL; + char * cmd = NULL; # define cmd_append(ch) { \ if (cmd_pos >= cmd_size) { \ cmd_size += 0x1000; \ - cmd = (char *)loc_realloc(cmd, cmd_size); \ + cmd = (char *)tmp_realloc(cmd, cmd_size); \ } \ cmd[cmd_pos++] = (ch); \ } @@ -1405,7 +1520,7 @@ int is_daemon(void) { # define pipe(fds) _pipe((fds), 1024, 0) # endif -void become_daemon(char **args) { +void become_daemon(char ** args) { int fdpairs[4]; int npairs = 2; char fnm[FILE_PATH_SIZE]; @@ -1875,15 +1990,60 @@ 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 + +int tcf_set_thread_name(const char * name) { +#if defined(__APPLE__) + return pthread_setname_np(name); +#elif defined(_WIN32) + int error = 0; + typedef HRESULT(FAR WINAPI * ProcType)(HANDLE, wchar_t *); + static ProcType set_td; + static int init_done; + size_t w_len; + wchar_t * w_name = NULL; + HANDLE thread; + + if (!init_done) { + HMODULE kernel_dll = LoadLibrarySystem32("Kernel32.dll"); + if (kernel_dll != NULL) { + set_td = (ProcType)GetProcAddress(kernel_dll, "SetThreadDescription"); + if (set_td == NULL) { + /* Decrement the reference count. */ + FreeLibrary(kernel_dll); + } + } + init_done = 1; + } + + if (set_td == NULL) return 0; + + w_len = strlen(name) + 1; + w_name = (wchar_t *)loc_alloc_zero(sizeof(wchar_t) * w_len); + thread = OpenThread(SYNCHRONIZE | THREAD_SET_INFORMATION, FALSE, GetCurrentThreadId()); + + if (thread == NULL) error = set_win32_errno(GetLastError()); + if (!error) { + w_len = MultiByteToWideChar(CP_UTF8, 0, name, -1, w_name, w_len); + if (w_len == 0) error = set_win32_errno(GetLastError()); + } + if (!error && set_td(thread, w_name) < 0) error = set_win32_errno(GetLastError()); + if (!CloseHandle(thread) && !error) error = set_win32_errno(GetLastError()); + + loc_free(w_name); + return error; +#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; +#endif +} diff --git a/agent/tcf/framework/mdep.h b/agent/tcf/framework/mdep.h index 4ea57f56..f9da3f2f 100644 --- a/agent/tcf/framework/mdep.h +++ b/agent/tcf/framework/mdep.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 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. @@ -67,9 +67,9 @@ # endif # ifdef _DEBUG # define _CRTDBG_MAP_ALLOC -# include <stdlib.h> # include <crtdbg.h> # endif +# include <stdlib.h> /* Required for the byte swap intrinsics. */ # define _WSPIAPI_H_ #endif @@ -148,10 +148,12 @@ struct timespec { #if defined(_M_IX86) # define __i386__ #elif defined(_M_AMD64) -# define __x86_64__ +# ifndef __x86_64__ +# define __x86_64__ +# endif #endif -#define strcasecmp(x,y) stricmp(x,y) -#define strncasecmp(x,y,z) strnicmp(x,y,z) +#define strcasecmp(x,y) _stricmp(x,y) +#define strncasecmp(x,y,z) _strnicmp(x,y,z) #if defined(USE_WINDOWS_SCHED_H) # include <windows/sched.h> #else @@ -159,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); @@ -184,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 */ @@ -199,16 +213,10 @@ extern ssize_t pwrite(int fd, const void * buf, size_t size, off_t offset); #include <strings.h> #include <sys/ioctl.h> #include <selectLib.h> -#if _WRS_VXWORKS_MAJOR > 6 || _WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 6 -# include <private/taskLibP.h> -#endif +#include <private/taskLibP.h> #define environ taskIdCurrent->ppEnviron -#if _WRS_VXWORKS_MAJOR < 6 || _WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR < 9 -typedef unsigned uintptr_t; -#endif - typedef unsigned long useconds_t; #define FILE_PATH_SIZE PATH_MAX @@ -417,7 +425,28 @@ 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); -#define SWAP(x) swap_bytes(&(x), sizeof(x)) + +#if defined(__GNUC__) && __GNUC__ >= 5 +# define SWAP(x) do { \ + switch(sizeof(x)) { \ + case 8: x = __builtin_bswap64(x); break; \ + case 4: x = __builtin_bswap32(x); break; \ + case 2: x = __builtin_bswap16(x); break; \ + default: swap_bytes(&(x), sizeof(x)); \ + } \ + } while (0) +#elif defined(_MSC_VER) +# define SWAP(x) do { \ + switch(sizeof(x)) { \ + case 8: x = _byteswap_uint64(x); break; \ + case 4: x = _byteswap_ulong(x); break; \ + case 2: x = _byteswap_ushort(x); break; \ + default: swap_bytes(&(x), sizeof(x)); \ + } \ + } while (0) +#else +# define SWAP(x) swap_bytes(&(x), sizeof(x)) +#endif /* Return Operating System name */ extern const char * get_os_name(void); @@ -428,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 1f7ef050..3b4478b1 100644 --- a/agent/tcf/framework/myalloc.c +++ b/agent/tcf/framework/myalloc.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. @@ -26,7 +26,7 @@ #include <tcf/framework/events.h> #include <tcf/framework/myalloc.h> -#define ALIGNMENT (sizeof(size_t *)) +#define ALIGNMENT (sizeof(void *) < 8 ? 8 : sizeof(void *)) #if !defined(ENABLE_FastMemAlloc) # define ENABLE_FastMemAlloc 1 @@ -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) { @@ -152,9 +156,8 @@ void * tmp_realloc(void * ptr, size_t size) { } char * tmp_strdup(const char * s) { - char * rval = (char *)tmp_alloc(strlen(s) + 1); - strcpy(rval, s); - return rval; + size_t len = strlen(s) + 1; + return (char *)memcpy(tmp_alloc(len), s, len); } char * tmp_strdup2(const char * s1, const char * s2) { @@ -168,23 +171,38 @@ char * tmp_strdup2(const char * s1, const char * s2) { char * tmp_strndup(const char * s, size_t len) { char * rval = (char *)tmp_alloc(len + 1); - strncpy(rval, s, len); rval[len] = '\0'; - return rval; + return strncpy(rval, s, len); } char * tmp_printf(const char * fmt, ...) { va_list ap; - char arr[0x100]; + char * buf = NULL; + va_start(ap, fmt); + buf = tmp_vprintf(fmt, ap); + va_end(ap); + 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) { 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) { - va_start(ap, fmt); - n = vsnprintf(buf, len, fmt, ap); - va_end(ap); + n = vsnprintf_apc(buf, len, fmt, ap); if (n < 0) { if (len > 0x1000) break; len *= 2; @@ -196,7 +214,7 @@ char * tmp_printf(const char * fmt, ...) { 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; } @@ -250,9 +268,8 @@ void loc_free(const void * p) { /* strdup() with end-of-memory checking. */ char * loc_strdup(const char * s) { - char * rval = (char *)loc_alloc(strlen(s) + 1); - strcpy(rval, s); - return rval; + size_t len = strlen(s) + 1; + return (char *)memcpy(loc_alloc(len), s, len); } /* strdup2() with concatenation and end-of-memory checking. */ @@ -268,23 +285,27 @@ char * loc_strdup2(const char * s1, const char * s2) { /* strndup() with end-of-memory checking. */ char * loc_strndup(const char * s, size_t len) { char * rval = (char *)loc_alloc(len + 1); - strncpy(rval, s, len); rval[len] = '\0'; - return rval; + return strncpy(rval, s, len); } char * loc_printf(const char * fmt, ...) { va_list ap; - char arr[0x100]; + char * buf = NULL; + va_start(ap, fmt); + buf = loc_vprintf(fmt, ap); + va_end(ap); + return buf; +} + +char * loc_vprintf(const char * fmt, va_list ap) { 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) { - va_start(ap, fmt); - n = vsnprintf(buf, len, fmt, ap); - va_end(ap); + n = vsnprintf_apc(buf, len, fmt, ap); if (n < 0) { if (len > 0x1000) break; len *= 2; @@ -296,6 +317,6 @@ char * loc_printf(const char * fmt, ...) { 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/myalloc.h b/agent/tcf/framework/myalloc.h index 185281f3..d1f975dd 100644 --- a/agent/tcf/framework/myalloc.h +++ b/agent/tcf/framework/myalloc.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 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. @@ -22,6 +22,7 @@ #include <tcf/config.h> #include <stdlib.h> +#include <stdarg.h> #ifndef MEM_HEAP_LINK_SIZE #define MEM_HEAP_LINK_SIZE 0x10 @@ -34,6 +35,7 @@ extern char * loc_strdup(const char * s); extern char * loc_strdup2(const char * s1, const char * s2); extern char * loc_strndup(const char * s, size_t len); extern char * loc_printf(const char * fmt, ...) ATTR_PRINTF(1, 2); +extern char * loc_vprintf(const char * fmt, va_list args); extern void loc_free(const void * p); @@ -48,6 +50,7 @@ extern char * tmp_strdup(const char * s); extern char * tmp_strdup2(const char * s1, const char * s2); extern char * tmp_strndup(const char * s, size_t len); extern char * tmp_printf(const char * fmt, ...) ATTR_PRINTF(1, 2); +extern char * tmp_vprintf(const char * fmt, va_list args); extern void tmp_gc(void); diff --git a/agent/tcf/framework/streams.c b/agent/tcf/framework/streams.c index d8173b6b..9f34241f 100644 --- a/agent/tcf/framework/streams.c +++ b/agent/tcf/framework/streams.c @@ -157,12 +157,17 @@ OutputStream * create_byte_array_output_stream(ByteArrayOutputStream * buf) { } void get_byte_array_output_stream_data(ByteArrayOutputStream * buf, char ** data, size_t * size) { - if (buf->mem == NULL) { - buf->max = buf->pos; - buf->mem = (char *)loc_alloc(buf->max); - memcpy(buf->mem, buf->buf, buf->pos); + if (data != NULL) { + if (buf->mem == NULL) { + buf->max = buf->pos; + buf->mem = (char *)loc_alloc(buf->max); + memcpy(buf->mem, buf->buf, buf->pos); + } + *data = buf->mem; + } + else if (buf->mem != NULL) { + loc_free(buf->mem); } - if (data != NULL) *data = buf->mem; if (size != NULL) *size = buf->pos; buf->mem = NULL; buf->max = 0; 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 38d09bae..be3ddbe6 100644 --- a/agent/tcf/framework/trace.c +++ b/agent/tcf/framework/trace.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. @@ -33,6 +33,10 @@ int log_mode = LOG_EVENTS | LOG_CHILD | LOG_WAITPID | LOG_CONTEXT | LOG_PROTOCOL #include <syslog.h> #endif +#if !defined(ENABLE_CustomPrintTrace) +# define ENABLE_CustomPrintTrace 0 +#endif + static int use_syslog = 0; FILE * log_file = NULL; @@ -52,14 +56,15 @@ 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" } + { LOG_SHUTDOWN, "shutdown", "shutdown of subsystems" }, + { LOG_DISASM, "disasm", "disassembly service" } }; static pthread_mutex_t mutex; +#if !ENABLE_CustomPrintTrace int print_trace(int mode, const char * fmt, ...) { va_list ap; int error = errno; @@ -111,7 +116,7 @@ int print_trace(int mode, const char * fmt, ...) { errno = error; return 1; } - +#endif /* ENABLE_CustomPrintTrace */ #endif /* ENABLE_Trace */ int parse_trace_mode(const char * mode, int * result) { @@ -176,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 cb2e92ed..8ada41d8 100644 --- a/agent/tcf/framework/trace.h +++ b/agent/tcf/framework/trace.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 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. @@ -37,10 +37,10 @@ #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 +#define LOG_DISASM 0x10000 #define LOG_NAME_STDERR "-" @@ -56,15 +56,19 @@ extern int print_trace(int mode, const char * fmt, ...) ATTR_PRINTF(2, 3); extern FILE * log_file; -#define trace log_file == NULL ? (void)0 : (void)print_trace +#ifndef trace +# define trace log_file == NULL ? (void)0 : (void)print_trace +#endif /* not def trace */ #else /* not ENABLE_Trace */ -#if (defined(_MSC_VER) && _MSC_VER >= 1400) || defined(__GNUC__) -# define trace(...) ((void)0) -#else -# define trace 0 && -#endif +#ifndef trace +# if (defined(_MSC_VER) && _MSC_VER >= 1400) || defined(__GNUC__) +# define trace(...) ((void)0) +# else +# define trace 0 && +# endif +#endif /* not def trace */ #endif /* ENABLE_Trace */ 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 1c6c236c..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. @@ -41,7 +41,7 @@ typedef struct ClientData { LINK link_all; - Channel channel; + Channel * channel; /* Must be a pointer, because of channel_extension() */ unsigned lock_cnt; char * id; char * cmd_data; @@ -53,6 +53,7 @@ typedef struct ClientData { char * wait_token; int wait_done; int sse_posted; + int closed; unsigned timeout; } ClientData; @@ -79,11 +80,21 @@ static LINK link_clients; #define link2msg(x) ((Message *)((char *)(x) - offsetof(Message, link))) #define all2client(x) ((ClientData *)((char *)(x) - offsetof(ClientData, link_all))) -#define channel2client(x) ((ClientData *)((char *)(x) - offsetof(ClientData, channel))) + +static ClientData * channel2client(Channel * ch) { + LINK * l = link_clients.next; + while (l != &link_clients) { + ClientData * x = all2client(l); + if (x->channel == ch) return x; + l = l->next; + } + assert(0); + return NULL; +} static void close_client(ClientData * client) { - Channel * channel = &client->channel; - list_remove(&client->link_all); + Channel * channel = client->channel; + client->closed = 1; channel->state = ChannelStateDisconnected; notify_channel_closed(channel); if (channel->disconnected) { @@ -165,7 +176,7 @@ static void http_message(OutputStream * out, Message * m) { } static void send_http_reply(ClientData * cd) { - Channel * ch = &cd->channel; + Channel * ch = cd->channel; OutputStream * out = cd->http_out; write_string(out, "[\n"); while (!list_is_empty(&cd->link_messages)) { @@ -227,16 +238,17 @@ static void sse_event(void * arg) { } static void http_channel_lock(Channel * channel) { - ClientData * client = channel2client(channel); - client->lock_cnt++; + ClientData * cd = channel2client(channel); + cd->lock_cnt++; } static void http_channel_unlock(Channel * channel) { - ClientData * client = channel2client(channel); - assert(client->lock_cnt > 0); - client->lock_cnt--; - if (client->lock_cnt == 0) { - ClientData * cd = channel2client(channel); + ClientData * cd = channel2client(channel); + assert(cd->lock_cnt > 0); + cd->lock_cnt--; + if (cd->lock_cnt == 0) { + assert(cd->closed); + list_remove(&cd->link_all); channel_clear_broadcast_group(channel); while (!list_is_empty(&cd->link_messages)) { Message * e = link2msg(cd->link_messages.next); @@ -245,6 +257,7 @@ static void http_channel_unlock(Channel * channel) { } cancel_event(sse_event, cd, 0); loc_free(channel->peer_name); + channel_free(cd->channel); loc_free(cd->out_buf.mem); loc_free(cd->cmd_data); loc_free(cd->id); @@ -347,8 +360,12 @@ static void http_channel_write(OutputStream * out, int byte) { } static void http_channel_write_block(OutputStream * out, const char * bytes, size_t size) { - unsigned i; - for (i = 0; i < size; i++) http_channel_write(out, (unsigned char)bytes[i]); + Channel * ch = out2channel(out); + if (ch->state != ChannelStateDisconnected) { + ClientData * cd = channel2client(ch); + OutputStream * out = &cd->out_buf.out; + write_block_stream(out, bytes, size); + } } static ssize_t http_channel_splice_block(OutputStream * out, int fd, size_t size, int64_t * offset) { @@ -376,7 +393,7 @@ static void timer_event(void * arg) { while (l != &link_clients) { ClientData * x = all2client(l); l = l->next; - if (x->http_out == NULL && x->sse_out == NULL) { + if (!x->closed && x->http_out == NULL && x->sse_out == NULL) { x->timeout++; if (x->timeout > timeout) { close_client(x); @@ -453,7 +470,7 @@ static ClientData * find_client(int alloc, const char * id) { for (l = link_clients.next; l != &link_clients; l = l->next) { ClientData * x = all2client(l); - if (strcmp(x->id, id) == 0) { + if (!x->closed && strcmp(x->id, id) == 0) { x->timeout = 0; return x; } @@ -465,22 +482,23 @@ static ClientData * find_client(int alloc, const char * id) { cd = (ClientData *)loc_alloc_zero(sizeof(ClientData)); cd->lock_cnt = 1; - cd->channel.state = ChannelStateStartWait; - cd->channel.lock = http_channel_lock; - cd->channel.unlock = http_channel_unlock; - cd->channel.start_comm = http_channel_start_comm; - cd->channel.inp.peek = http_channel_peek; - cd->channel.inp.read = http_channel_read; - cd->channel.out.write = http_channel_write; - cd->channel.out.write_block = http_channel_write_block; - cd->channel.out.splice_block = http_channel_splice_block; - cd->channel.peer_name = loc_printf("HTTP:%s", id); + cd->channel = channel_alloc(); + cd->channel->state = ChannelStateStartWait; + cd->channel->lock = http_channel_lock; + cd->channel->unlock = http_channel_unlock; + cd->channel->start_comm = http_channel_start_comm; + cd->channel->inp.peek = http_channel_peek; + cd->channel->inp.read = http_channel_read; + cd->channel->out.write = http_channel_write; + cd->channel->out.write_block = http_channel_write_block; + cd->channel->out.splice_block = http_channel_splice_block; + cd->channel->peer_name = loc_printf("HTTP:%s", id); create_byte_array_output_stream(&cd->out_buf); list_init(&cd->link_messages); cd->id = loc_strdup(id); list_add_first(&cd->link_all, &link_clients); - if (cd->channel.state == ChannelStateStartWait) { - server.new_conn(&server, &cd->channel); + if (cd->channel->state == ChannelStateStartWait) { + server.new_conn(&server, cd->channel); } return cd; } @@ -537,12 +555,17 @@ static int get_page(const char * uri) { } if (strncmp(uri, "/stop/", 6) == 0) { ClientData * cd = find_client(0, session); + http_printf(cd != NULL ? "OK\n" : "Already stopped\n"); + http_close(); + http_flush(); if (cd != NULL) { + if (cd->sse_out != NULL) { + http_resume(cd->sse_out); + http_printf("data: stop\n\n"); + http_close(); + http_flush(); + } close_client(cd); - http_printf("OK\n"); - } - else { - http_printf("Already stopped\n"); } return 1; } @@ -603,7 +626,7 @@ static int get_page(const char * uri) { if (service != NULL && command != NULL) { Trap trap; ClientData * cd = find_client(1, session); - Channel * ch = &cd->channel; + Channel * ch = cd->channel; ch->inp.cur = NULL; ch->inp.end = NULL; loc_free(cd->cmd_data); @@ -688,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); @@ -707,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 53a280e3..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> @@ -81,6 +81,7 @@ typedef struct HttpConnection { char * page_reason; HttpParam * page_hdrs; int suspended; + int close; int sse; } HttpConnection; @@ -143,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); @@ -262,36 +266,53 @@ static void http_send_done(void * x) { async_req_post(&con->req_wr); return; } - if (con->sse) { - if (con->out.pos > 0) { - con->send_done = 0; - loc_free(con->send_data); - get_byte_array_output_stream_data(&con->out, &con->send_data, &con->send_size); - con->req_wr.u.sio.bufp = con->send_data + con->send_done; - con->req_wr.u.sio.bufsz = con->send_size - con->send_done; - con->write_posted = 1; - async_req_post(&con->req_wr); + if (!con->close) { + if (con->sse) { + if (con->out.pos > 0) { + con->send_done = 0; + loc_free(con->send_data); + get_byte_array_output_stream_data(&con->out, &con->send_data, &con->send_size); + con->req_wr.u.sio.bufp = con->send_data + con->send_done; + con->req_wr.u.sio.bufsz = con->send_size - con->send_done; + con->write_posted = 1; + async_req_post(&con->req_wr); + } + return; + } + if (con->keep_alive) { + clear_connection_state(con); + con->req_rd.u.sio.bufp = con->recv_buf; + con->req_rd.u.sio.bufsz = con->recv_max; + con->read_posted = 1; + async_req_post(&con->req_rd); + return; } - return; - } - if (con->keep_alive) { - clear_connection_state(con); - con->req_rd.u.sio.bufp = con->recv_buf; - con->req_rd.u.sio.bufsz = con->recv_max; - con->read_posted = 1; - async_req_post(&con->req_rd); - return; } } + if (con->read_posted) { + shutdown(con->sock, SHUT_RDWR); + con->close = 1; + return; + } close_connection(con); } 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; @@ -302,41 +323,47 @@ static void send_reply(HttpConnection * con) { } static void read_http_request(HttpConnection * con) { - while (con->recv_len > con->recv_pos && !con->read_request_done) { - unsigned i = 0; - while (con->recv_buf[con->recv_pos++] != '\n') { - if (con->recv_pos >= con->recv_len) return; + char * buf = con->recv_buf; + size_t len = con->recv_len; + while (len > 0 && !con->read_request_done) { + unsigned i = con->recv_pos; + while (i < len && buf[i] != '\n') i++; + if (i++ >= len) { + /* Incomplete line in the buffer */ + con->recv_pos = len; + if (con->recv_len == len) return; + break; } - i = con->recv_pos; + con->recv_pos = 0; if (con->http_method == NULL) { unsigned j = 0; unsigned k = 0; while (j < i) { - char * s = con->recv_buf + j; - while (j < i && con->recv_buf[j] > ' ') j++; - while (j < i && con->recv_buf[j] <= ' ') con->recv_buf[j++] = 0; + unsigned l = j; + char * s = buf + j; + while (j < i && buf[j] > ' ') j++; switch (k++) { - case 0: con->http_method = loc_strdup(s); break; - case 1: con->http_uri = loc_strdup(s); break; - case 2: con->http_ver = loc_strdup(s); break; + case 0: con->http_method = loc_strndup(s, j - l); break; + case 1: con->http_uri = loc_strndup(s, j - l); break; + case 2: con->http_ver = loc_strndup(s, j - l); break; } + while (j < i && buf[j] <= ' ') j++; } } else { - unsigned j = 0; unsigned k = i; - while (k > 0 && con->recv_buf[k - 1] <= ' ') con->recv_buf[--k] = 0; + while (k > 0 && buf[k - 1] <= ' ') k--; if (k == 0) { con->read_request_done = 1; } else { - while (j < k && con->recv_buf[j] != ':') j++; + unsigned j = 0; + while (j < k && buf[j] != ':') j++; if (j < k) { HttpParam * h = (HttpParam *)loc_alloc_zero(sizeof(HttpParam)); - con->recv_buf[j++] = 0; - while (j < k && con->recv_buf[j] == ' ') con->recv_buf[j++] = 0; - h->name = loc_strdup(con->recv_buf); - h->value = loc_strdup(con->recv_buf + j); + h->name = loc_strndup(buf, j++); + while (j < k && buf[j] == ' ') j++; + h->value = loc_strndup(buf + j, k - j); h->next = con->http_hdrs; if (strcmp(h->name, "Connection") == 0 && strcmp(h->value, "keep-alive") == 0) { con->keep_alive = 1; @@ -345,10 +372,11 @@ static void read_http_request(HttpConnection * con) { } } } - memmove(con->recv_buf, con->recv_buf + i, con->recv_len - i); - con->recv_len -= i; - con->recv_pos = 0; + buf += i; + len -= i; } + con->recv_len = len; + memmove(con->recv_buf, buf, len); } static void http_read_done(void * x) { @@ -364,6 +392,11 @@ static void http_read_done(void * x) { con->read_posted = 0; if (len < 0) { + if (con->write_posted) { + shutdown(con->sock, SHUT_RDWR); + con->close = 1; + return; + } close_connection(con); } else if (len > 0) { @@ -456,7 +489,7 @@ void http_flush(void) { } if (!content_type) http_printf("Content-Type: text/html\n"); if (!cache_control) http_printf("Cache-Control: no-cache\n"); - if (con->keep_alive) http_printf("Connection: keep-alive\n"); + if (con->keep_alive && !con->close) http_printf("Connection: keep-alive\n"); if (con->sse) { con->suspended = 1; } @@ -479,6 +512,10 @@ void http_flush(void) { async_req_post(&con->req_wr); } +void http_close(void) { + current_con->close = 1; +} + static int get_page(const char * uri) { unsigned i = 0; char * nm = tmp_strdup(uri); diff --git a/agent/tcf/http/http.h b/agent/tcf/http/http.h index 9c4bb638..64166a91 100644 --- a/agent/tcf/http/http.h +++ b/agent/tcf/http/http.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. @@ -45,9 +45,11 @@ extern void http_printf(const char * fmt, ...) ATTR_PRINTF(1, 2); extern void http_suspend(void); extern void http_resume(OutputStream * out); extern void http_flush(void); +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/cmdline.c b/agent/tcf/main/cmdline.c index b3aaf427..6370fb04 100644 --- a/agent/tcf/main/cmdline.c +++ b/agent/tcf/main/cmdline.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 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. @@ -412,6 +412,8 @@ static void * interactive_handler(void * x) { size_t len; char buf[1000]; + tcf_set_thread_name("Interactive"); + check_error(pthread_mutex_lock(&cmdline_mutex)); while (!done) { if (cmdline_pending) { @@ -442,6 +444,8 @@ static void * interactive_handler(void * x) { static void * single_command_handler(void * x) { const char * connect_string = "connect "; + tcf_set_thread_name("Single Cmd"); + check_error(pthread_mutex_lock(&cmdline_mutex)); post_event(event_cmd_line, loc_strdup2(connect_string, host_name)); diff --git a/agent/tcf/main/gdb-rsp.c b/agent/tcf/main/gdb-rsp.c index cd1a0dad..9c4fcad6 100644 --- a/agent/tcf/main/gdb-rsp.c +++ b/agent/tcf/main/gdb-rsp.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016-2018 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. @@ -46,6 +46,8 @@ #include <machine/ppc64/tcf/cpu-regs-gdb.h> #include <machine/microblaze/tcf/cpu-regs-gdb.h> #include <machine/microblaze64/tcf/cpu-regs-gdb.h> +#include <machine/riscv/tcf/cpu-regs-gdb.h> +#include <machine/riscv64/tcf/cpu-regs-gdb.h> #include <tcf/main/gdb-rsp.h> @@ -58,7 +60,7 @@ # define DEBUG_RSP 0 #endif -#define ID_ANY ~0u +#define ID_ALL ~0u typedef struct GdbServer { LINK link_a2s; @@ -76,7 +78,7 @@ typedef struct GdbClient { uint8_t * buf; AsyncReqInfo req; GdbServer * server; - ClientConnection client; + ClientConnection connection; int closed; /* Command packet */ @@ -159,9 +161,8 @@ 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 size_t context_extension_offset = 0; static int ini_done = 0; static LINK link_a2s; @@ -278,6 +279,10 @@ static const char * get_regs(GdbClient * c) { if (strcmp(c->server->isa, "microblaze64") == 0) return cpu_regs_gdb_microblaze64; if (strcmp(c->server->isa, "mb") == 0) return cpu_regs_gdb_microblaze; if (strcmp(c->server->isa, "mb64") == 0) return cpu_regs_gdb_microblaze64; + if (strcmp(c->server->isa, "riscv32") == 0) return cpu_regs_gdb_riscv32; + if (strcmp(c->server->isa, "riscv64") == 0) return cpu_regs_gdb_riscv64; + if (strcmp(c->server->isa, "rv32") == 0) return cpu_regs_gdb_riscv32; + if (strcmp(c->server->isa, "rv64") == 0) return cpu_regs_gdb_riscv64; set_fmt_errno(ERR_OTHER, "Unsupported ISA %s", c->server->isa); return NULL; } @@ -287,7 +292,10 @@ static int check_process_isa(GdbClient * c, Context * prs) { const char * regs = get_regs(c); if (regs != NULL) { memset(&isa, 0, sizeof(isa)); - context_get_isa(prs, 0, &isa); + if (context_get_isa(prs, 0, &isa) < 0) { + trace(LOG_ALWAYS, "Cannot get process ISA: %s", errno_to_str(errno)); + return 0; + } if (isa.def != NULL) { if (strcmp(isa.def, "386") == 0) return regs == cpu_regs_gdb_i386; if (strcmp(isa.def, "X86_64") == 0) return regs == cpu_regs_gdb_x86_64; @@ -300,6 +308,8 @@ static int check_process_isa(GdbClient * c, Context * prs) { if (strcmp(isa.def, "PPC64") == 0) return regs == cpu_regs_gdb_ppc64; if (strcmp(isa.def, "MicroBlaze") == 0) return regs == cpu_regs_gdb_microblaze; if (strcmp(isa.def, "MicroBlaze64") == 0) return regs == cpu_regs_gdb_microblaze64; + if (strcmp(isa.def, "Riscv32") == 0) return regs == cpu_regs_gdb_riscv32; + if (strcmp(isa.def, "Riscv64") == 0) return regs == cpu_regs_gdb_riscv64; } } return 0; @@ -311,21 +321,32 @@ 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); + if (def == NULL) return NULL; while (def->name != NULL) { if (def->dwarf_id == r->id) return def; def++; } 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) { @@ -345,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) { @@ -523,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; @@ -603,6 +643,10 @@ static void add_res_hex8(GdbClient * c, unsigned n) { add_res_str(c, s); } +static void add_res_hex8_str(GdbClient * c, const char * s) { + while (*s) add_res_hex8(c, *s++); +} + static void add_res_ptid(GdbClient * c, unsigned pid, unsigned tid) { if (c->multiprocess) { add_res_ch(c, 'p'); @@ -802,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; @@ -899,27 +956,78 @@ static void monitor_ps(GdbClient * c, const char * args) { LINK * l; unsigned cnt = 0; for (l = c->link_c2p.next; l != &c->link_c2p; l = l->next) { - char s[256]; - char * m = s; + char * m = NULL; GdbProcess * p = link_c2p(l); if (context_has_state(p->ctx)) { const char * state = get_context_state_name(p->ctx); - snprintf(s, sizeof(s), "%u: %s (%s)\n", (unsigned)p->pid, p->ctx->name ? p->ctx->name : p->ctx->id, state); + m = tmp_printf("%u: %s (%s)\n", (unsigned)p->pid, p->ctx->name ? p->ctx->name : p->ctx->id, state); } else { - snprintf(s, sizeof(s), "%u: %s\n", (unsigned)p->pid, p->ctx->name ? p->ctx->name : p->ctx->id); + m = tmp_printf("%u: %s\n", (unsigned)p->pid, p->ctx->name ? p->ctx->name : p->ctx->id); } - while (*m) add_res_hex8(c, *m++); + add_res_hex8_str(c, m); cnt++; } - if (cnt == 0) { - const char * m = "No processes\n"; - while (*m) add_res_hex8(c, *m++); + if (cnt == 0) add_res_hex8_str(c, "No debug targets found\n"); +} + +static void monitor_info(GdbClient * c, const char * args) { + unsigned pid = 0; + char * s = (char *)args; + while (*s == ' ') s++; + pid = (unsigned)strtol(s, &s, 10); + while (*s == ' ') s++; + if (*s == 0 && pid != 0) { + GdbProcess * prs = find_process_pid(c, pid); + if (prs != NULL) { + Context * ctx = prs->ctx; + add_res_hex8_str(c, tmp_printf("Target %u properties:\n", pid)); + for (;;) { + add_res_hex8_str(c, tmp_printf(" ID : \"%s\"\n", ctx->id)); + if (ctx->parent != NULL) add_res_hex8_str(c, tmp_printf(" ParentID : \"%s\"\n", ctx->parent->id)); + if (ctx->name != NULL) add_res_hex8_str(c, tmp_printf(" Name : \"%s\"\n", ctx->name)); + add_res_hex8_str(c, tmp_printf(" WordSize : %u\n", context_word_size(ctx))); + add_res_hex8_str(c, tmp_printf(" BigEndian : %d\n", ctx->big_endian)); +#if ENABLE_ContextExtraProperties + { + /* Back-end context properties */ + int cnt = 0; + const char ** names = NULL; + const char ** values = NULL; + if (context_get_extra_properties(ctx, &names, &values, &cnt) == 0) { + while (cnt > 0) { + if (*values != NULL) add_res_hex8_str(c, tmp_printf(" %-10s: %s\n", *names, *values)); + names++; + values++; + cnt--; + } + } + } +#endif + if (ctx->parent == NULL) break; + add_res_hex8_str(c, "Parent properties:\n"); + ctx = ctx->parent; + } + return; + } } + add_res_hex8_str(c, "Invalid target ID.\n"); + add_res_hex8_str(c, "Available targets:\n"); + monitor_ps(c, ""); +} + +static void monitor_help(GdbClient * c, const char * args) { + add_res_hex8_str(c, "Usage: monitor <command> [<arguments>]\n"); + add_res_hex8_str(c, "Commands:\n"); + add_res_hex8_str(c, " ps - list of debug targets\n"); + add_res_hex8_str(c, " info <target ID> - properties of a target\n"); + add_res_hex8_str(c, " help - print this text\n"); } static MonitorCommand mon_cmds[] = { { "ps", monitor_ps }, + { "info", monitor_info }, + { "help", monitor_help }, { NULL } }; @@ -1196,7 +1304,7 @@ static int handle_q_command(GdbClient * c) { } } if (m == NULL) m = "Invalid ID"; - while (*m) add_res_hex8(c, *m++); + add_res_hex8_str(c, m); return 0; } if (strcmp(w, "Rcmd") == 0) { @@ -1207,7 +1315,6 @@ static int handle_q_command(GdbClient * c) { MonitorCommand * mon_cmd = NULL; unsigned mon_cnt = 0; unsigned cmd_pos = 0; - const char * res = NULL; while (i < max - 1) { char ch = get_cmd_uint8(c, &s); if (ch == 0) break; @@ -1229,18 +1336,16 @@ static int handle_q_command(GdbClient * c) { } } if (mon_cnt > 1) { - res = "Ambiguous command\n"; + add_res_hex8_str(c, "Ambiguous command.\n"); } else if (mon_cmd == NULL) { - res = "Invalid command\n"; + add_res_hex8_str(c, "Invalid command.\n"); + monitor_help(c, ""); } else { while (cmd[cmd_pos] == ' ') cmd_pos++; mon_cmd->func(c, cmd + cmd_pos); } - if (res) { - while (*res) add_res_hex8(c, *res++); - } return 0; } add_res_str(c, "E02"); @@ -1346,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': @@ -1424,6 +1529,8 @@ static int handle_D_command(GdbClient * c) { c->cur_g_pid = 0; c->cur_g_tid = 0; } + /* According to the GDB manual: Detaching the process continues its execution. */ + if (!p->ctx->exited) continue_debug_context(p->ctx, NULL, RM_RESUME, 1, 0, 0); detach_process(p); add_res_str(c, "OK"); return 0; @@ -1709,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); @@ -1722,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) { @@ -1888,6 +1995,12 @@ int ini_gdb_rsp(const char * conf) { isa = "microblaze"; #elif defined(__MICROBLAZE64__) isa = "microblaze64"; +#elif defined(__riscv) && __riscv_xlen == 32 + isa = "riscv32"; +#elif defined(__riscv) && __riscv_xlen == 64 + isa = "riscv64"; +#elif defined(__riscv) && __riscv_xlen == 128 + isa = "riscv128"; #else isa = "i386"; #endif @@ -1907,7 +2020,6 @@ int ini_gdb_rsp(const char * conf) { if (sock < 0) return -1; if (!ini_done) { list_init(&link_a2s); - context_extension_offset = context_extension(sizeof(LINK)); add_context_event_listener(&context_listener, NULL); add_registers_event_listener(®isters_listener, NULL); add_run_control_event_listener(&run_ctrl_listener, NULL); 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 21aca101..d9aedc76 100644 --- a/agent/tcf/main/main.c +++ b/agent/tcf/main/main.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2019 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. @@ -149,6 +149,7 @@ static void signal_handler(int sig) { static void * signal_handler_thread(void * arg) { int sig = 0; sigset_t * set = (sigset_t *)arg; + tcf_set_thread_name("Signal Handler"); sigwait(set, &sig); exit_event_loop(); return NULL; @@ -431,7 +432,13 @@ int main(int argc, char ** argv) { } } + if (url_cnt == 0) { + if (url_cnt >= url_max) url_arr = (const char **)loc_realloc((void *)url_arr, sizeof(const char *) * (url_max += 16)); + url_arr[url_cnt++] = DEFAULT_SERVER_URL; + } + POST_OPTION_HOOK; + if (daemon) { #if defined(_WIN32) || defined(__CYGWIN__) become_daemon(daemon > 1 ? argv : NULL); @@ -467,20 +474,15 @@ int main(int argc, char ** argv) { { unsigned i; - if (url_cnt == 0) { - if (url_cnt >= url_max) url_arr = (const char **)loc_realloc((void *)url_arr, sizeof(const char *) * (url_max += 16)); - url_arr[url_cnt++] = DEFAULT_SERVER_URL; - } - 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); } } loc_free(url_arr); url_cnt = 0; - url_cnt = 0; + url_max = 0; discovery_start(); } @@ -518,6 +520,5 @@ int main(int argc, char ** argv) { PRE_EXIT_HOOK; - fprintf(stderr, "\n"); return 0; } 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/main/test.c b/agent/tcf/main/test.c index 9b37a708..253ad77f 100644 --- a/agent/tcf/main/test.c +++ b/agent/tcf/main/test.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 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. @@ -17,10 +17,21 @@ * Agent self-testing service. */ -#include <tcf/config.h> +#ifndef PURE_RCBP_TEST +# include <tcf/config.h> +#else +# include <stdlib.h> +# include <errno.h> +# define usleep(x) {} +# ifndef ENABLE_RCBP_TEST +# define ENABLE_RCBP_TEST 1 +# endif +#endif #if ENABLE_RCBP_TEST +#ifndef PURE_RCBP_TEST + #ifndef ENABLE_TestSymbols # define ENABLE_TestSymbols (SERVICE_Expressions && !ENABLE_ELF) #endif @@ -39,6 +50,8 @@ # include <system/Windows/tcf/context-win32.h> #endif +#endif /* PURE_RCBP_TEST */ + #ifdef __cplusplus bool tcf_cpp_test_bool = false; @@ -166,6 +179,20 @@ unsigned tcf_test_func_call_cnt = 0; static test_array_field tcf_test_array_field; +#if defined(__clang_major__) && __clang_major__ == 7 +/* TLS debug info is broken in clang 7.0 */ +# define TLS_SUPPORTED 0 +#elif defined(__linux__) && defined(__GNUC__) +# define TLS_SUPPORTED 1 +#else +# define TLS_SUPPORTED 0 +#endif + +#if TLS_SUPPORTED +__thread uint32_t tcf_test_tls = 0; +__thread uint32_t tcf_test_tls2 = 0; +#endif + int tcf_test_func_int(int x, int y) { tcf_test_func_call_cnt++; return x + y; @@ -205,6 +232,10 @@ func2_label: tcf_test_short++; errno = tcf_test_short; func2_local4 = &errno; +#if TLS_SUPPORTED + tcf_test_tls++; + tcf_test_tls2 += 2; +#endif tcf_test_func3(); func2_local1++; func2_local2 = func2_local1; @@ -227,21 +258,8 @@ char * tcf_test_array = array; } #endif -static void * test_sub(void * x) { - volatile int * test_done = (int *)x; - while (!*test_done) { - tcf_test_func0(enum_val3); - } - return NULL; -} - -void test_proc(void) { +static void test_start(void) { int i, j; - pthread_t thread[4]; - int test_done = 0; - for (i = 0; i < 4; i++) { - thread[i] = 0; - } for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) { tcf_test_array_field.buf[i][j] = (unsigned char)(i * 5 + j); @@ -253,6 +271,34 @@ void test_proc(void) { tcf_cpp_test_class_extension_var.f_int = 345; #endif tcf_test_func0(enum_val1); +} + +#ifdef PURE_RCBP_TEST + +void test_proc(void) { + int i; + test_start(); + for (i = 0; i < 9; i++) { + tcf_test_func0(enum_val2); + } +} + +#else + +static void * test_sub(void * x) { + volatile int * test_done = (int *)x; + while (!*test_done) { + tcf_test_func0(enum_val3); + } + return NULL; +} + +void test_proc(void) { + int i; + int test_done = 0; + pthread_t thread[4]; + for (i = 0; i < 4; i++) thread[i] = 0; + test_start(); for (i = 0; i < 4; i++) { if (pthread_create(thread + i, &pthread_create_attr, test_sub, &test_done) != 0) { perror("pthread_create"); @@ -269,9 +315,10 @@ void test_proc(void) { } int find_test_symbol(Context * ctx, const char * name, void ** addr, int * sym_class) { -#if ENABLE_TestSymbols /* This code allows to run TCF diagnostic tests when symbols info is not available */ *addr = NULL; + *sym_class = SYM_CLASS_UNKNOWN; +#if ENABLE_TestSymbols && !defined(ALT_RCBP_TEST) if (is_test_process(ctx) && strncmp(name, "tcf_test_", 9) == 0) { if (strcmp(name, "tcf_test_array") == 0) { *sym_class = SYM_CLASS_REFERENCE; @@ -360,7 +407,13 @@ int run_test_process(ContextAttachCallBack * done, void * data) { int fd = sysconf(_SC_OPEN_MAX); while (fd > 3) close(--fd); if (context_attach_self() < 0) exit(1); -#if defined(__linux__) && !ENABLE_TestSymbols +#if defined(ALT_RCBP_TEST) + { + char * fnm = canonicalize_file_name(ALT_RCBP_TEST); + if (fnm != NULL) execl(fnm, fnm, "-t", (char *)NULL); + exit(1); + } +#elif defined(__linux__) && !ENABLE_TestSymbols { char buf[32]; char * fnm = NULL; @@ -381,4 +434,6 @@ int run_test_process(ContextAttachCallBack * done, void * data) { #endif } +#endif /* PURE_RCBP_TEST */ + #endif /* ENABLE_RCBP_TEST */ diff --git a/agent/tcf/services/breakpoints.c b/agent/tcf/services/breakpoints.c index 59fee9b9..61a07131 100644 --- a/agent/tcf/services/breakpoints.c +++ b/agent/tcf/services/breakpoints.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2017 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; @@ -137,6 +139,7 @@ struct BreakInstruction { size_t saved_size; ErrorReport * planting_error; ErrorReport * address_error; + ErrorReport * ph_address_error; ErrorReport * condition_error; int stepping_over_bp; InstructionRef * refs; @@ -155,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 { @@ -169,6 +176,7 @@ struct ConditionEvaluationRequest { BreakInstruction * bi; int condition_ok; int triggered; + int canceled; }; struct LocationEvaluationRequest { @@ -281,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; } @@ -390,7 +400,8 @@ static void plant_instruction(BreakInstruction * bi) { } } else if (error == ERR_UNSUPPORTED) { - error = set_errno(ERR_OTHER, "Unsupported set of breakpoint attributes"); + if (bi->ph_address_error) error = set_error_report_errno(bi->ph_address_error); + else error = set_errno(ERR_OTHER, "Unsupported set of breakpoint attributes"); } rp = get_error_report(error); @@ -406,6 +417,7 @@ static void plant_instruction(BreakInstruction * bi) { release_error_report(rp); } bi->planted = bi->planting_error == NULL; + assert(bi->planted || !bi->dirty); if (bi->planted && !bi->virtual_addr) planted_sw_bp_cnt++; } @@ -513,9 +525,12 @@ static void free_instruction(BreakInstruction * bi) { list_remove(&bi->link_adr); context_unlock(bi->cb.ctx); release_error_report(bi->address_error); + release_error_report(bi->ph_address_error); 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); } @@ -550,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) { @@ -593,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 */ @@ -790,6 +808,7 @@ void invalidate_breakpoints_on_process_exec(Context * ctx) { if (bi->cb.ctx != mem) continue; if (!bi->virtual_addr) planted_sw_bp_cnt--; bi->planted = 0; + bi->dirty = 0; } } @@ -1035,6 +1054,7 @@ typedef struct LineOffsCheckArgs { char * file; } LineOffsCheckArgs; +#if ENABLE_LineNumbers static void line_offs_check(CodeArea * area, void * x) { LineOffsCheckArgs * args = (LineOffsCheckArgs *)x; assert(area->start_address <= args->bi->cb.address); @@ -1054,8 +1074,10 @@ static void line_offs_check(CodeArea * area, void * x) { args->line_offs_ok = strcmp(args->file, file) == 0; } } +#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; @@ -1074,6 +1096,7 @@ static void verify_line_offset(BreakInstruction * bi, InstructionRef * ref) { } } } +#endif } static void get_bp_opcodes(void) { @@ -1087,11 +1110,16 @@ static void get_bp_opcodes(void) { bi->bp_size = 0; bi->ph_ctx = NULL; bi->ph_addr = 0; + release_error_report(bi->ph_address_error); + bi->ph_address_error = 0; if (bi->ref_cnt > 0 && !bi->cb.ctx->exiting && !bi->cb.ctx->exited && (bi->cb.access_types & CTX_BP_ACCESS_INSTRUCTION) != 0) { Context * ph_ctx = NULL; ContextAddress ph_addr = 0; - if (context_get_canonical_addr(bi->cb.ctx, bi->cb.address, &ph_ctx, &ph_addr, NULL, NULL) == 0) { + if (context_get_canonical_addr(bi->cb.ctx, bi->cb.address, &ph_ctx, &ph_addr, NULL, NULL) < 0) { + bi->ph_address_error = get_error_report(errno); + } + else { #if ENABLE_ContextISA ContextISA isa; LINK * m = channel_root.next; @@ -1231,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) { @@ -1281,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) { @@ -1294,6 +1323,7 @@ static ConditionEvaluationRequest * add_condition_evaluation_request( c->bi = bi; c->condition_ok = 0; c->triggered = 0; + c->canceled = 0; return c; } @@ -1606,12 +1636,11 @@ static int skip_function_prologue(Context * ctx, Symbol * sym, ContextAddress * if (get_symbol_class(sym, &sym_class) < 0) return -1; if (sym_class != SYM_CLASS_FUNCTION) return 0; - if (get_symbol_size(sym, &sym_size) < 0) return -1; - if (sym_size == 0) return 0; + if (get_symbol_size(sym, &sym_size) < 0) sym_size = 0; memset(&area, 0, sizeof(area)); if (address_to_line(ctx, *addr, *addr + 1, function_prolog_line_info, &area) < 0) return -1; if (area.start_address > *addr || area.end_address <= *addr) return 0; - if (*addr + sym_size <= area.end_address) return 0; + if (sym_size != 0 && *addr + sym_size <= area.end_address) return 0; *addr = area.end_address; #endif return 0; @@ -1622,20 +1651,41 @@ 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; - SymbolProperties props; - 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; /* We want to add the LocalEntryOffset */ get_symbol_props(v.sym, &props); /* If the symbol is not a PPC64 function, offset should be 0, so it is safe to add */ addr += props.local_entry_offset; } +#endif +#endif #if ENABLE_SkipPrologueWhenPlanting /* Even if addr is incremented by local_entry_offset, we still should be on right code area */ if (!error && bp->skip_prologue && v.sym != NULL && skip_function_prologue(ctx, v.sym, &addr) < 0) error = errno; @@ -1643,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 @@ -1658,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) { @@ -1670,6 +1760,7 @@ static void plant_at_address_expression(Context * ctx, ContextAddress ip, Breakp while (v.sym_list[n] != NULL) { Symbol * sym = v.sym_list[n++]; if (get_symbol_address(sym, &addr) == 0) { + SymbolProperties props; /* We want to add the LocalEntryOffset */ get_symbol_props(sym, &props); /* If the symbol is not a PPC64 function, offset should be 0, so it is safe to add */ @@ -1774,7 +1865,7 @@ static int check_context_ids_condition(BreakpointInfo * bp, Context * ctx) { /* Check context IDs attribute and return 1 if the breakpoint should be triggered by 'ctx' */ assert(context_has_state(ctx)); if (bp->ctx != NULL) { - if (bp->ctx != ctx) return 0; + if (bp->ctx != ctx && bp->ctx != context_get_group(ctx, CONTEXT_GROUP_PROCESS)) return 0; } if (bp->context_ids != NULL) { int ok = 0; @@ -1821,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); @@ -1828,33 +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) { - 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; - } + if (check_context_ids_condition(bp, ctx)) condition_ok = 1; + if (condition_ok && bp->condition != NULL) { +#if ENABLE_Expressions + 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 { + int changed = 0; + if (bi->bit_size == 0) { + changed = memcmp(bi->bit_value, bi->bit_next, size) != 0; } - else if (b) { - ce->condition_ok = 1; + 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; } - else { - ce->condition_ok = 1; + } + 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); } @@ -1885,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; @@ -1985,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); @@ -2007,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; @@ -2019,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++; @@ -2940,7 +3052,7 @@ void evaluate_breakpoint(Context * ctx) { Context * grp = context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT); EvaluationRequest * req = create_evaluation_request(grp); int already_posted = !list_is_empty(&req->link_posted) || !list_is_empty(&req->link_active); - int need_to_post = already_posted; + int need_to_post = already_posted || cache_enter_cnt > 0; assert(context_has_state(ctx)); assert(ctx->stopped); @@ -2964,20 +3076,20 @@ void evaluate_breakpoint(Context * ctx) { else { bi = find_instruction(mem, 0, mem_addr, CTX_BP_ACCESS_INSTRUCTION, 1); } - if (bi != NULL && bi->planted) { - assert(bi->valid); + if (bi != NULL) { for (i = 0; i < bi->ref_cnt; i++) { if (bi->refs[i].ctx == grp) { BreakpointInfo * bp = bi->refs[i].bp; ConditionEvaluationRequest * c = add_condition_evaluation_request(req, ctx, bp, bi); if (c == NULL) continue; 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; } } @@ -2988,19 +3100,19 @@ void evaluate_breakpoint(Context * ctx) { assert(ctx->stopped_by_cb[0] != NULL); for (j = 0; ctx->stopped_by_cb[j]; j++) { BreakInstruction * bi = (BreakInstruction *)((char *)ctx->stopped_by_cb[j] - offsetof(BreakInstruction, cb)); - assert(bi->planted); for (i = 0; i < bi->ref_cnt; i++) { if (bi->refs[i].ctx == grp) { BreakpointInfo * bp = bi->refs[i].bp; ConditionEvaluationRequest * c = add_condition_evaluation_request(req, ctx, bp, bi); if (c == NULL) continue; 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; } } @@ -3199,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 @@ -3273,6 +3411,7 @@ static void event_code_unmapped(Context * ctx, ContextAddress addr, ContextAddre } if (!bi->virtual_addr) planted_sw_bp_cnt--; bi->planted = 0; + bi->dirty = 0; } addr += sz; size -= sz; @@ -3298,43 +3437,48 @@ static void channel_close_listener(Channel * c) { } void ini_breakpoints_service(Protocol * proto, TCFBroadcastGroup * bcg) { - int i; - broadcast_group = bcg; - - { - static ContextEventListener listener = { - event_context_created, - event_context_exited, - NULL, - NULL, - event_context_changed, - event_context_disposed - }; - add_context_event_listener(&listener, NULL); - } + static int ini_done = 0; + if (!ini_done) { + int i; + ini_done = 1; + { + static ContextEventListener listener = { + event_context_created, + event_context_exited, + NULL, + event_context_started, + event_context_changed, + event_context_disposed + }; + add_context_event_listener(&listener, NULL); + } #if SERVICE_MemoryMap - { - static MemoryMapEventListener listener = { - event_context_changed, - event_code_unmapped, - event_context_changed, - event_context_changed, - }; - add_memory_map_event_listener(&listener, NULL); - } + { + static MemoryMapEventListener listener = { + event_context_changed, + event_code_unmapped, + event_context_changed, + event_context_changed, + }; + add_memory_map_event_listener(&listener, NULL); + } #endif #if SERVICE_PathMap - { - static PathMapEventListener listener = { - event_path_map_changed, - }; - add_path_map_event_listener(&listener, NULL); - } + { + static PathMapEventListener listener = { + event_path_map_changed, + }; + add_path_map_event_listener(&listener, NULL); + } #endif - for (i = 0; i < ADDR2INSTR_HASH_SIZE; i++) list_init(addr2instr + i); - for (i = 0; i < ID2BP_HASH_SIZE; i++) list_init(id2bp + i); - for (i = 0; i < INP2BR_HASH_SIZE; i++) list_init(inp2br + i); - add_channel_close_listener(channel_close_listener); + for (i = 0; i < ADDR2INSTR_HASH_SIZE; i++) list_init(addr2instr + i); + for (i = 0; i < ID2BP_HASH_SIZE; i++) list_init(id2bp + i); + for (i = 0; i < INP2BR_HASH_SIZE; i++) list_init(inp2br + i); + add_channel_close_listener(channel_close_listener); + context_extension_offset = context_extension(sizeof(ContextExtensionBP)); + broadcast_group = bcg; + } + assert(broadcast_group == bcg); add_command_handler(proto, BREAKPOINTS, "set", command_set); add_command_handler(proto, BREAKPOINTS, "add", command_add); add_command_handler(proto, BREAKPOINTS, "change", command_change); @@ -3345,7 +3489,6 @@ void ini_breakpoints_service(Protocol * proto, TCFBroadcastGroup * bcg) { add_command_handler(proto, BREAKPOINTS, "getProperties", command_get_properties); add_command_handler(proto, BREAKPOINTS, "getStatus", command_get_status); add_command_handler(proto, BREAKPOINTS, "getCapabilities", command_get_capabilities); - context_extension_offset = context_extension(sizeof(ContextExtensionBP)); } #endif /* SERVICE_Breakpoints */ 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/contextreset.h b/agent/tcf/services/contextreset.h index 7b67336a..71c7f1dd 100644 --- a/agent/tcf/services/contextreset.h +++ b/agent/tcf/services/contextreset.h @@ -14,6 +14,7 @@ #include <tcf/config.h> #include <tcf/framework/protocol.h> +#include <tcf/framework/context.h> typedef struct ResetParameter ResetParameter; diff --git a/agent/tcf/services/disassembly.c b/agent/tcf/services/disassembly.c index b0085dbb..a9ee66c1 100644 --- a/agent/tcf/services/disassembly.c +++ b/agent/tcf/services/disassembly.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013-2018 Xilinx, Inc. and others. + * Copyright (c) 2013-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. @@ -24,6 +24,7 @@ #include <tcf/framework/exceptions.h> #include <tcf/framework/myalloc.h> #include <tcf/framework/cache.h> +#include <tcf/framework/trace.h> #include <tcf/services/runctrl.h> #include <tcf/services/symbols.h> #include <tcf/services/linenumbers.h> @@ -78,7 +79,7 @@ static DisassemblerInfo * find_disassembler_info(Context * ctx, const char * isa return NULL; } -static Disassembler * find_disassembler(Context * ctx, const char * isa) { +Disassembler * find_disassembler(Context * ctx, const char * isa) { DisassemblerInfo * i = find_disassembler_info(ctx, isa); return i ? i->disassembler : NULL; } @@ -147,7 +148,7 @@ static void command_get_capabilities(char * token, Channel * c) { cache_enter(command_get_capabilities_cache_client, c, &args, sizeof(args)); } -static int get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { +int get_disassembler_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { if (context_get_isa(ctx, addr, isa) < 0) { memset(isa, 0, sizeof(ContextISA)); return -1; @@ -206,7 +207,7 @@ static int disassemble_block(Context * ctx, OutputStream * out, uint8_t * mem_bu DisassemblyResult * dr = NULL; if (args->isa == NULL && (addr < isa->addr || (isa->addr + isa->size >= isa->addr && addr >= isa->addr + isa->size))) { - if (get_isa(ctx, addr, isa) < 0) return -1; + if (get_disassembler_isa(ctx, addr, isa) < 0) return -1; disassembler_ok = 0; } if (!disassembler_ok) { @@ -278,7 +279,7 @@ static int disassemble_block(Context * ctx, OutputStream * out, uint8_t * mem_bu return 0; } -#if SERVICE_LineNumbers +#if ENABLE_LineNumbers static void address_to_line_cb(CodeArea * area, void * args) { CodeArea ** p = (CodeArea **)args; if (*p == NULL || (*p)->start_address < area->start_address) { @@ -310,14 +311,26 @@ static void disassemble_cache_client(void * x) { if (ctx == NULL) error = ERR_INV_CONTEXT; else if (ctx->exited) error = ERR_ALREADY_EXITED; - if (!error) check_all_stopped(ctx); + trace(LOG_DISASM, "%s: ctx %s address 0x%16" PRIx64 " size %" PRId64 " ISA %s", + DISASSEMBLY, ctx->id, (uint64_t)args->addr, (uint64_t)args->size, + args->isa == NULL ? "(null)" : args->isa); + + if (!error) { + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + if ((mem->mem_access & MEM_ACCESS_RD_STOP) != 0) { + check_all_stopped(ctx); + } + if ((mem->mem_access & MEM_ACCESS_RD_RUNNING) == 0) { + if (!is_all_stopped(ctx)) error = set_errno(errno, "Cannot read memory if not stopped"); + } + } if (!error) { ContextAddress sym_addr = 0; ContextAddress sym_size = 0; int sym_addr_ok = 0; int sym_size_ok = 0; -#if SERVICE_Symbols +#if ENABLE_Symbols { Symbol * sym = NULL; if (find_symbol_by_addr(ctx, STACK_NO_FRAME, args->addr, &sym) == 0) { @@ -330,7 +343,7 @@ static void disassemble_cache_client(void * x) { } } #endif -#if SERVICE_LineNumbers +#if ENABLE_LineNumbers if (!sym_addr_ok || !sym_size_ok) { CodeArea * area = NULL; address_to_line(ctx, args->addr, args->addr + 1, address_to_line_cb, &area); @@ -343,7 +356,7 @@ static void disassemble_cache_client(void * x) { } #endif if (sym_addr_ok && sym_addr <= args->addr) { - if (get_isa(ctx, sym_addr, &isa) < 0) { + if (get_disassembler_isa(ctx, sym_addr, &isa) < 0) { error = errno; } else { @@ -359,7 +372,7 @@ static void disassemble_cache_client(void * x) { } else { /* Use default address alignment */ - if (get_isa(ctx, args->addr, &isa) < 0) { + if (get_disassembler_isa(ctx, args->addr, &isa) < 0) { error = errno; } else { @@ -403,7 +416,7 @@ static void disassemble_cache_client(void * x) { if (addr_error < buf_addr || args->addr < addr_error) break; buf_addr = addr_error; buf_size = args->addr + args->size - buf_addr; - if (get_isa(ctx, buf_addr, &isa) < 0) { + if (get_disassembler_isa(ctx, buf_addr, &isa) < 0) { error = errno; break; } @@ -413,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; } } @@ -452,6 +465,7 @@ static void disassemble_cache_client(void * x) { } loc_free(data); + run_ctrl_unlock(); } static void read_disassembly_params(InputStream * inp, const char * name, void * x) { @@ -467,7 +481,7 @@ static void read_disassembly_params(InputStream * inp, const char * name, void * args->pseudo_instr = json_read_boolean(inp); } else if (strcmp(name, "OpcodeValue") == 0) { - args->opcode_value =json_read_boolean(inp); + args->opcode_value = json_read_boolean(inp); } else { json_skip_object(inp); @@ -488,6 +502,7 @@ static void command_disassemble(char * token, Channel * c) { if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); cache_enter(disassemble_cache_client, c, &args, sizeof(DisassembleCmdArgs)); } diff --git a/agent/tcf/services/disassembly.h b/agent/tcf/services/disassembly.h index 50cb3374..212c81f5 100644 --- a/agent/tcf/services/disassembly.h +++ b/agent/tcf/services/disassembly.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013-2018 Xilinx, Inc. and others. + * Copyright (c) 2013-2019 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. @@ -19,6 +19,7 @@ #include <tcf/config.h> #include <tcf/framework/cpudefs.h> #include <tcf/framework/protocol.h> +#include <tcf/framework/context.h> typedef struct { const char * text; @@ -44,6 +45,10 @@ typedef DisassemblyResult * Disassembler(uint8_t * /* code */, ContextAddress /* extern void add_disassembler(Context * ctx, const char * isa, Disassembler disassembler); +extern Disassembler * find_disassembler(Context * ctx, const char * isa); + +extern int get_disassembler_isa(Context * ctx, ContextAddress addr, ContextISA * isa); + extern void ini_disassembly_service(Protocol * proto); #else /* SERVICE_Disassembly */ 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 5d28742c..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 */ @@ -433,6 +497,8 @@ #define OP_GNU_addr_index 0xfb #define OP_GNU_const_index 0xfc #define OP_GNU_variable_value 0xfd +/* Synopsis ASIP-specific extension */ +#define OP_address_class 0xfd /* TCF extensions */ #define OP_TCF_switch 0xfe #define OP_TCF_offset 0xff @@ -501,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 @@ -645,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 d81cd2f2..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; + } + 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; } - 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->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. @@ -2103,18 +2333,24 @@ static void add_state(CompUnit * unit, LineNumbersState * state) { add_state(unit, &s); } if (unit->mStatesCnt > 0) { + LineNumbersState * last = unit->mStates + unit->mStatesCnt - 1; /* Workaround: malformed gnu-8.1.0.0 line info when -gstatement-frontiers is used. * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=544359 + * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=544359 */ - LineNumbersState * last = unit->mStates + unit->mStatesCnt - 1; if (last->mAddress == state->mAddress && last->mSection == state->mSection && - last->mFile == state->mFile && last->mLine == state->mLine && last->mColumn == state->mColumn && + last->mFile == state->mFile && last->mLine == state->mLine && last->mColumn <= state->mColumn && (last->mFlags & ~(LINE_IsStmt | LINE_BasicBlock)) == state->mFlags) { last->mISA = state->mISA; last->mOpIndex = state->mOpIndex; last->mDiscriminator = state->mDiscriminator; return; } + /* Workaround: malformed CHESS Synopsys line info at the end of the info section */ + if (state->mLine == 0 && state->mAddress == 1 && state->mFlags == LINE_EndSequence) { + last->mFlags |= LINE_EndSequence; + return; + } } if (unit->mStatesCnt >= unit->mStatesMax) { unit->mStatesMax = unit->mStatesMax == 0 ? 128 : unit->mStatesMax * 2; @@ -2159,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[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[i] = s1; + 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; @@ -2208,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); @@ -2228,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]; @@ -2240,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(); @@ -2252,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()) { @@ -2311,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; } @@ -2368,7 +2713,7 @@ static void load_line_numbers_v2(CompUnit * Unit, U8_T unit_size, int dwarf64) { state.mAddress += (255 - opcode_base) / line_range * min_instruction_length; break; case DW_LNS_fixed_advance_pc: - state.mAddress += dio_ReadU2(); + state.mAddress += dio_ReadAddressX(NULL, 2); break; case DW_LNS_set_prologue_end: state.mFlags |= LINE_PrologueEnd; @@ -2391,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 9c42f64e..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; @@ -894,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: @@ -906,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: @@ -953,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(); @@ -990,7 +1020,6 @@ static void add_expression(DWARFExpressionInfo * info) { } break; case OP_bregx: - check_frame(); add(op); expr_pos++; copy_leb128(); @@ -1022,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(); @@ -1035,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(); @@ -1043,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++; { @@ -1089,6 +1126,7 @@ static void add_expression(DWARFExpressionInfo * info) { copy(size); } break; + case OP_regval_type: case OP_GNU_regval_type: expr_pos++; { @@ -1121,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++; { @@ -1137,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++; { @@ -1182,6 +1223,19 @@ static void add_expression(DWARFExpressionInfo * info) { } break; case OP_GNU_variable_value: + /* case OP_address_class: */ + 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 + * evaluated. Since AIE core has only one data memory, address class can be + * ignored. Add OP_drop, so that the integer arg is dropped from the stack + */ + add(OP_drop); + expr_pos++; + break; + } op_gnu_variable_value(); break; default: 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 5beb1920..2ddb2897 100644 --- a/agent/tcf/services/dwarfframe.c +++ b/agent/tcf/services/dwarfframe.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2017 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; } @@ -281,6 +281,38 @@ static RegisterRules * get_reg(StackFrameRegisters * regs, int reg) { regs->regs[n].offset = 30; /* LR */ } break; + case EM_RISCV: + min_reg_cnt = 28; + if (n == 0) { /* Always same - reads as zero */ + regs->regs[n].rule = RULE_SAME_VALUE; + } + else if ((n >= 8 && n <= 9) || (n >= 18 && n <= 27)) { /* Callee-saved registers */ + regs->regs[n].rule = RULE_SAME_VALUE; + } + else if (n == 2) { /* 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 = 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; @@ -892,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++) { @@ -1017,6 +1049,12 @@ static void generate_plt_section_commands(Context * ctx, ELF_File * file, U8_T o frame_regs.cfa_register = 31; /* SP */ generate_commands(); break; + case EM_RISCV: + rules.return_address_register = 1; /* RA */ + frame_regs.cfa_rule = RULE_OFFSET; + frame_regs.cfa_register = 2; /* SP */ + generate_commands(); + break; } } @@ -1033,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; @@ -1118,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; @@ -1204,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(); @@ -1225,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; @@ -1288,7 +1326,20 @@ static void read_frame_info_section(Context * ctx, ELF_Section * text_section, rules.reg_id_scope.id_type = rules.eh_frame ? REGNUM_EH_FRAME : REGNUM_DWARF; rules.cie_pos = ~(U8_T)0; - if (index->mFrameInfoRanges == NULL) create_search_index(cache, index); + if (index->mFrameInfoRanges == NULL) { + Trap trap; + if (set_trap(&trap)) { + create_search_index(cache, index); + clear_trap(&trap); + } + else { + loc_free(index->mFrameInfoRanges); + index->mFrameInfoRanges = NULL; + index->mFrameInfoRangesCnt = 0; + index->mFrameInfoRangesMax = 0; + exception(trap.error); + } + } l = 0; h = index->mFrameInfoRangesCnt; if (index->mRelocatable && text_section != NULL) sec_idx = text_section->index; diff --git a/agent/tcf/services/dwarfio.c b/agent/tcf/services/dwarfio.c index 96011acf..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,23 +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 ((Attr == AT_stmt_list || Attr == AT_ranges) && sSection->relocate) { - 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; @@ -476,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; @@ -489,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); } } @@ -529,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; @@ -536,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) { @@ -565,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; @@ -577,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); @@ -615,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; @@ -692,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) { @@ -731,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) { @@ -797,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"); @@ -811,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"); @@ -826,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); @@ -839,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/dwarfreloc.c b/agent/tcf/services/dwarfreloc.c index 47af0673..134fc6e2 100644 --- a/agent/tcf/services/dwarfreloc.c +++ b/agent/tcf/services/dwarfreloc.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2014 Wind River Systems, Inc. and others. + * Copyright (c) 2010-2019 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. @@ -149,12 +149,24 @@ static void relocate(void * r) { func->func(); } +static U4_T get_offs4(uint8_t * x) { + U4_T offs = *(U4_T *)x; + if (relocs->file->byte_swap) SWAP(offs); + if (section->file->type != ET_REL) offs -= (U4_T)section->addr; + return offs; +} + +static U8_T get_offs8(uint8_t * x) { + U8_T offs = *(U8_T *)x; + if (relocs->file->byte_swap) SWAP(offs); + if (section->file->type != ET_REL) offs -= section->addr; + return offs; +} + void drl_relocate_in_context(Context * c, ELF_Section * s, U8_T offset, void * buf, size_t size, ELF_Section ** dst, int * rt_addr) { ELF_Section * r = s->relocate; ELF_Section * d = NULL; - uint8_t * p; - uint8_t * q; unsigned ix; if (rt_addr) *rt_addr = 0; @@ -223,18 +235,15 @@ void drl_relocate_in_context(Context * c, ELF_Section * s, U8_T offset, } /* Perform a dichotomic look up for each ordered area */ - for (ix = 0; ix < r->reloc_num_zones; ix++) { - p = (uint8_t *)r->data + r->reloc_zones_bondaries[ix] * r->entsize; - q = (uint8_t *)r->data + r->reloc_zones_bondaries[ix + 1] * r->entsize; + uint8_t * p = (uint8_t *)r->data + r->reloc_zones_bondaries[ix] * r->entsize; + uint8_t * q = (uint8_t *)r->data + r->reloc_zones_bondaries[ix + 1] * r->entsize; while (p < q) { unsigned n = (q - p) / r->entsize / 2; uint8_t * x = p + n * r->entsize; assert(x < q); if (r->file->elf64) { - U8_T offs = *(U8_T *)x; - if (r->file->byte_swap) SWAP(offs); - if (s->file->type != ET_REL) offs -= s->addr; + U8_T offs = get_offs8(x); if (offset > offs) { p = x + r->entsize; continue; @@ -243,6 +252,30 @@ void drl_relocate_in_context(Context * c, ELF_Section * s, U8_T offset, q = x; continue; } + { + /* ELF can have multiple relocations at same offset */ + uint8_t * x0 = x; + uint8_t * x1 = x; + while (x0 > p) { + uint8_t * y = x0 - r->entsize; + U8_T z = get_offs8(y); + assert(z <= offs); + if (z != offs) break; + x0 = y; + } + while (x1 + r->entsize < q) { + uint8_t * y = x1 + r->entsize; + U8_T z = get_offs8(y); + assert(z >= offs); + if (z != offs) break; + x1 = y; + } + while (x0 <= x1) { + relocate(x0); + x0 += r->entsize; + } + } + return; } else { U4_T offs = *(U4_T *)x; @@ -256,9 +289,31 @@ void drl_relocate_in_context(Context * c, ELF_Section * s, U8_T offset, q = x; continue; } + { + /* ELF can have multiple relocations at same offset */ + uint8_t * x0 = x; + uint8_t * x1 = x; + while (x0 > p) { + uint8_t * y = x0 - r->entsize; + U4_T z = get_offs4(y); + assert(z <= offs); + if (z != offs) break; + x0 = y; + } + while (x1 + r->entsize < q) { + uint8_t * y = x1 + r->entsize; + U4_T z = get_offs4(y); + assert(z >= offs); + if (z != offs) break; + x1 = y; + } + while (x0 <= x1) { + relocate(x0); + x0 += r->entsize; + } + } + return; } - relocate(x); - return; } } } diff --git a/agent/tcf/services/elf-loader.c b/agent/tcf/services/elf-loader.c index 2d3bb7b8..a37e39d2 100644 --- a/agent/tcf/services/elf-loader.c +++ b/agent/tcf/services/elf-loader.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2013 Wind River Systems, Inc. and others. + * Copyright (c) 2011-2019 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. @@ -161,7 +161,13 @@ ContextAddress elf_get_debug_structure_address(Context * ctx, ELF_File ** file_p ContextAddress addr = 0; for (file = elf_list_first(ctx, 0, ~(ContextAddress)0); file != NULL; file = elf_list_next(ctx)) { - if (file->type != ET_EXEC) continue; + if (file->type != ET_EXEC) { + /* Check for PIE executable */ + ContextAddress flags = 0; + if (file->type != ET_DYN) continue; + if (get_dynamic_tag(ctx, file, DT_FLAGS_1, &flags) != 0) continue; + if ((flags & DF_1_PIE) == 0) continue; + } if (file_ptr != NULL) *file_ptr = file; #ifdef DT_MIPS_RLD_MAP if (get_dynamic_tag(ctx, file, DT_MIPS_RLD_MAP, &addr) == 0) { @@ -212,7 +218,7 @@ static void read_field(Context * ctx, const Symbol * sym, ContextAddress base, C #endif static ContextAddress find_module(Context * ctx, ELF_File * exe_file, ELF_File * module, - ContextAddress r_map, ContextAddress r_brk) { + ContextAddress r_map, ContextAddress r_brk, ContextAddress * tls_offs) { #if ENABLE_Symbols Symbol * sym = NULL; int i = 0, n = 0; @@ -221,6 +227,7 @@ static ContextAddress find_module(Context * ctx, ELF_File * exe_file, ELF_File * Symbol * sym_l_addr = NULL; Symbol * sym_l_next = NULL; Symbol * sym_l_tls_modid = NULL; + Symbol * sym_l_tls_offset = NULL; if (find_symbol_by_name(ctx, STACK_NO_FRAME, r_brk, "link_map", &sym) < 0) str_exception(errno, "Cannot find loader symbol: link_map"); if (get_symbol_children(sym, &children, &n) < 0) exception(errno); @@ -231,6 +238,7 @@ static ContextAddress find_module(Context * ctx, ELF_File * exe_file, ELF_File * if (strcmp(name, "l_map_start") == 0) sym_l_addr = children[i]; else if (strcmp(name, "l_next") == 0) sym_l_next = children[i]; else if (strcmp(name, "l_tls_modid") == 0) sym_l_tls_modid = children[i]; + else if (strcmp(name, "l_tls_offset") == 0) sym_l_tls_offset = children[i]; } if (sym_l_addr == NULL || sym_l_next == NULL || sym_l_tls_modid == NULL) str_exception(ERR_OTHER, "Invalid 'link_map' fields"); @@ -243,8 +251,10 @@ static ContextAddress find_module(Context * ctx, ELF_File * exe_file, ELF_File * read_field(ctx, sym_l_addr, link, &l_addr); elf_map_to_link_time_address(ctx, l_addr, 0, &link_file, NULL); if (link_file != NULL) { - if (link_file == module) return l_tls_modid; - if (get_dwarf_file(link_file) == module) return l_tls_modid; + if (link_file == module || get_dwarf_file(link_file) == module) { + if (sym_l_tls_offset != NULL) read_field(ctx, sym_l_tls_offset, link, tls_offs); + return l_tls_modid; + } } } read_field(ctx, sym_l_next, link, &link); @@ -253,7 +263,7 @@ static ContextAddress find_module(Context * ctx, ELF_File * exe_file, ELF_File * return 0; } -static ContextAddress get_module_id(Context * ctx, ELF_File * module) { +static ContextAddress get_module_id(Context * ctx, ELF_File * module, ContextAddress * tls_offs) { ELF_File * exe_file = NULL; ContextAddress addr = elf_get_debug_structure_address(ctx, &exe_file); size_t word_size = exe_file && exe_file->elf64 ? 8 : 4; @@ -266,7 +276,7 @@ static ContextAddress get_module_id(Context * ctx, ELF_File * module) { ContextAddress mod_id = 0; if (elf_read_memory_word(ctx, exe_file, addr + word_size * 1, &r_map) < 0) exception(errno); if (elf_read_memory_word(ctx, exe_file, addr + word_size * 2, &r_brk) < 0) exception(errno); - if (r_map != 0 && r_brk != 0) mod_id = find_module(ctx, exe_file, module, r_map, r_brk); + if (r_map != 0 && r_brk != 0) mod_id = find_module(ctx, exe_file, module, r_map, r_brk, tls_offs); clear_trap(&trap); if (mod_id) return mod_id; } @@ -278,8 +288,18 @@ static ContextAddress get_module_id(Context * ctx, ELF_File * module) { } ContextAddress get_tls_address(Context * ctx, ELF_File * file) { + + /* Note: handling TLS needs libc debug info on the target machine (apt install libc6-dbg) */ + + uint8_t buf[8]; ContextAddress mod_tls_addr = 0; RegisterIdScope reg_id_scope; + ContextAddress tcb_addr = 0; + ContextAddress tls_addr = 0; + ContextAddress dtv_addr = 0; /* Address of Dynamic Thread Vector */ + ContextAddress tls_offs = 0; + ContextAddress mod_id = get_module_id(ctx, file, &tls_offs); + RegisterDefinition * reg_def = NULL; memset(®_id_scope, 0, sizeof(reg_id_scope)); reg_id_scope.machine = file->machine; @@ -288,32 +308,73 @@ ContextAddress get_tls_address(Context * ctx, ELF_File * file) { reg_id_scope.big_endian = file->big_endian; reg_id_scope.id_type = REGNUM_DWARF; + /* Element type of the DTV: + typedef union { + size_t counter; + struct { + void * val; + void * to_free; + } pointer; + } dtv_t; + + val == (void *) -1l means allocation is delayed + */ + switch (file->machine) { + case EM_386: case EM_X86_64: - { - uint8_t buf[8]; - ContextAddress tcb_addr = 0; - ContextAddress vdt_addr = 0; - ContextAddress mod_id = 0; - RegisterDefinition * reg_def = get_reg_by_id(ctx, 58, ®_id_scope); - if (reg_def == NULL) exception(errno); - if (context_read_reg(ctx, reg_def, 0, reg_def->size, buf) < 0) - str_exception(errno, "Cannot read TCB base register"); - tcb_addr = to_address(buf, reg_def->size, reg_def->big_endian); - if (elf_read_memory_word(ctx, file, tcb_addr + 8, &vdt_addr) < 0) - str_exception(errno, "Cannot read TCB"); - mod_id = get_module_id(ctx, file); - if (elf_read_memory_word(ctx, file, vdt_addr + mod_id * 16, &mod_tls_addr) < 0) - str_exception(errno, "Cannot read VDT"); - if (mod_tls_addr == 0 || mod_tls_addr == ~(ContextAddress)0) - str_exception(errno, "Thread local storage is not allocated yet"); - } + reg_def = get_reg_by_id(ctx, 58, ®_id_scope); + if (reg_def == NULL) exception(errno); + if (context_read_reg(ctx, reg_def, 0, reg_def->size, buf) < 0) + str_exception(errno, "Cannot read TCB base register"); + tcb_addr = to_address(buf, reg_def->size, reg_def->big_endian); + if (elf_read_memory_word(ctx, file, tcb_addr + (file->elf64 ? 8 : 4), &dtv_addr) < 0) + str_exception(errno, "Cannot read TCB"); + break; + case EM_ARM: + case EM_AARCH64: + reg_def = get_reg_definitions(ctx); + if (reg_def == NULL) str_exception(ERR_OTHER, "TLS register not found"); + while (reg_def->name != NULL && strcmp(reg_def->name, "tls") != 0) reg_def++; + if (reg_def->name == NULL) str_exception(ERR_OTHER, "TLS register not found"); + if (context_read_reg(ctx, reg_def, 0, reg_def->size, buf) < 0) + str_exception(errno, "Cannot read TLS register"); + tls_addr = to_address(buf, reg_def->size, reg_def->big_endian); + if (elf_read_memory_word(ctx, file, tls_addr, &dtv_addr) < 0) + str_exception(errno, "Cannot read TLS"); + break; + case EM_RISCV: + reg_def = get_reg_by_id(ctx, 4, ®_id_scope); + if (reg_def == NULL) exception(errno); + if (context_read_reg(ctx, reg_def, 0, reg_def->size, buf) < 0) + str_exception(errno, "Cannot read TCB base register"); + tcb_addr = to_address(buf, reg_def->size, reg_def->big_endian); + if (elf_read_memory_word(ctx, file, tcb_addr - (file->elf64 ? 16 : 8), &dtv_addr) < 0) + str_exception(errno, "Cannot read TCB"); break; - default: + case EM_PPC: + case EM_PPC64: + reg_def = get_reg_by_id(ctx, (file->elf64 ? 13 : 2), ®_id_scope); + if (reg_def == NULL) exception(errno); + if (context_read_reg(ctx, reg_def, 0, reg_def->size, buf) < 0) + str_exception(errno, "Cannot read TCB base register"); + tcb_addr = to_address(buf, reg_def->size, reg_def->big_endian) - 0x7000; + if (elf_read_memory_word(ctx, file, tcb_addr - (file->elf64 ? 8 : 4), &dtv_addr) < 0) + str_exception(errno, "Cannot read TCB"); + break; + } + if (dtv_addr == 0) { str_fmt_exception(ERR_INV_CONTEXT, "Thread local storage access is not supported yet for machine type %d", file->machine); } + if (elf_read_memory_word(ctx, file, dtv_addr + mod_id * (file->elf64 ? 16 : 8), &mod_tls_addr) < 0) + str_exception(errno, "Cannot read DTV"); + if (mod_tls_addr == ~(ContextAddress)0 && tls_offs != 0 && tls_offs != ~(ContextAddress)0) { + mod_tls_addr = tcb_addr ? tcb_addr - tls_offs : tls_addr + tls_offs; + } + if (mod_tls_addr == 0 || mod_tls_addr == ~(ContextAddress)0) + str_exception(ERR_OTHER, "Thread local storage is not allocated yet"); return mod_tls_addr; } 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 5ac250fe..61561d20 100644 --- a/agent/tcf/services/expressions.c +++ b/agent/tcf/services/expressions.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2017 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. @@ -116,9 +116,6 @@ static int expression_has_func_call = 0; #ifndef ENABLE_FuncCallInjection # define ENABLE_FuncCallInjection (ENABLE_Symbols && SERVICE_RunControl && SERVICE_Breakpoints && ENABLE_DebugContext) #endif -#ifndef ENABLE_ExpressionSerialization -# define ENABLE_ExpressionSerialization ENABLE_SymbolsProxy -#endif #if ENABLE_FuncCallInjection typedef struct FuncCallState { @@ -172,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; @@ -182,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); @@ -205,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); } @@ -218,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); } @@ -256,14 +260,11 @@ static void set_string_value(Value * v, char * str) { static void error(int no, const char * fmt, ...) { va_list ap; - char buf[256]; - size_t l = 0; - + char * buf = NULL; va_start(ap, fmt); - l = snprintf(buf, sizeof(buf), "At col %d: ", sy_pos); - vsnprintf(buf + l, sizeof(buf) - l, fmt, ap); + buf = tmp_vprintf(fmt, ap); va_end(ap); - str_exception(no, buf); + str_fmt_exception(no, "At col %d: %s", sy_pos, buf); } #define next_ch_fast() { \ @@ -844,8 +845,8 @@ static void reg2value(int mode, Context * ctx, int frame, RegisterDefinition * d if (frame != STACK_NO_FRAME) str_exception(ERR_INV_CONTEXT, "Invalid stack frame ID"); if (context_read_reg(ctx, def, 0, def->size, v->value) < 0) exception(errno); } - else if (!ctx->stopped && (ctx->reg_access & REG_ACCESS_RD_RUNNING) == 0) { - str_exception(ERR_IS_RUNNING, "Cannot read CPU register"); + else if ((ctx->reg_access & REG_ACCESS_RD_RUNNING) == 0 && !is_ctx_stopped(ctx)) { + str_exception(errno, "Cannot read CPU register"); } else if (frame == STACK_TOP_FRAME || frame == STACK_NO_FRAME) { if (context_read_reg(ctx, def, 0, def->size, v->value) < 0) exception(errno); @@ -1081,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; } @@ -1099,7 +1105,9 @@ static int sym2value(int mode, Symbol * sym, Value * v) { { ContextAddress word = 0; v->type_class = TYPE_CLASS_POINTER; - if (v->type != NULL) get_array_symbol(v->type, 0, &v->type); + if (v->type != NULL && get_array_symbol(v->type, 0, &v->type)) { + error(errno, "Cannot get function type"); + } if (mode == MODE_NORMAL && get_symbol_address(sym, &word) < 0) { error(errno, "Cannot retrieve symbol address"); } @@ -1126,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; } @@ -1171,6 +1184,81 @@ static unsigned flag_count(SYM_FLAGS flags) { } #endif /* ENABLE_Symbols */ +static void expression(int mode, Value * v); +static uint64_t to_uns(int mode, Value * v); +static void load_value(Value * v); + +static int builtin_identifier(int mode, char * name, Value * v) { + Context * ctx = expression_context; + for (;;) { + RegisterDefinition * def = get_reg_definitions(ctx); + if (def != NULL) { + while (def->name != NULL) { + if (strcmp(name + 1, def->name) == 0) { + int frame = STACK_NO_FRAME; + if (ctx == expression_context) frame = expression_frame; + reg2value(mode, ctx, frame, def, v); + return SYM_CLASS_REFERENCE; + } + def++; + } + } + ctx = ctx->parent; + if (ctx == NULL) break; + } + if (strcmp(name, "$thread") == 0) { + set_string_value(v, expression_context->id); + v->constant = 1; + return SYM_CLASS_VALUE; + } +#if ENABLE_Symbols + if (strcmp(name, "$relocate") == 0 && text_sy == '(') { + unsigned cnt; + uint64_t addr = 0; + const char * file_name = ""; + const char * sect_name = ""; + Symbol * sym = NULL; + next_sy(); + for (cnt = 0;; cnt++) { + switch (cnt) { + case 0: + expression(mode, v); + addr = to_uns(mode, v); + break; + case 1: + expression(mode, v); + load_value(v); + file_name = tmp_strndup((char *)v->value, (size_t)v->size); + break; + case 2: + expression(mode, v); + load_value(v); + sect_name = tmp_strndup((char *)v->value, (size_t)v->size); + break; + default: + error(ERR_INV_EXPRESSION, "Too many arguments"); + } + if (text_sy != ',') break; + next_sy(); + } + if (text_sy != ')') error(ERR_INV_EXPRESSION, "Missing ')'"); + next_sy(); + ini_value(v); + if (mode != MODE_NORMAL) { + set_ctx_word_value(v, (ContextAddress)addr); + v->type_class = TYPE_CLASS_POINTER; + return SYM_CLASS_VALUE; + } + if (find_symbol_by_name(expression_context, STACK_NO_FRAME, 0, + tmp_printf("$relocate:%s:%s:%" PRIX64, file_name, sect_name, addr), &sym) < 0) { + error(errno, "Cannot read symbol data"); + } + return sym2value(mode, sym, v); + } +#endif + return -1; +} + static int identifier(int mode, Value * scope, char * name, SYM_FLAGS flags, Value * v) { ini_value(v); if (scope == NULL) { @@ -1182,28 +1270,8 @@ static int identifier(int mode, Value * scope, char * name, SYM_FLAGS flags, Val exception(ERR_INV_CONTEXT); } if (name[0] == '$') { - Context * ctx = expression_context; - for (;;) { - RegisterDefinition * def = get_reg_definitions(ctx); - if (def != NULL) { - while (def->name != NULL) { - if (strcmp(name + 1, def->name) == 0) { - int frame = STACK_NO_FRAME; - if (ctx == expression_context) frame = expression_frame; - reg2value(mode, ctx, frame, def, v); - return SYM_CLASS_REFERENCE; - } - def++; - } - } - ctx = ctx->parent; - if (ctx == NULL) break; - } - } - if (strcmp(name, "$thread") == 0) { - set_string_value(v, expression_context->id); - v->constant = 1; - return SYM_CLASS_VALUE; + int id_class = builtin_identifier(mode, name, v); + if (id_class >= 0) return id_class; } } #if ENABLE_Symbols @@ -1291,8 +1359,20 @@ static int identifier(int mode, Value * scope, char * name, SYM_FLAGS flags, Val return -1; } +#ifndef NDEBUG +/* Check for bad recursion */ +static int indentifier_checked(int mode, Value * scope, char * name, SYM_FLAGS flags, Value * v) { + int text_pos_org = text_pos; + int text_sy_org = text_sy; + int res = identifier(mode, scope, name, flags, v); + assert(text_pos_org == text_pos); + assert(text_sy_org == text_sy); + return res; +} +#define identifier(mode, scope, name, flags, v) indentifier_checked(mode, scope, name, flags, v) +#endif + static int qualified_name(int mode, Value * scope, SYM_FLAGS flags, Value * v) { - Value x; int sym_class = 0; for (;;) { ini_value(v); @@ -1349,8 +1429,7 @@ static int qualified_name(int mode, Value * scope, SYM_FLAGS flags, Value * v) { } if (text_sy != SY_SCOPE) break; next_sy(); - scope = &x; - x = *v; + *(scope = (Value *)tmp_alloc(sizeof(Value))) = *v; } return sym_class; } @@ -1405,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) { @@ -1448,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); @@ -1559,8 +1636,13 @@ static void load_value(Value * v) { if (v->remote) { size_t size = (size_t)v->size; void * buf = tmp_alloc(size); + Context * ctx = expression_context; + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); assert(!v->constant); - if (context_read_mem(expression_context, v->address, buf, size) < 0) { + if ((mem->mem_access & MEM_ACCESS_RD_RUNNING) == 0) { + if (!is_all_stopped(ctx)) error(errno, "Cannot read memory if not stopped"); + } + if (context_read_mem(ctx, v->address, buf, size) < 0) { error(errno, "Can't read variable value"); } v->value = buf; @@ -1569,6 +1651,7 @@ static void load_value(Value * v) { else if (v->value != NULL) { /* OK */ } +#if ENABLE_Symbols else if (v->loc != NULL) { size_t size = 0; void * value = NULL; @@ -1579,6 +1662,7 @@ static void load_value(Value * v) { v->size = (ContextAddress)size; sign_extend(v, loc); } +#endif else { error(ERR_OTHER, "Has no value"); } @@ -1697,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; @@ -1748,6 +1832,16 @@ static uint64_t to_uns_fixed_point(int mode, Value * v) { } } } + if (v->type_class == TYPE_CLASS_UNKNOWN) { + load_value(v); + to_host_endianness(v); + switch (v->size) { + case 1: return *(uint8_t *)v->value; + case 2: return *(uint16_t *)v->value; + case 4: return *(uint32_t *)v->value; + case 8: return *(uint64_t *)v->value; + } + } error(ERR_INV_EXPRESSION, "Operation is not applicable for the value type"); return 0; @@ -2012,8 +2106,6 @@ static void set_complex_type(Value * v) { #endif } -static void expression(int mode, Value * v); - static void primary_expression(int mode, Value * v) { if (text_sy == '(') { next_sy(); @@ -2026,7 +2118,9 @@ static void primary_expression(int mode, Value * v) { next_sy(); } else if (text_sy == SY_VAL) { +#if ENABLE_Symbols int flags = text_val_flags; +#endif *v = text_val; next_sy(); #if ENABLE_Symbols @@ -2099,7 +2193,7 @@ static void primary_expression(int mode, Value * v) { } else if (v->type_class == TYPE_CLASS_ARRAY && (flags & VAL_FLAG_S) != 0) { if (text_sy == SY_SCOPE) { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); char * name = NULL; if (flags & VAL_FLAG_L) { unsigned i = 0; @@ -2128,10 +2222,10 @@ static void primary_expression(int mode, Value * v) { else { name = (char *)v->value; } - if (identifier(mode, NULL, name, 0, &x) < 0) + if (identifier(mode, NULL, name, 0, x) < 0) error(ERR_INV_EXPRESSION, "Undefined identifier '%s'", name); next_sy(); - qualified_name_expression(mode, &x, v); + qualified_name_expression(mode, x, v); } else { size_t size = 0; @@ -2158,10 +2252,8 @@ static void primary_expression(int mode, Value * v) { #endif } else if (text_sy == SY_SCOPE) { - Value x; next_sy(); - memset(&x, 0, sizeof(x)); - qualified_name_expression(mode, &x, v); + qualified_name_expression(mode, (Value *)tmp_alloc_zero(sizeof(Value)), v); } else if (text_sy == SY_NAME || text_sy == SY_ID) { qualified_name_expression(mode, NULL, v); @@ -2229,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) { @@ -2310,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) { @@ -2341,12 +2428,25 @@ static void op_field(int mode, Value * v) { addr = (ContextAddress)loc->stk[0]; } v->type_class = TYPE_CLASS_POINTER; - if (v->type != NULL) get_array_symbol(v->type, 0, &v->type); + if (v->type != NULL && get_array_symbol(v->type, 0, &v->type)) { + error(errno, "Cannot get function type"); + } set_ctx_word_value(v, addr); v->function = 1; 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"); } @@ -2354,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]; @@ -2376,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; @@ -2537,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); @@ -2568,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); @@ -3151,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; @@ -3271,11 +3390,11 @@ static void pm_expression(int mode, Value * v) { unary_expression(mode, v); #if ENABLE_Symbols while (text_sy == SY_PM_D || text_sy == SY_PM_R) { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int sy = text_sy; next_sy(); - unary_expression(mode, &x); - if (x.type == NULL || x.type_class != TYPE_CLASS_MEMBER_PTR) { + unary_expression(mode, x); + if (x->type == NULL || x->type_class != TYPE_CLASS_MEMBER_PTR) { error(ERR_INV_EXPRESSION, "Invalid type: pointer to member expected"); } if (mode != MODE_SKIP) { @@ -3290,8 +3409,8 @@ static void pm_expression(int mode, Value * v) { else { obj = (ContextAddress)to_uns(mode, v); } - ptr = (ContextAddress)to_uns(mode, &x); - evaluate_symbol_location(x.type, obj, ptr, &loc, NULL); + ptr = (ContextAddress)to_uns(mode, x); + evaluate_symbol_location(x->type, obj, ptr, &loc, NULL); if (loc->stk_pos != 1) error(ERR_INV_EXPRESSION, "Cannot evaluate symbol address"); v->address = (ContextAddress)loc->stk[0]; } @@ -3308,7 +3427,7 @@ static void pm_expression(int mode, Value * v) { v->field_cb = NULL; v->value = NULL; v->constant = 0; - if (get_symbol_base_type(x.type, &v->type) < 0) { + if (get_symbol_base_type(x->type, &v->type) < 0) { error(ERR_INV_EXPRESSION, "Cannot get pointed type"); } if (get_symbol_type_class(v->type, &v->type_class) < 0) { @@ -3317,7 +3436,7 @@ static void pm_expression(int mode, Value * v) { if (get_symbol_size(v->type, &v->size) < 0) { error(errno, "Cannot retrieve field size"); } - set_value_endianness(v, x.type, v->type); + set_value_endianness(v, x->type, v->type); } } #endif @@ -3326,15 +3445,15 @@ static void pm_expression(int mode, Value * v) { static void multiplicative_expression(int mode, Value * v) { pm_expression(mode, v); while (text_sy == '*' || text_sy == '/' || text_sy == '%') { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int sy = text_sy; next_sy(); - pm_expression(mode, &x); + pm_expression(mode, x); if (mode != MODE_SKIP) { - if (!is_number(v) || !is_number(&x)) { + if (!is_number(v) || !is_number(x)) { error(ERR_INV_EXPRESSION, "Numeric types expected"); } - else if (v->type_class == TYPE_CLASS_COMPLEX || x.type_class == TYPE_CLASS_COMPLEX) { + else if (v->type_class == TYPE_CLASS_COMPLEX || x->type_class == TYPE_CLASS_COMPLEX) { double r_value = 0; double i_value = 0; if (mode == MODE_NORMAL) { @@ -3342,22 +3461,22 @@ static void multiplicative_expression(int mode, Value * v) { switch (sy) { case '*': r_value = - to_r_double(mode, v) * to_r_double(mode, &x) - - to_i_double(mode, v) * to_i_double(mode, &x); + to_r_double(mode, v) * to_r_double(mode, x) - + to_i_double(mode, v) * to_i_double(mode, x); i_value = - to_r_double(mode, v) * to_i_double(mode, &x) + - to_i_double(mode, v) * to_r_double(mode, &x); + to_r_double(mode, v) * to_i_double(mode, x) + + to_i_double(mode, v) * to_r_double(mode, x); break; case '/': d = - to_r_double(mode, &x) * to_r_double(mode, &x) + - to_i_double(mode, &x) * to_i_double(mode, &x); + to_r_double(mode, x) * to_r_double(mode, x) + + to_i_double(mode, x) * to_i_double(mode, x); r_value = - (to_r_double(mode, v) * to_r_double(mode, &x) + - to_i_double(mode, v) * to_i_double(mode, &x)) / d; + (to_r_double(mode, v) * to_r_double(mode, x) + + to_i_double(mode, v) * to_i_double(mode, x)) / d; i_value = - (to_i_double(mode, v) * to_r_double(mode, &x) - - to_r_double(mode, v) * to_i_double(mode, &x)) / d; + (to_i_double(mode, v) * to_r_double(mode, x) - + to_r_double(mode, v) * to_i_double(mode, x)) / d; break; default: error(ERR_INV_EXPRESSION, "Invalid type"); @@ -3368,12 +3487,12 @@ static void multiplicative_expression(int mode, Value * v) { set_complex_value(v, sizeof(double) * 2, r_value, i_value); set_complex_type(v); } - else if (is_real_number(v) || is_real_number(&x)) { + else if (is_real_number(v) || is_real_number(x)) { double value = 0; if (mode == MODE_NORMAL) { switch (sy) { - case '*': value = to_double(mode, v) * to_double(mode, &x); break; - case '/': value = to_double(mode, v) / to_double(mode, &x); break; + case '*': value = to_double(mode, v) * to_double(mode, x); break; + case '/': value = to_double(mode, v) / to_double(mode, x); break; default: error(ERR_INV_EXPRESSION, "Invalid type"); } } @@ -3382,11 +3501,11 @@ static void multiplicative_expression(int mode, Value * v) { set_fp_value(v, sizeof(double), value); set_fp_type(v); } - else if (v->type_class == TYPE_CLASS_CARDINAL || x.type_class == TYPE_CLASS_CARDINAL) { + else if (v->type_class == TYPE_CLASS_CARDINAL || x->type_class == TYPE_CLASS_CARDINAL) { uint64_t value = 0; if (mode == MODE_NORMAL) { uint64_t a = to_uns(mode, v); - uint64_t b = to_uns(mode, &x); + uint64_t b = to_uns(mode, x); if (sy != '*' && b == 0) error(ERR_INV_EXPRESSION, "Dividing by zero"); switch (sy) { case '*': value = a * b; break; @@ -3402,7 +3521,7 @@ static void multiplicative_expression(int mode, Value * v) { int64_t value = 0; if (mode == MODE_NORMAL) { int64_t a = to_int(mode, v); - int64_t b = to_int(mode, &x); + int64_t b = to_int(mode, x); if (sy != '*' && b == 0) error(ERR_INV_EXPRESSION, "Dividing by zero"); switch (sy) { case '*': value = a * b; break; @@ -3414,7 +3533,7 @@ static void multiplicative_expression(int mode, Value * v) { v->type_class = TYPE_CLASS_INTEGER; set_int_value(v, sizeof(int64_t), value); } - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; } } } @@ -3422,20 +3541,20 @@ static void multiplicative_expression(int mode, Value * v) { static void additive_expression(int mode, Value * v) { multiplicative_expression(mode, v); while (text_sy == '+' || text_sy == '-') { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int sy = text_sy; next_sy(); - multiplicative_expression(mode, &x); + multiplicative_expression(mode, x); if (mode != MODE_SKIP) { if (v->function) { v->type_class = TYPE_CLASS_CARDINAL; v->type = NULL; } - if (x.function) { - x.type_class = TYPE_CLASS_CARDINAL; - x.type = NULL; + if (x->function) { + x->type_class = TYPE_CLASS_CARDINAL; + x->type = NULL; } - if (sy == '+' && v->type_class == TYPE_CLASS_ARRAY && x.type_class == TYPE_CLASS_ARRAY) { + if (sy == '+' && v->type_class == TYPE_CLASS_ARRAY && x->type_class == TYPE_CLASS_ARRAY) { if (mode == MODE_TYPE) { v->remote = 0; v->size = 0; @@ -3444,17 +3563,17 @@ static void additive_expression(int mode, Value * v) { else { char * value; load_value(v); - load_value(&x); - v->size = strlen((char *)v->value) + strlen((char *)x.value) + 1; + load_value(x); + v->size = strlen((char *)v->value) + strlen((char *)x->value) + 1; value = (char *)tmp_alloc((size_t)v->size); strcpy(value, (const char *)(v->value)); - strcat(value, (const char *)(x.value)); + strcat(value, (const char *)(x->value)); v->value = value; } v->type = NULL; } #if ENABLE_Symbols - else if ((v->type_class == TYPE_CLASS_POINTER || v->type_class == TYPE_CLASS_ARRAY) && is_number(&x)) { + else if ((v->type_class == TYPE_CLASS_POINTER || v->type_class == TYPE_CLASS_ARRAY) && is_number(x)) { uint64_t value = 0; Symbol * base = NULL; ContextAddress size = 0; @@ -3463,8 +3582,8 @@ static void additive_expression(int mode, Value * v) { error(ERR_INV_EXPRESSION, "Unknown pointer base type size"); } switch (sy) { - case '+': value = to_uns(mode, v) + to_uns(mode, &x) * size; break; - case '-': value = to_uns(mode, v) - to_uns(mode, &x) * size; break; + case '+': value = to_uns(mode, v) + to_uns(mode, x) * size; break; + case '-': value = to_uns(mode, v) - to_uns(mode, x) * size; break; } if (v->type_class == TYPE_CLASS_ARRAY) { if (get_array_symbol(base, 0, &v->type) < 0 || @@ -3475,40 +3594,40 @@ static void additive_expression(int mode, Value * v) { } set_int_value(v, (size_t)v->size, value); } - else if (is_number(v) && (x.type_class == TYPE_CLASS_POINTER || x.type_class == TYPE_CLASS_ARRAY) && sy == '+') { + else if (is_number(v) && (x->type_class == TYPE_CLASS_POINTER || x->type_class == TYPE_CLASS_ARRAY) && sy == '+') { uint64_t value = 0; Symbol * base = NULL; ContextAddress size = 0; - if (x.type == NULL || get_symbol_base_type(x.type, &base) < 0 || + if (x->type == NULL || get_symbol_base_type(x->type, &base) < 0 || base == NULL || get_symbol_size(base, &size) < 0 || size == 0) { error(ERR_INV_EXPRESSION, "Unknown pointer base type size"); } - value = to_uns(mode, &x) + to_uns(mode, v) * size; - v->type = x.type; - if (x.type_class == TYPE_CLASS_ARRAY) { + value = to_uns(mode, x) + to_uns(mode, v) * size; + v->type = x->type; + if (x->type_class == TYPE_CLASS_ARRAY) { if (get_array_symbol(base, 0, &v->type) < 0 || get_symbol_size(v->type, &v->size) < 0) { error(errno, "Cannot cast to pointer"); } } v->type_class = TYPE_CLASS_POINTER; - set_int_value(v, (size_t)x.size, value); + set_int_value(v, (size_t)x->size, value); } #endif - else if (!is_number(v) || !is_number(&x)) { + else if (!is_number(v) || !is_number(x)) { error(ERR_INV_EXPRESSION, "Numeric types expected"); } - else if (v->type_class == TYPE_CLASS_COMPLEX || x.type_class == TYPE_CLASS_COMPLEX) { + else if (v->type_class == TYPE_CLASS_COMPLEX || x->type_class == TYPE_CLASS_COMPLEX) { double r_value = 0; double i_value = 0; switch (sy) { case '+': - r_value = to_r_double(mode, v) + to_r_double(mode, &x); - i_value = to_i_double(mode, v) + to_i_double(mode, &x); + r_value = to_r_double(mode, v) + to_r_double(mode, x); + i_value = to_i_double(mode, v) + to_i_double(mode, x); break; case '-': - r_value = to_r_double(mode, v) - to_r_double(mode, &x); - i_value = to_i_double(mode, v) - to_i_double(mode, &x); + r_value = to_r_double(mode, v) - to_r_double(mode, x); + i_value = to_i_double(mode, v) - to_i_double(mode, x); break; } v->type = NULL; @@ -3516,22 +3635,22 @@ static void additive_expression(int mode, Value * v) { set_complex_value(v, sizeof(double) * 2, r_value, i_value); set_complex_type(v); } - else if (is_real_number(v) || is_real_number(&x)) { + else if (is_real_number(v) || is_real_number(x)) { double value = 0; switch (sy) { - case '+': value = to_double(mode, v) + to_double(mode, &x); break; - case '-': value = to_double(mode, v) - to_double(mode, &x); break; + case '+': value = to_double(mode, v) + to_double(mode, x); break; + case '-': value = to_double(mode, v) - to_double(mode, x); break; } v->type = NULL; v->type_class = TYPE_CLASS_REAL; set_fp_value(v, sizeof(double), value); set_fp_type(v); } - else if (v->type_class == TYPE_CLASS_CARDINAL || x.type_class == TYPE_CLASS_CARDINAL) { + else if (v->type_class == TYPE_CLASS_CARDINAL || x->type_class == TYPE_CLASS_CARDINAL) { uint64_t value = 0; switch (sy) { - case '+': value = to_uns(mode, v) + to_uns(mode, &x); break; - case '-': value = to_uns(mode, v) - to_uns(mode, &x); break; + case '+': value = to_uns(mode, v) + to_uns(mode, x); break; + case '-': value = to_uns(mode, v) - to_uns(mode, x); break; } v->type = NULL; v->type_class = TYPE_CLASS_CARDINAL; @@ -3540,14 +3659,14 @@ static void additive_expression(int mode, Value * v) { else { int64_t value = 0; switch (sy) { - case '+': value = to_int(mode, v) + to_int(mode, &x); break; - case '-': value = to_int(mode, v) - to_int(mode, &x); break; + case '+': value = to_int(mode, v) + to_int(mode, x); break; + case '-': value = to_int(mode, v) - to_int(mode, x); break; } v->type = NULL; v->type_class = TYPE_CLASS_INTEGER; set_int_value(v, sizeof(int64_t), value); } - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; } } } @@ -3555,26 +3674,26 @@ static void additive_expression(int mode, Value * v) { static void shift_expression(int mode, Value * v) { additive_expression(mode, v); while (text_sy == SY_SHL || text_sy == SY_SHR) { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int sy = text_sy; next_sy(); - additive_expression(mode, &x); + additive_expression(mode, x); if (mode != MODE_SKIP) { uint64_t value = 0; - if (!is_whole_number(v) || !is_whole_number(&x)) { + if (!is_whole_number(v) || !is_whole_number(x)) { error(ERR_INV_EXPRESSION, "Integral types expected"); } - if (x.type_class != TYPE_CLASS_CARDINAL && to_int(mode, &x) < 0) { + if (x->type_class != TYPE_CLASS_CARDINAL && to_int(mode, x) < 0) { if (v->type_class == TYPE_CLASS_CARDINAL) { switch (sy) { - case SY_SHL: value = to_uns(mode, v) >> -to_int(mode, &x); break; - case SY_SHR: value = to_uns(mode, v) << -to_int(mode, &x); break; + case SY_SHL: value = to_uns(mode, v) >> -to_int(mode, x); break; + case SY_SHR: value = to_uns(mode, v) << -to_int(mode, x); break; } } else { switch (sy) { - case SY_SHL: value = to_int(mode, v) >> -to_int(mode, &x); break; - case SY_SHR: value = to_int(mode, v) << -to_int(mode, &x); break; + case SY_SHL: value = to_int(mode, v) >> -to_int(mode, x); break; + case SY_SHR: value = to_int(mode, v) << -to_int(mode, x); break; } v->type_class = TYPE_CLASS_INTEGER; } @@ -3582,20 +3701,20 @@ static void shift_expression(int mode, Value * v) { else { if (v->type_class == TYPE_CLASS_CARDINAL) { switch (sy) { - case SY_SHL: value = to_uns(mode, v) << to_uns(mode, &x); break; - case SY_SHR: value = to_uns(mode, v) >> to_uns(mode, &x); break; + case SY_SHL: value = to_uns(mode, v) << to_uns(mode, x); break; + case SY_SHR: value = to_uns(mode, v) >> to_uns(mode, x); break; } } else { switch (sy) { - case SY_SHL: value = to_int(mode, v) << to_uns(mode, &x); break; - case SY_SHR: value = to_int(mode, v) >> to_uns(mode, &x); break; + case SY_SHL: value = to_int(mode, v) << to_uns(mode, x); break; + case SY_SHR: value = to_int(mode, v) >> to_uns(mode, x); break; } v->type_class = TYPE_CLASS_INTEGER; } } v->type = NULL; - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; set_int_value(v, sizeof(uint64_t), value); } } @@ -3604,17 +3723,17 @@ static void shift_expression(int mode, Value * v) { static void relational_expression(int mode, Value * v) { shift_expression(mode, v); while (text_sy == '<' || text_sy == '>' || text_sy == SY_LEQ || text_sy == SY_GEQ) { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int sy = text_sy; next_sy(); - shift_expression(mode, &x); + shift_expression(mode, x); if (mode != MODE_SKIP) { uint32_t value = 0; - if (v->type_class == TYPE_CLASS_ARRAY && x.type_class == TYPE_CLASS_ARRAY) { + if (v->type_class == TYPE_CLASS_ARRAY && x->type_class == TYPE_CLASS_ARRAY) { int n = 0; load_value(v); - load_value(&x); - n = strcmp((char *)v->value, (char *)x.value); + load_value(x); + n = strcmp((char *)v->value, (char *)x->value); switch (sy) { case '<': value = n < 0; break; case '>': value = n > 0; break; @@ -3622,32 +3741,32 @@ static void relational_expression(int mode, Value * v) { case SY_GEQ: value = n >= 0; break; } } - else if (is_real_number(v) || is_real_number(&x)) { + else if (is_real_number(v) || is_real_number(x)) { switch (sy) { - case '<': value = to_double(mode, v) < to_double(mode, &x); break; - case '>': value = to_double(mode, v) > to_double(mode, &x); break; - case SY_LEQ: value = to_double(mode, v) <= to_double(mode, &x); break; - case SY_GEQ: value = to_double(mode, v) >= to_double(mode, &x); break; + case '<': value = to_double(mode, v) < to_double(mode, x); break; + case '>': value = to_double(mode, v) > to_double(mode, x); break; + case SY_LEQ: value = to_double(mode, v) <= to_double(mode, x); break; + case SY_GEQ: value = to_double(mode, v) >= to_double(mode, x); break; } } - else if (v->type_class == TYPE_CLASS_CARDINAL || x.type_class == TYPE_CLASS_CARDINAL) { + else if (v->type_class == TYPE_CLASS_CARDINAL || x->type_class == TYPE_CLASS_CARDINAL) { switch (sy) { - case '<': value = to_uns(mode, v) < to_uns(mode, &x); break; - case '>': value = to_uns(mode, v) > to_uns(mode, &x); break; - case SY_LEQ: value = to_uns(mode, v) <= to_uns(mode, &x); break; - case SY_GEQ: value = to_uns(mode, v) >= to_uns(mode, &x); break; + case '<': value = to_uns(mode, v) < to_uns(mode, x); break; + case '>': value = to_uns(mode, v) > to_uns(mode, x); break; + case SY_LEQ: value = to_uns(mode, v) <= to_uns(mode, x); break; + case SY_GEQ: value = to_uns(mode, v) >= to_uns(mode, x); break; } } else { switch (sy) { - case '<': value = to_int(mode, v) < to_int(mode, &x); break; - case '>': value = to_int(mode, v) > to_int(mode, &x); break; - case SY_LEQ: value = to_int(mode, v) <= to_int(mode, &x); break; - case SY_GEQ: value = to_int(mode, v) >= to_int(mode, &x); break; + case '<': value = to_int(mode, v) < to_int(mode, x); break; + case '>': value = to_int(mode, v) > to_int(mode, x); break; + case SY_LEQ: value = to_int(mode, v) <= to_int(mode, x); break; + case SY_GEQ: value = to_int(mode, v) >= to_int(mode, x); break; } } if (mode != MODE_NORMAL) value = 0; - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; set_bool_value(v, value); } } @@ -3656,31 +3775,31 @@ static void relational_expression(int mode, Value * v) { static void equality_expression(int mode, Value * v) { relational_expression(mode, v); while (text_sy == SY_EQU || text_sy == SY_NEQ) { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int sy = text_sy; next_sy(); - relational_expression(mode, &x); + relational_expression(mode, x); if (mode != MODE_SKIP) { uint32_t value = 0; - if (v->type_class == TYPE_CLASS_ARRAY && x.type_class == TYPE_CLASS_ARRAY) { + if (v->type_class == TYPE_CLASS_ARRAY && x->type_class == TYPE_CLASS_ARRAY) { load_value(v); - load_value(&x); - value = strcmp((char *)v->value, (char *)x.value) == 0; + load_value(x); + value = strcmp((char *)v->value, (char *)x->value) == 0; } - else if (v->type_class == TYPE_CLASS_COMPLEX || x.type_class == TYPE_CLASS_COMPLEX) { + else if (v->type_class == TYPE_CLASS_COMPLEX || x->type_class == TYPE_CLASS_COMPLEX) { value = - to_r_double(mode, v) == to_r_double(mode, &x) && - to_i_double(mode, v) == to_i_double(mode, &x); + to_r_double(mode, v) == to_r_double(mode, x) && + to_i_double(mode, v) == to_i_double(mode, x); } - else if (is_real_number(v) || is_real_number(&x)) { - value = to_double(mode, v) == to_double(mode, &x); + else if (is_real_number(v) || is_real_number(x)) { + value = to_double(mode, v) == to_double(mode, x); } else { - value = to_int(mode, v) == to_int(mode, &x); + value = to_int(mode, v) == to_int(mode, x); } if (sy == SY_NEQ) value = !value; if (mode != MODE_NORMAL) value = 0; - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; set_bool_value(v, value); } } @@ -3689,25 +3808,25 @@ static void equality_expression(int mode, Value * v) { static void and_expression(int mode, Value * v) { equality_expression(mode, v); while (text_sy == '&') { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); next_sy(); - equality_expression(mode, &x); + equality_expression(mode, x); if (mode != MODE_SKIP) { int64_t value = 0; - if (!is_whole_number(v) || !is_whole_number(&x)) { + if (!is_whole_number(v) || !is_whole_number(x)) { error(ERR_INV_EXPRESSION, "Integral types expected"); } - if (v->type_class == TYPE_CLASS_CARDINAL || x.type_class == TYPE_CLASS_CARDINAL) { + if (v->type_class == TYPE_CLASS_CARDINAL || x->type_class == TYPE_CLASS_CARDINAL) { v->type_class = TYPE_CLASS_CARDINAL; - value = to_uns(mode, v) & to_uns(mode, &x); + value = to_uns(mode, v) & to_uns(mode, x); } else { v->type_class = TYPE_CLASS_INTEGER; - value = to_int(mode, v) & to_int(mode, &x); + value = to_int(mode, v) & to_int(mode, x); } if (mode != MODE_NORMAL) value = 0; v->type = NULL; - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; set_int_value(v, sizeof(int64_t), value); } } @@ -3716,25 +3835,25 @@ static void and_expression(int mode, Value * v) { static void exclusive_or_expression(int mode, Value * v) { and_expression(mode, v); while (text_sy == '^') { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); next_sy(); - and_expression(mode, &x); + and_expression(mode, x); if (mode != MODE_SKIP) { int64_t value = 0; - if (!is_whole_number(v) || !is_whole_number(&x)) { + if (!is_whole_number(v) || !is_whole_number(x)) { error(ERR_INV_EXPRESSION, "Integral types expected"); } - if (v->type_class == TYPE_CLASS_CARDINAL || x.type_class == TYPE_CLASS_CARDINAL) { + if (v->type_class == TYPE_CLASS_CARDINAL || x->type_class == TYPE_CLASS_CARDINAL) { v->type_class = TYPE_CLASS_CARDINAL; - value = to_uns(mode, v) ^ to_uns(mode, &x); + value = to_uns(mode, v) ^ to_uns(mode, x); } else { v->type_class = TYPE_CLASS_INTEGER; - value = to_int(mode, v) ^ to_int(mode, &x); + value = to_int(mode, v) ^ to_int(mode, x); } if (mode != MODE_NORMAL) value = 0; v->type = NULL; - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; set_int_value(v, sizeof(int64_t), value); } } @@ -3743,25 +3862,25 @@ static void exclusive_or_expression(int mode, Value * v) { static void inclusive_or_expression(int mode, Value * v) { exclusive_or_expression(mode, v); while (text_sy == '|') { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); next_sy(); - exclusive_or_expression(mode, &x); + exclusive_or_expression(mode, x); if (mode != MODE_SKIP) { int64_t value = 0; - if (!is_whole_number(v) || !is_whole_number(&x)) { + if (!is_whole_number(v) || !is_whole_number(x)) { error(ERR_INV_EXPRESSION, "Integral types expected"); } - if (v->type_class == TYPE_CLASS_CARDINAL || x.type_class == TYPE_CLASS_CARDINAL) { + if (v->type_class == TYPE_CLASS_CARDINAL || x->type_class == TYPE_CLASS_CARDINAL) { v->type_class = TYPE_CLASS_CARDINAL; - value = to_uns(mode, v) | to_uns(mode, &x); + value = to_uns(mode, v) | to_uns(mode, x); } else { v->type_class = TYPE_CLASS_INTEGER; - value = to_int(mode, v) | to_int(mode, &x); + value = to_int(mode, v) | to_int(mode, x); } if (mode != MODE_NORMAL) value = 0; v->type = NULL; - v->constant = v->constant && x.constant; + v->constant = v->constant && x->constant; set_int_value(v, sizeof(int64_t), value); } } @@ -3770,13 +3889,13 @@ static void inclusive_or_expression(int mode, Value * v) { static void logical_and_expression(int mode, Value * v) { inclusive_or_expression(mode, v); while (text_sy == SY_AND) { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int b = to_boolean(mode, v); next_sy(); - inclusive_or_expression(b ? mode : MODE_SKIP, &x); + inclusive_or_expression(b ? mode : MODE_SKIP, x); if (b) { - if (!v->constant) x.constant = 0; - *v = x; + if (!v->constant) x->constant = 0; + *v = *x; } } } @@ -3784,13 +3903,13 @@ static void logical_and_expression(int mode, Value * v) { static void logical_or_expression(int mode, Value * v) { logical_and_expression(mode, v); while (text_sy == SY_OR) { - Value x; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); int b = to_boolean(mode, v); next_sy(); - logical_and_expression(!b ? mode : MODE_SKIP, &x); + logical_and_expression(!b ? mode : MODE_SKIP, x); if (!b) { - if (!v->constant) x.constant = 0; - *v = x; + if (!v->constant) x->constant = 0; + *v = *x; } } } @@ -3798,16 +3917,16 @@ static void logical_or_expression(int mode, Value * v) { static void conditional_expression(int mode, Value * v) { logical_or_expression(mode, v); if (text_sy == '?') { - Value x; - Value y; + Value * x = (Value *)tmp_alloc_zero(sizeof(Value)); + Value * y = (Value *)tmp_alloc_zero(sizeof(Value)); int b = to_boolean(mode, v); next_sy(); - expression(b ? mode : MODE_SKIP, &x); + expression(b ? mode : MODE_SKIP, x); if (text_sy != ':') error(ERR_INV_EXPRESSION, "Missing ':'"); next_sy(); - conditional_expression(!b ? mode : MODE_SKIP, &y); - if (!v->constant) x.constant = y.constant = 0; - *v = b ? x : y; + conditional_expression(!b ? mode : MODE_SKIP, y); + if (!v->constant) x->constant = y->constant = 0; + *v = b ? *x : *y; } } @@ -3914,12 +4033,12 @@ int value_to_double(Value * v, double *res) { /********************** Commands **************************/ -typedef struct CommandArgs { +typedef struct { char token[256]; char id[256]; } CommandArgs; -typedef struct CommandCreateArgs { +typedef struct { char token[256]; char id[256]; int use_state; @@ -3928,14 +4047,14 @@ typedef struct CommandCreateArgs { char * script; } CommandCreateArgs; -typedef struct CommandAssignArgs { +typedef struct { char token[256]; char id[256]; char * value_buf; size_t value_size; } CommandAssignArgs; -typedef struct Expression { +typedef struct { LINK link_all; LINK link_id; char id[256]; @@ -3966,9 +4085,7 @@ static unsigned expr_id_cnt = 0; #define expression_hash(id) ((unsigned)atoi(id + 4) % ID2EXP_HASH_SIZE) -#if ENABLE_ExpressionSerialization - -typedef struct PendingCommand { +typedef struct { LINK link; CacheClient * client; Channel * channel; @@ -3978,50 +4095,56 @@ typedef struct PendingCommand { #define link_cmds2cmd(A) ((PendingCommand *)((char *)(A) - offsetof(PendingCommand, link))) -static PendingCommand * pending_cmd = NULL; -static LINK cmd_queue; +typedef struct { + PendingCommand * pending_cmd; + LINK cmd_queue; +} ChannelExtensionExpr; + +static size_t channel_extension_offset = 0; +#define EXT_CH(ch) ((ChannelExtensionExpr *)((char *)(ch) + channel_extension_offset)) static void command_start(CacheClient * client, Channel * channel, void * args, size_t args_size) { + ChannelExtensionExpr * ext = EXT_CH(channel); PendingCommand * cmd = (PendingCommand *)loc_alloc_zero(sizeof(PendingCommand)); assert(args_size <= sizeof(cmd->args)); channel_lock_with_msg(cmd->channel = channel, EXPRESSIONS); memcpy(cmd->args, args, args_size); cmd->args_size = args_size; cmd->client = client; - list_add_last(&cmd->link, &cmd_queue); - if (cmd_queue.next == &cmd->link) { - assert(pending_cmd == NULL); - pending_cmd = cmd; + if (ext->cmd_queue.next == NULL) list_init(&ext->cmd_queue); + list_add_last(&cmd->link, &ext->cmd_queue); + if (ext->cmd_queue.next == &cmd->link) { + assert(ext->pending_cmd == NULL); + ext->pending_cmd = cmd; cache_enter(cmd->client, cmd->channel, cmd->args, cmd->args_size); } } static void command_start_next(void * args) { + Channel * channel = (Channel *)args; + ChannelExtensionExpr * ext = EXT_CH(channel); PendingCommand * cmd = NULL; - assert(pending_cmd == NULL); - pending_cmd = cmd = link_cmds2cmd(cmd_queue.next); + assert(ext->pending_cmd == NULL); + assert(!list_is_empty(&ext->cmd_queue)); + ext->pending_cmd = cmd = link_cmds2cmd(ext->cmd_queue.next); cache_enter(cmd->client, cmd->channel, cmd->args, cmd->args_size); } -static void command_done(void) { - PendingCommand * cmd = pending_cmd; - pending_cmd = NULL; +static void command_done(Channel * channel) { + ChannelExtensionExpr * ext = EXT_CH(channel); + PendingCommand * cmd = ext->pending_cmd; + ext->pending_cmd = NULL; assert(cmd != NULL); - assert(&cmd->link == cmd_queue.next); + assert(cmd->channel == channel); + assert(&cmd->link == ext->cmd_queue.next); + list_remove(ext->cmd_queue.next); + if (!list_is_empty(&ext->cmd_queue)) { + post_event(command_start_next, channel); + } channel_unlock_with_msg(cmd->channel, EXPRESSIONS); - list_remove(cmd_queue.next); loc_free(cmd); - if (list_is_empty(&cmd_queue)) return; - post_event(command_start_next, NULL); } -#else - -#define command_start(client, channel, args, args_size) cache_enter(client, channel, args, args_size) -#define command_done() - -#endif - static Expression * find_expression(char * id) { if (id[0] == 'E' && id[1] == 'X' && id[2] == 'P' && id[3] == 'R') { unsigned hash = expression_hash(id); @@ -4193,19 +4316,21 @@ static void get_context_cache_client(void * x) { cache_exit(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, err); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, err); - if (err) { - write_stringz(&c->out, "null"); - } - else { - write_context(&c->out, expr); - write_stream(&c->out, 0); - } + if (err) { + write_stringz(&c->out, "null"); + } + else { + write_context(&c->out, expr); + write_stream(&c->out, 0); + } - write_stream(&c->out, MARKER_EOM); + write_stream(&c->out, MARKER_EOM); + } } static void command_get_context(char * token, Channel * c) { @@ -4269,35 +4394,37 @@ static void get_children_cache_client(void * x) { cache_exit(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); - write_errno(&c->out, err); + write_errno(&c->out, err); - write_stream(&c->out, '['); + write_stream(&c->out, '['); #if ENABLE_Symbols && (SERVICE_StackTrace || ENABLE_ContextProxy) - { - int i; - for (i = 0; i < sym_cnt; i++) { - const char * s = parent_id; - if (i > 0) write_stream(&c->out, ','); - write_stream(&c->out, '"'); - write_stream(&c->out, 'S'); - while (*s) { - if (*s == '.') write_stream(&c->out, '.'); - json_write_char(&c->out, *s++); + { + int i; + for (i = 0; i < sym_cnt; i++) { + const char * s = parent_id; + if (i > 0) write_stream(&c->out, ','); + write_stream(&c->out, '"'); + write_stream(&c->out, 'S'); + while (*s) { + if (*s == '.') write_stream(&c->out, '.'); + json_write_char(&c->out, *s++); + } + write_stream(&c->out, '.'); + s = symbol2id(sym_buf[i]); + while (*s) json_write_char(&c->out, *s++); + write_stream(&c->out, '"'); } - write_stream(&c->out, '.'); - s = symbol2id(sym_buf[i]); - while (*s) json_write_char(&c->out, *s++); - write_stream(&c->out, '"'); } - } #endif - write_stream(&c->out, ']'); - write_stream(&c->out, 0); + write_stream(&c->out, ']'); + write_stream(&c->out, 0); - write_stream(&c->out, MARKER_EOM); + write_stream(&c->out, MARKER_EOM); + } } static void command_get_children(char * token, Channel * c) { @@ -4345,7 +4472,10 @@ static void command_create_cache_client(void * x) { err = errno; } if (!err) { - check_all_stopped(ctx); + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + if ((mem->mem_access & MEM_ACCESS_RD_STOP) != 0 || (ctx->reg_access & REG_ACCESS_RD_STOP) != 0) { + check_all_stopped(ctx); + } expression_context = ctx; expression_frame = frame; expression_addr = e->addr; @@ -4364,24 +4494,28 @@ static void command_create_cache_client(void * x) { cache_exit(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, err); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, err); - if (err) { - write_stringz(&c->out, "null"); - loc_free(args->script); - } - else { - *(e = (Expression *)loc_alloc(sizeof(Expression))) = buf; - list_add_last(&e->link_all, &expressions); - list_add_last(&e->link_id, id2exp + expression_hash(e->id)); - write_context(&c->out, e); - write_stream(&c->out, 0); + if (err) { + write_stringz(&c->out, "null"); + loc_free(args->script); + } + else { + *(e = (Expression *)loc_alloc(sizeof(Expression))) = buf; + list_add_last(&e->link_all, &expressions); + list_add_last(&e->link_id, id2exp + expression_hash(e->id)); + write_context(&c->out, e); + write_stream(&c->out, 0); + } + + write_stream(&c->out, MARKER_EOM); } - write_stream(&c->out, MARKER_EOM); - command_done(); + run_ctrl_unlock(); + command_done(c); } static void command_create(char * token, Channel * c) { @@ -4396,6 +4530,7 @@ static void command_create(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); args.use_state = 1; strlcpy(args.token, token, sizeof(args.token)); command_start(command_create_cache_client, c, &args, sizeof(args)); @@ -4419,6 +4554,7 @@ static void command_create_in_scope(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); command_start(command_create_cache_client, c, &args, sizeof(args)); } @@ -4438,7 +4574,10 @@ static void command_evaluate_cache_client(void * x) { memset(&value, 0, sizeof(value)); if (expression_context_id(args->id, &ctx, &frame, &e) < 0) err = errno; if (!err) { - check_all_stopped(ctx); + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + if ((mem->mem_access & MEM_ACCESS_RD_STOP) != 0 || (ctx->reg_access & REG_ACCESS_RD_STOP) != 0) { + check_all_stopped(ctx); + } expression_context = ctx; expression_frame = frame; expression_addr = e->addr; @@ -4446,9 +4585,14 @@ static void command_evaluate_cache_client(void * x) { else value_ok = 1; } if (!err && value.remote && value.size <= 0x10000) { + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); buf = tmp_alloc_zero((size_t)value.size); - if (!err && context_read_mem(ctx, value.address, buf, (size_t)value.size) < 0) + if ((mem->mem_access & MEM_ACCESS_RD_RUNNING) == 0) { + if (!is_all_stopped(ctx)) err = set_errno(errno, "Cannot read memory if not stopped"); + } + if (!err && context_read_mem(ctx, value.address, buf, (size_t)value.size) < 0) { err = set_errno(errno, "Cannot read target memory"); + } } if (!err && value.loc) { unsigned n; @@ -4470,169 +4614,173 @@ static void command_evaluate_cache_client(void * x) { cache_exit(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - if (err) { - write_stringz(&c->out, "null"); - } - else if (!value.remote) { - json_write_binary(&c->out, value.value, (size_t)value.size); - write_stream(&c->out, 0); - } - else if (buf != NULL) { - json_write_binary(&c->out, buf, (size_t)value.size); - write_stream(&c->out, 0); - } - else { - write_stringz(&c->out, "null"); - } - write_errno(&c->out, err); - if (!value_ok) { - write_stringz(&c->out, "null"); - } - else { - int cnt = 0; - write_stream(&c->out, '{'); - - if (value.type_class != TYPE_CLASS_UNKNOWN) { - json_write_string(&c->out, "Class"); - write_stream(&c->out, ':'); - json_write_long(&c->out, value.type_class); - cnt++; + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + if (err) { + write_stringz(&c->out, "null"); } - -#if ENABLE_Symbols - if (value.type != NULL) { - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "Type"); - write_stream(&c->out, ':'); - json_write_string(&c->out, symbol2id(value.type)); - cnt++; + else if (!value.remote) { + json_write_binary(&c->out, value.value, (size_t)value.size); + write_stream(&c->out, 0); } - - if (value.sym != NULL) { - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "Symbol"); - write_stream(&c->out, ':'); - json_write_string(&c->out, symbol2id(value.sym)); - cnt++; + else if (buf != NULL) { + json_write_binary(&c->out, buf, (size_t)value.size); + write_stream(&c->out, 0); } -#endif - if (value.bit_stride != 0) { - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "BitStride"); - write_stream(&c->out, ':'); - json_write_ulong(&c->out, value.bit_stride); - cnt++; + else { + write_stringz(&c->out, "null"); } - - if (value.binary_scale != 0) { - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "BinaryScale"); - write_stream(&c->out, ':'); - json_write_long(&c->out, value.binary_scale); - cnt++; + write_errno(&c->out, err); + if (!value_ok) { + write_stringz(&c->out, "null"); } + else { + unsigned cnt = 0; + write_stream(&c->out, '{'); - if (value.decimal_scale != 0) { - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "DecimalScale"); - write_stream(&c->out, ':'); - json_write_long(&c->out, value.decimal_scale); - cnt++; - } + if (value.type_class != TYPE_CLASS_UNKNOWN) { + json_write_string(&c->out, "Class"); + write_stream(&c->out, ':'); + json_write_long(&c->out, value.type_class); + cnt++; + } - if (implicit_pointer) { - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "ImplicitPointer"); - write_stream(&c->out, ':'); - json_write_boolean(&c->out, 1); - cnt++; - } - else { - if (value.reg != NULL) { - int reg_frame = value.loc->ctx == ctx ? frame : STACK_NO_FRAME; +#if ENABLE_Symbols + if (value.type != NULL) { + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "Type"); + write_stream(&c->out, ':'); + json_write_string(&c->out, symbol2id(value.type)); + cnt++; + } + + if (value.sym != NULL) { if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "Register"); + json_write_string(&c->out, "Symbol"); write_stream(&c->out, ':'); - json_write_string(&c->out, register2id(value.loc->ctx, reg_frame, value.reg)); + json_write_string(&c->out, symbol2id(value.sym)); + cnt++; + } +#endif + if (value.bit_stride != 0) { + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "BitStride"); + write_stream(&c->out, ':'); + json_write_ulong(&c->out, value.bit_stride); cnt++; } - if (value.remote) { + if (value.binary_scale != 0) { if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "Address"); + json_write_string(&c->out, "BinaryScale"); write_stream(&c->out, ':'); - json_write_uint64(&c->out, value.address); + json_write_long(&c->out, value.binary_scale); cnt++; } - if (value.loc != NULL && value.loc->pieces_cnt > 0 && value.reg == NULL) { - unsigned i; + if (value.decimal_scale != 0) { if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "Pieces"); + json_write_string(&c->out, "DecimalScale"); write_stream(&c->out, ':'); - write_stream(&c->out, '['); - for (i = 0; i < value.loc->pieces_cnt; i++) { - LocationPiece * piece = value.loc->pieces + i; - if (i > 0) write_stream(&c->out, ','); - write_stream(&c->out, '{'); - if (piece->size) { - json_write_string(&c->out, "Size"); - write_stream(&c->out, ':'); - json_write_ulong(&c->out, piece->size); - } - else { - json_write_string(&c->out, "BitSize"); - write_stream(&c->out, ':'); - json_write_ulong(&c->out, piece->bit_size); - } - if (piece->bit_offs) { - write_stream(&c->out, ','); - json_write_string(&c->out, "BitOffs"); - write_stream(&c->out, ':'); - json_write_ulong(&c->out, piece->bit_offs); - } - if (!piece->optimized_away) { - write_stream(&c->out, ','); - if (piece->reg) { - Context * reg_ctx = value.loc->ctx; - int reg_frame = get_info_frame(value.loc->ctx, value.loc->stack_frame); - json_write_string(&c->out, "Register"); + json_write_long(&c->out, value.decimal_scale); + cnt++; + } + + if (implicit_pointer) { + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "ImplicitPointer"); + write_stream(&c->out, ':'); + json_write_boolean(&c->out, 1); + cnt++; + } + else { + if (value.reg != NULL) { + int reg_frame = value.loc->ctx == ctx ? frame : STACK_NO_FRAME; + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "Register"); + write_stream(&c->out, ':'); + json_write_string(&c->out, register2id(value.loc->ctx, reg_frame, value.reg)); + cnt++; + } + + if (value.remote) { + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "Address"); + write_stream(&c->out, ':'); + json_write_uint64(&c->out, value.address); + cnt++; + } + + if (value.loc != NULL && value.loc->pieces_cnt > 0 && value.reg == NULL) { + unsigned i; + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "Pieces"); + write_stream(&c->out, ':'); + write_stream(&c->out, '['); + for (i = 0; i < value.loc->pieces_cnt; i++) { + LocationPiece * piece = value.loc->pieces + i; + if (i > 0) write_stream(&c->out, ','); + write_stream(&c->out, '{'); + if (piece->size) { + json_write_string(&c->out, "Size"); write_stream(&c->out, ':'); - json_write_string(&c->out, register2id(reg_ctx, reg_frame, piece->reg)); + json_write_ulong(&c->out, piece->size); } - else if (piece->value) { - json_write_string(&c->out, "Value"); + else { + json_write_string(&c->out, "BitSize"); write_stream(&c->out, ':'); - json_write_binary(&c->out, piece->value, piece->size); + json_write_ulong(&c->out, piece->bit_size); } - else { - json_write_string(&c->out, "Address"); + if (piece->bit_offs) { + write_stream(&c->out, ','); + json_write_string(&c->out, "BitOffs"); write_stream(&c->out, ':'); - json_write_uint64(&c->out, piece->addr); + json_write_ulong(&c->out, piece->bit_offs); + } + if (!piece->optimized_away) { + write_stream(&c->out, ','); + if (piece->reg) { + Context * reg_ctx = value.loc->ctx; + int reg_frame = get_info_frame(value.loc->ctx, value.loc->stack_frame); + json_write_string(&c->out, "Register"); + write_stream(&c->out, ':'); + json_write_string(&c->out, register2id(reg_ctx, reg_frame, piece->reg)); + } + else if (piece->value) { + json_write_string(&c->out, "Value"); + write_stream(&c->out, ':'); + json_write_binary(&c->out, piece->value, piece->size); + } + else { + json_write_string(&c->out, "Address"); + write_stream(&c->out, ':'); + json_write_uint64(&c->out, piece->addr); + } } + write_stream(&c->out, '}'); } - write_stream(&c->out, '}'); + write_stream(&c->out, ']'); + cnt++; } - write_stream(&c->out, ']'); - cnt++; - } - if (value.big_endian) { - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, "BigEndian"); - write_stream(&c->out, ':'); - json_write_boolean(&c->out, 1); - cnt++; + if (value.big_endian) { + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, "BigEndian"); + write_stream(&c->out, ':'); + json_write_boolean(&c->out, 1); + cnt++; + } } - } - write_stream(&c->out, '}'); - write_stream(&c->out, 0); + write_stream(&c->out, '}'); + write_stream(&c->out, 0); + } + write_stream(&c->out, MARKER_EOM); } - write_stream(&c->out, MARKER_EOM); - command_done(); + + run_ctrl_unlock(); + command_done(c); } static void command_evaluate(char * token, Channel * c) { @@ -4642,6 +4790,7 @@ static void command_evaluate(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); command_start(command_evaluate_cache_client, c, &args, sizeof(args)); } @@ -4658,7 +4807,13 @@ static void command_assign_cache_client(void * x) { memset(&value, 0, sizeof(value)); if (expression_context_id(args->id, &ctx, &frame, &e) < 0) err = errno; if (!err) { - check_all_stopped(ctx); + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + if ((mem->mem_access & MEM_ACCESS_RD_STOP) != 0 || (ctx->reg_access & REG_ACCESS_RD_STOP) != 0) { + check_all_stopped(ctx); + } + else if ((mem->mem_access & MEM_ACCESS_WR_STOP) != 0 || (ctx->reg_access & REG_ACCESS_WR_STOP) != 0) { + check_all_stopped(ctx); + } expression_context = ctx; expression_frame = frame; expression_addr = e->addr; @@ -4666,7 +4821,10 @@ static void command_assign_cache_client(void * x) { } if (!err) { if (value.remote) { - if (context_write_mem(ctx, value.address, args->value_buf, args->value_size) < 0) err = errno; + if ((ctx->mem_access & MEM_ACCESS_WR_RUNNING) == 0) { + if (!is_all_stopped(ctx)) err = set_errno(errno, "Cannot write memory if not stopped"); + } + if (!err && context_write_mem(ctx, value.address, args->value_buf, args->value_size) < 0) err = errno; #if SERVICE_Memory if (!err) send_event_memory_changed(ctx, value.address, args->value_size); #endif @@ -4711,12 +4869,16 @@ static void command_assign_cache_client(void * x) { cache_exit(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, err); - write_stream(&c->out, MARKER_EOM); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, err); + write_stream(&c->out, MARKER_EOM); + } + loc_free(args->value_buf); - command_done(); + run_ctrl_unlock(); + command_done(c); } static void command_assign(char * token, Channel * c) { @@ -4728,6 +4890,7 @@ static void command_assign(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); command_start(command_assign_cache_client, c, &args, sizeof(args)); } @@ -4752,11 +4915,14 @@ static void command_dispose_cache_client(void * x) { err = ERR_INV_CONTEXT; } - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, err); - write_stream(&c->out, MARKER_EOM); - command_done(); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, err); + write_stream(&c->out, MARKER_EOM); + } + + command_done(c); } static void command_dispose(char * token, Channel * c) { @@ -4823,10 +4989,8 @@ void ini_expressions_service(Protocol * proto) { static RunControlEventListener rc_listener = { context_intercepted, NULL }; add_run_control_event_listener(&rc_listener, NULL); #endif -#if ENABLE_ExpressionSerialization - list_init(&cmd_queue); -#endif for (i = 0; i < ID2EXP_HASH_SIZE; i++) list_init(id2exp + i); + channel_extension_offset = channel_extension(sizeof(ChannelExtensionExpr)); add_channel_close_listener(on_channel_close); big_endian = big_endian_host(); init = 1; 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/funccall.c b/agent/tcf/services/funccall.c index dca820a3..a5b3f9a9 100644 --- a/agent/tcf/services/funccall.c +++ b/agent/tcf/services/funccall.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Wind River Systems, Inc. and others. + * Copyright (c) 2012-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. @@ -227,18 +227,20 @@ static int c_call_cmds(void) { static void save_registers(void) { unsigned cnt = 0; - RegisterDefinition * r; RegisterDefinition * regs = get_reg_definitions(info->ctx); - for (r = regs; r->name != NULL; r++) { - if (r->dwarf_id < 0) continue; - if (r->size == 0) continue; - cnt++; - } - info->saveregs = (RegisterDefinition **)tmp_alloc(sizeof(RegisterDefinition *) * cnt); - for (r = regs; r->name != NULL; r++) { - if (r->dwarf_id < 0) continue; - if (r->size == 0) continue; - info->saveregs[info->saveregs_cnt++] = r; + if (regs != NULL) { + RegisterDefinition * r; + for (r = regs; r->name != NULL; r++) { + if (r->dwarf_id < 0) continue; + if (r->size == 0) continue; + cnt++; + } + info->saveregs = (RegisterDefinition **)tmp_alloc(sizeof(RegisterDefinition *) * cnt); + for (r = regs; r->name != NULL; r++) { + if (r->dwarf_id < 0) continue; + if (r->size == 0) continue; + info->saveregs[info->saveregs_cnt++] = r; + } } assert(info->saveregs_cnt == cnt); } 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/memorymap.c b/agent/tcf/services/memorymap.c index eb1c70e3..a5d10802 100644 --- a/agent/tcf/services/memorymap.c +++ b/agent/tcf/services/memorymap.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2016 Wind River Systems, Inc. and others. + * Copyright (c) 2009-2019 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. @@ -366,7 +366,7 @@ void add_memory_map_event_listener(MemoryMapEventListener * listener, void * cli l->args = client_data; } -static void write_map_region(OutputStream * out, MemoryRegion * m) { +void write_map_region(OutputStream * out, MemoryRegion * m) { MemoryRegionAttribute * x = m->attrs; write_stream(out, '{'); @@ -437,25 +437,29 @@ static void write_map_region(OutputStream * out, MemoryRegion * m) { write_stream(out, '}'); } -static void command_get(char * token, Channel * c) { +typedef struct CommandGetArgs { + char token[256]; char id[256]; - int err = 0; +} CommandGetArgs; + +static void command_get_cache_client(void * x) { + CommandGetArgs * args = (CommandGetArgs *)x; + Channel * c = cache_channel(); Context * ctx = NULL; MemoryMap * client_map = NULL; MemoryMap * target_map = NULL; + int err = 0; - json_read_string(&c->inp, id, sizeof(id)); - json_test_char(&c->inp, MARKER_EOA); - json_test_char(&c->inp, MARKER_EOM); - - ctx = id2ctx(id); + ctx = id2ctx(args->id); if (ctx == NULL) err = ERR_INV_CONTEXT; else ctx = get_mem_context(ctx); if (!err && memory_map_get(ctx, &client_map, &target_map) < 0) err = errno; + cache_exit(); + write_stringz(&c->out, "R"); - write_stringz(&c->out, token); + write_stringz(&c->out, args->token); write_errno(&c->out, err); if (err) { write_stringz(&c->out, "null"); @@ -481,6 +485,20 @@ static void command_get(char * token, Channel * c) { write_stream(&c->out, MARKER_EOM); } +static void command_get(char * token, Channel * c) { + char id[256]; + CommandGetArgs args; + + json_read_string(&c->inp, id, sizeof(id)); + json_test_char(&c->inp, MARKER_EOA); + json_test_char(&c->inp, MARKER_EOM); + + strlcpy(args.token, token, sizeof(args.token)); + strlcpy(args.id, id, sizeof(args.id)); + + cache_enter(command_get_cache_client, c, &args, sizeof(args)); +} + static void read_map_attribute(InputStream * inp, const char * name, void * args) { MemoryRegion * r = (MemoryRegion *)args; if (strcmp(name, "Addr") == 0) r->addr = (ContextAddress)json_read_uint64(inp); @@ -594,30 +612,35 @@ static void channel_close_listener(Channel * c) { } void ini_memory_map_service(Protocol * proto, TCFBroadcastGroup * bcg) { - { - static ContextEventListener listener = { - event_context_changed, - NULL, - NULL, - NULL, - event_context_changed, - event_context_disposed - }; - add_context_event_listener(&listener, NULL); - } + static int ini_done = 0; + if (!ini_done) { + ini_done = 1; + { + static ContextEventListener listener = { + event_context_changed, + NULL, + NULL, + NULL, + event_context_changed, + event_context_disposed + }; + add_context_event_listener(&listener, NULL); + } #if SERVICE_PathMap - { - static PathMapEventListener listener = { - event_path_map_changed, - }; - add_path_map_event_listener(&listener, NULL); - } + { + static PathMapEventListener listener = { + event_path_map_changed, + }; + add_path_map_event_listener(&listener, NULL); + } #endif - broadcast_group = bcg; - add_channel_close_listener(channel_close_listener); + add_channel_close_listener(channel_close_listener); + context_extension_offset = context_extension(sizeof(ContextExtensionMM)); + broadcast_group = bcg; + } + assert(broadcast_group == bcg); add_command_handler(proto, MEMORY_MAP, "get", command_get); add_command_handler(proto, MEMORY_MAP, "set", command_set); - context_extension_offset = context_extension(sizeof(ContextExtensionMM)); } diff --git a/agent/tcf/services/memorymap.h b/agent/tcf/services/memorymap.h index e0747e38..687f2651 100644 --- a/agent/tcf/services/memorymap.h +++ b/agent/tcf/services/memorymap.h @@ -77,6 +77,8 @@ extern void add_memory_map_event_listener(MemoryMapEventListener * listener, voi extern void ini_memory_map_service(Protocol * proto, TCFBroadcastGroup * bcg); +extern void write_map_region(OutputStream * out, MemoryRegion * m); + #else #define memory_map_event_module_loaded(ctx) diff --git a/agent/tcf/services/memoryservice.c b/agent/tcf/services/memoryservice.c index c44f83db..58515563 100644 --- a/agent/tcf/services/memoryservice.c +++ b/agent/tcf/services/memoryservice.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2016 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. @@ -146,6 +146,22 @@ static void write_context(OutputStream * out, Context * ctx) { if (cnt++) write_stream(out, ','); json_write_string(out, "tlb"); } + if (ctx->mem_access & MEM_ACCESS_RD_RUNNING) { + if (cnt++) write_stream(out, ','); + json_write_string(out, "rd-running"); + } + if (ctx->mem_access & MEM_ACCESS_WR_RUNNING) { + if (cnt++) write_stream(out, ','); + json_write_string(out, "wr-running"); + } + if (ctx->mem_access & MEM_ACCESS_RD_STOP) { + if (cnt++) write_stream(out, ','); + json_write_string(out, "rd-stop"); + } + if (ctx->mem_access & MEM_ACCESS_WR_STOP) { + if (cnt++) write_stream(out, ','); + json_write_string(out, "wr-stop"); + } write_stream(out, ']'); } @@ -237,22 +253,19 @@ static void write_ranges(OutputStream * out, ContextAddress addr, int offs, int write_stream(out, 0); } -static void command_get_context(char * token, Channel * c) { +static void get_context_cache_client(void * parm) { + MemoryCommandArgs * args = (MemoryCommandArgs *)parm; + Channel * c = cache_channel(); + Context * ctx = id2ctx(args->ctx_id); int err = 0; - char id[256]; - Context * ctx = NULL; - - json_read_string(&c->inp, id, sizeof(id)); - json_test_char(&c->inp, MARKER_EOA); - json_test_char(&c->inp, MARKER_EOM); - ctx = id2ctx(id); + cache_exit(); if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; else if (ctx->mem_access == 0) err = ERR_INV_CONTEXT; write_stringz(&c->out, "R"); - write_stringz(&c->out, token); + write_stringz(&c->out, args->token); write_errno(&c->out, err); if (err == 0) { write_context(&c->out, ctx); @@ -264,20 +277,34 @@ static void command_get_context(char * token, Channel * c) { write_stream(&c->out, MARKER_EOM); } -static void command_get_children(char * token, Channel * c) { - char id[256]; +static void command_get_context(char * token, Channel * c) { + MemoryCommandArgs args; - json_read_string(&c->inp, id, sizeof(id)); + memset(&args, 0, sizeof(args)); + json_read_string(&c->inp, args.ctx_id, sizeof(args.ctx_id)); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + strlcpy(args.token, token, sizeof(args.token)); + cache_enter(get_context_cache_client, c, &args, sizeof(MemoryCommandArgs)); +} + +static void get_children_cache_client(void * parm) { + MemoryCommandArgs * args = (MemoryCommandArgs *)parm; + Channel * c = cache_channel(); + Context * parent = NULL; + + if (args->ctx_id[0] != 0) parent = id2ctx(args->ctx_id); + + cache_exit(); + write_stringz(&c->out, "R"); - write_stringz(&c->out, token); + write_stringz(&c->out, args->token); write_errno(&c->out, 0); write_stream(&c->out, '['); - if (id[0] == 0) { + if (args->ctx_id[0] == 0) { LINK * qp; int cnt = 0; for (qp = context_root.next; qp != &context_root; qp = qp->next) { @@ -290,20 +317,17 @@ static void command_get_children(char * token, Channel * c) { cnt++; } } - else { - Context * parent = id2ctx(id); - if (parent != NULL) { - LINK * l; - int cnt = 0; - for (l = parent->children.next; l != &parent->children; l = l->next) { - Context * ctx = cldl2ctxp(l); - assert(ctx->parent == parent); - if (ctx->exited) continue; - if (ctx->mem_access == 0 && list_is_empty(&ctx->children)) continue; - if (cnt > 0) write_stream(&c->out, ','); - json_write_string(&c->out, ctx->id); - cnt++; - } + else if (parent != NULL) { + LINK * l; + int cnt = 0; + for (l = parent->children.next; l != &parent->children; l = l->next) { + Context * ctx = cldl2ctxp(l); + assert(ctx->parent == parent); + if (ctx->exited) continue; + if (ctx->mem_access == 0 && list_is_empty(&ctx->children)) continue; + if (cnt > 0) write_stream(&c->out, ','); + json_write_string(&c->out, ctx->id); + cnt++; } } write_stream(&c->out, ']'); @@ -312,6 +336,18 @@ static void command_get_children(char * token, Channel * c) { write_stream(&c->out, MARKER_EOM); } +static void command_get_children(char * token, Channel * c) { + MemoryCommandArgs args; + + memset(&args, 0, sizeof(args)); + json_read_string(&c->inp, args.ctx_id, sizeof(args.ctx_id)); + json_test_char(&c->inp, MARKER_EOA); + json_test_char(&c->inp, MARKER_EOM); + + strlcpy(args.token, token, sizeof(args.token)); + cache_enter(get_children_cache_client, c, &args, sizeof(MemoryCommandArgs)); +} + static void read_memory_fill_array_cb(InputStream * inp, void * args) { MemoryCommandArgs * buf = (MemoryCommandArgs *)args; if (buf->pos >= buf->max) { @@ -340,6 +376,7 @@ static MemoryCommandArgs * read_command_args(char * token, Channel * c, int cmd) if (mode & 0x02) buf.mode.verify = 1; if (mode & 0x04) buf.mode.bypass_addr_check = 1; if (mode & 0x08) buf.mode.bypass_cache_sync = 1; + if (mode & 0x10) buf.mode.dont_stop = 1; switch (cmd) { case CMD_SET: json_read_binary_start(&buf.state, &c->inp); @@ -357,6 +394,7 @@ static MemoryCommandArgs * read_command_args(char * token, Channel * c, int cmd) break; } + run_ctrl_lock(); strlcpy(buf.token, token, sizeof(buf.token)); return &buf; } @@ -364,6 +402,7 @@ static MemoryCommandArgs * read_command_args(char * token, Channel * c, int cmd) void send_event_memory_changed(Context * ctx, ContextAddress addr, unsigned long size) { OutputStream * out = &broadcast_group->out; + assert(cache_miss_count() == 0); write_stringz(out, "E"); write_stringz(out, MEMORY); write_stringz(out, "memoryChanged"); @@ -408,9 +447,18 @@ static void memory_set_cache_client(void * parm) { if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; + if (args->pos > 0 && err == 0) { + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + if (!args->mode.dont_stop && (mem->mem_access & MEM_ACCESS_WR_STOP) != 0) { + check_all_stopped(ctx); + } + if ((mem->mem_access & MEM_ACCESS_WR_RUNNING) == 0) { + if (!is_all_stopped(ctx)) err = set_errno(errno, "Cannot write memory if not stopped"); + } + } + /* First write needs to be done before cache_exit() */ - if (err == 0) { - check_all_stopped(ctx); + if (args->pos > 0 && err == 0) { #if ENABLE_MemoryAccessModes if (context_write_mem_ext(ctx, &args->mode, addr, args->buf, args->pos) < 0) { #else @@ -472,6 +520,7 @@ static void memory_set_cache_client(void * parm) { write_stream(out, MARKER_EOM); } loc_free(args->buf); + run_ctrl_unlock(); } static void command_set(char * token, Channel * c) { @@ -497,13 +546,22 @@ static void memory_get_cache_client(void * parm) { if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; + if (size > 0 && err == 0) { + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + if (!args->mode.dont_stop && (mem->mem_access & MEM_ACCESS_RD_STOP) != 0) { + check_all_stopped(ctx); + } + if ((mem->mem_access & MEM_ACCESS_RD_RUNNING) == 0) { + if (!is_all_stopped(ctx)) err = set_errno(errno, "Cannot read memory if not stopped"); + } + } + /* First read needs to be done before cache_exit() */ if (size > 0) { size_t rd = size; if (rd > args->max) rd = args->max; memset(args->buf, 0, rd); if (err == 0) { - check_all_stopped(ctx); #if ENABLE_MemoryAccessModes if (context_read_mem_ext(ctx, &args->mode, addr, args->buf, rd) < 0) { #else @@ -567,6 +625,7 @@ static void memory_get_cache_client(void * parm) { write_stream(out, MARKER_EOM); } loc_free(args->buf); + run_ctrl_unlock(); } static void command_get(char * token, Channel * c) { @@ -591,9 +650,17 @@ static void memory_fill_cache_client(void * parm) { if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; - if (err == 0) check_all_stopped(ctx); + if (size > 0 && err == 0) { + Context * mem = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + if (!args->mode.dont_stop && (mem->mem_access & MEM_ACCESS_WR_STOP) != 0) { + check_all_stopped(ctx); + } + if ((mem->mem_access & MEM_ACCESS_WR_RUNNING) == 0) { + if (!is_all_stopped(ctx)) err = set_errno(errno, "Cannot write memory if not stopped"); + } + } - while (err == 0 && addr < addr0 + size) { + while (err == 0 && addr - addr0 < size) { /* Note: context_write_mem() modifies buffer contents */ unsigned wr = (unsigned)(addr0 + size - addr); if (wr > args->pos) wr = args->pos; @@ -633,6 +700,7 @@ static void memory_fill_cache_client(void * parm) { write_stream(out, MARKER_EOM); } loc_free(args->buf); + run_ctrl_unlock(); } static void command_fill(char * token, Channel * c) { @@ -653,6 +721,7 @@ static void command_fill(char * token, Channel * c) { static void send_event_context_added(Context * ctx) { OutputStream * out = &broadcast_group->out; + assert(cache_miss_count() == 0); write_stringz(out, "E"); write_stringz(out, MEMORY); write_stringz(out, "contextAdded"); @@ -669,6 +738,7 @@ static void send_event_context_added(Context * ctx) { static void send_event_context_changed(Context * ctx) { OutputStream * out = &broadcast_group->out; + assert(cache_miss_count() == 0); write_stringz(out, "E"); write_stringz(out, MEMORY); write_stringz(out, "contextChanged"); @@ -685,6 +755,7 @@ static void send_event_context_changed(Context * ctx) { static void send_event_context_removed(Context * ctx) { OutputStream * out = &broadcast_group->out; + assert(cache_miss_count() == 0); write_stringz(out, "E"); write_stringz(out, MEMORY); write_stringz(out, "contextRemoved"); diff --git a/agent/tcf/services/pathmap.c b/agent/tcf/services/pathmap.c index 37df86ce..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. @@ -29,9 +29,12 @@ #include <tcf/services/contextquery.h> #include <tcf/services/pathmap.h> +#ifndef ENABLE_CaseInsensitivePathMap +#define ENABLE_CaseInsensitivePathMap 0 +#endif static int is_separator(const char c) { - return ((c == '/') || (c == '\\')); + return c == '/' || c == '\\'; } char * canonic_path_map_file_name(const char * fnm) { @@ -77,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; } @@ -122,7 +139,6 @@ struct PathMap { static const char PATH_MAP[] = "PathMap"; -static int ini_done = 0; static LINK maps = TCF_LIST_INIT(maps); static char host_name[256]; @@ -132,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; @@ -229,6 +249,7 @@ static int update_rule(PathMapRule * r, PathMapRuleAttribute * new_attrs) { InputStream * buf_inp; ByteArrayInputStream buf; char * name = new_attr->name; + int unsupported_attr = 0; new_attrs = new_attr->next; new_attr->next = NULL; @@ -284,6 +305,10 @@ static int update_rule(PathMapRule * r, PathMapRuleAttribute * new_attrs) { loc_free(r->ctx); r->ctx = json_read_alloc_string(buf_inp); } + else { + unsupported_attr = 1; + } + if (!unsupported_attr) json_test_char(buf_inp, MARKER_EOS); } while (old_attrs != NULL) { @@ -325,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++) { @@ -363,7 +388,11 @@ static char * map_file_name(Context * ctx, PathMap * m, char * fnm, int mode) { } src = canonic_path_map_file_name(r->src); k = (unsigned)strlen(src); +#if ENABLE_CaseInsensitivePathMap + if (strncasecmp(src, fnm, k)) continue; +#else if (strncmp(src, fnm, k)) continue; +#endif if (fnm[k] == 0) { /* perfect match */ @@ -389,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; } } @@ -412,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) { @@ -632,11 +667,13 @@ static void channel_close_listener(Channel * c) { } void ini_path_map_service(Protocol * proto, TCFBroadcastGroup * bcg) { + static int ini_done = 0; if (!ini_done) { ini_done = 1; add_channel_close_listener(channel_close_listener); + broadcast_group = bcg; } - broadcast_group = bcg; + assert(broadcast_group == bcg); add_command_handler(proto, PATH_MAP, "get", command_get); add_command_handler(proto, PATH_MAP, "set", command_set); } 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/profiler.c b/agent/tcf/services/profiler.c index 6df6b76d..3c72ecd2 100644 --- a/agent/tcf/services/profiler.c +++ b/agent/tcf/services/profiler.c @@ -163,10 +163,12 @@ static void read_cfg_param(InputStream * inp, const char * name, void * x) { if (strcmp(name, "FrameCnt") == 0) { inp = create_byte_array_input_stream(&buf, p->value, strlen(p->value)); cfg->params.frame_cnt = json_read_ulong(inp); + json_test_char(inp, MARKER_EOS); } else if (strcmp(name, "MaxSamples") == 0) { inp = create_byte_array_input_stream(&buf, p->value, strlen(p->value)); cfg->params.max_samples = json_read_ulong(inp); + json_test_char(inp, MARKER_EOS); } } diff --git a/agent/tcf/services/profiler_sst.c b/agent/tcf/services/profiler_sst.c index c4a5f867..076c5d04 100644 --- a/agent/tcf/services/profiler_sst.c +++ b/agent/tcf/services/profiler_sst.c @@ -62,7 +62,7 @@ typedef struct ProfilerSST { int stop_pending; ContextAddress pc; int disposed; - int lock; + int posted; } ProfilerSST; typedef struct { @@ -174,8 +174,8 @@ static void add_sample_cache_client(void * x) { SampleStackTrace * stk = find_stack_trace(prf); add_to_sample_array(prf, prf->pc, stk); } - prf->lock--; - if (prf->disposed && prf->lock == 0) loc_free(prf); + prf->posted = 0; + if (prf->disposed) loc_free(prf); run_ctrl_unlock(); } @@ -186,7 +186,8 @@ static void add_sample_event(void * args) { static void add_sample(ProfilerSST * prf) { assert(!prf->disposed); - prf->lock++; + if (prf->posted) return; + prf->posted = 1; run_ctrl_lock(); post_event(add_sample_event, prf); } @@ -243,7 +244,7 @@ static void profiler_dispose(void * args) { list_remove(&prf->link_core); free_buffers(prf); prf->disposed = 1; - if (prf->lock == 0) loc_free(prf); + if (!prf->posted) loc_free(prf); } static char * profiler_capabilities(Context * ctx) { diff --git a/agent/tcf/services/registers.c b/agent/tcf/services/registers.c index 190cded6..c7f0eb73 100644 --- a/agent/tcf/services/registers.c +++ b/agent/tcf/services/registers.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. @@ -46,6 +46,18 @@ static Listener * listeners = NULL; static unsigned listener_cnt = 0; static unsigned listener_max = 0; +typedef struct Notification { + LINK link_all; + Context * ctx; + int frame; + RegisterDefinition * def; + char * id; +} Notification; + +static int notify_definitions_changed = 0; +static LINK notifications = TCF_LIST_INIT(notifications); +#define all2notification(link) ((Notification *)((char *)(link) - offsetof(Notification, link_all))) + static uint8_t * bbf = NULL; static unsigned bbf_pos = 0; static unsigned bbf_len = 0; @@ -353,50 +365,87 @@ static void command_get_children(char * token, Channel * c) { cache_enter(command_get_children_cache_client, c, &args, sizeof(args)); } +static void flush_notifications(void) { + OutputStream * out = &broadcast_group->out; + + assert(cache_miss_count() == 0); + + if (notify_definitions_changed) { + unsigned i; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->register_definitions_changed == NULL) continue; + l->func->register_definitions_changed(l->args); + } + + write_stringz(out, "E"); + write_stringz(out, REGISTERS); + write_stringz(out, "contextChanged"); + write_stream(out, 0); + write_stream(out, MARKER_EOM); + } + + while (!list_is_empty(¬ifications)) { + Notification * n = all2notification(notifications.next); + list_remove(&n->link_all); + + if (!notify_definitions_changed && !n->ctx->exited) { + unsigned i; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->register_changed == NULL) continue; + l->func->register_changed(n->ctx, n->frame, n->def, l->args); + } + + write_stringz(out, "E"); + write_stringz(out, REGISTERS); + write_stringz(out, "registerChanged"); + json_write_string(out, n->id); + write_stream(out, 0); + write_stream(out, MARKER_EOM); + } + context_unlock(n->ctx); + loc_free(n->id); + loc_free(n); + } + + notify_definitions_changed = 0; +} + void send_event_register_changed(const char * id) { - unsigned i; Context * ctx = NULL; int frame = STACK_NO_FRAME; RegisterDefinition * def = NULL; - OutputStream * out = &broadcast_group->out; + Notification * n = NULL; + LINK * l = NULL; id2register(id, &ctx, &frame, &def); if (ctx == NULL) return; - - for (i = 0; i < listener_cnt; i++) { - Listener * l = listeners + i; - if (l->func->register_changed == NULL) continue; - l->func->register_changed(ctx, frame, def, l->args); + assert(!ctx->exited); + for (l = notifications.next; l != ¬ifications; l = l->next) { + n = all2notification(l); + if (n->ctx == ctx && n->frame == frame && n->def == def) return; } - if (frame >= 0 && frame == get_top_frame(ctx)) { id = register2id(ctx, STACK_TOP_FRAME, def); } + n = (Notification *)loc_alloc_zero(sizeof(Notification)); + n->ctx = ctx; + n->frame = frame; + n->def = def; + n->id = loc_strdup(id); + context_lock(n->ctx); + list_add_last(&n->link_all, ¬ifications); - write_stringz(out, "E"); - write_stringz(out, REGISTERS); - write_stringz(out, "registerChanged"); - - json_write_string(out, id); - write_stream(out, 0); - - write_stream(out, MARKER_EOM); + /* Delay notifications until cache transaction is committed */ + if (cache_transaction_id() == 0) flush_notifications(); } void send_event_register_definitions_changed(void) { - unsigned i; - OutputStream * out = &broadcast_group->out; - - for (i = 0; i < listener_cnt; i++) { - Listener * l = listeners + i; - if (l->func->register_definitions_changed == NULL) continue; - l->func->register_definitions_changed(l->args); - } - - write_stringz(out, "E"); - write_stringz(out, REGISTERS); - write_stringz(out, "contextChanged"); - write_stream(out, MARKER_EOM); + invalidate_register_ids(); + notify_definitions_changed = 1; + /* Delay notifications until cache transaction is committed */ + if (cache_transaction_id() == 0) flush_notifications(); } typedef struct GetArgs { @@ -421,8 +470,8 @@ static void command_get_cache_client(void * x) { check_all_stopped(ctx); } if ((ctx->reg_access & REG_ACCESS_RD_RUNNING) == 0) { - if (!ctx->stopped && context_has_state(ctx)) - str_exception(ERR_IS_RUNNING, "Cannot read register if not stopped"); + if (context_has_state(ctx) && !is_ctx_stopped(ctx)) + str_exception(errno, "Cannot read register if not stopped"); } if (reg_def->size > bbf_len) { bbf_len += 0x100 + reg_def->size; @@ -445,12 +494,16 @@ static void command_get_cache_client(void * x) { cache_exit(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, trap.error); - json_write_binary(&c->out, bbf, bbf_pos); - write_stream(&c->out, 0); - write_stream(&c->out, MARKER_EOM); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, trap.error); + json_write_binary(&c->out, bbf, bbf_pos); + write_stream(&c->out, 0); + write_stream(&c->out, MARKER_EOM); + } + + run_ctrl_unlock(); } static void command_get(char * token, Channel * c) { @@ -460,6 +513,7 @@ static void command_get(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_get_cache_client, c, &args, sizeof(args)); } @@ -474,7 +528,6 @@ typedef struct SetArgs { static void command_set_cache_client(void * x) { SetArgs * args = (SetArgs *)x; Channel * c = cache_channel(); - int notify = 0; Trap trap; if (set_trap(&trap)) { @@ -489,27 +542,28 @@ static void command_set_cache_client(void * x) { check_all_stopped(ctx); } if ((ctx->reg_access & REG_ACCESS_WR_RUNNING) == 0) { - if (!ctx->stopped && context_has_state(ctx)) - str_exception(ERR_IS_RUNNING, "Cannot write register if not stopped"); + if (context_has_state(ctx) && !is_ctx_stopped(ctx)) + str_exception(errno, "Cannot write register if not stopped"); } if ((size_t)args->data_len > reg_def->size) exception(ERR_INV_DATA_SIZE); if (args->data_len > 0) { if (context_write_reg(ctx, reg_def, 0, args->data_len, args->data) < 0) exception(errno); - notify = 1; + send_event_register_changed(args->id); } clear_trap(&trap); } cache_exit(); - if (notify) send_event_register_changed(args->id); - - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, trap.error); - write_stream(&c->out, MARKER_EOM); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, trap.error); + write_stream(&c->out, MARKER_EOM); + } loc_free(args->data); + run_ctrl_unlock(); } static void command_set(char * token, Channel * c) { @@ -521,6 +575,7 @@ static void command_set(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_set_cache_client, c, &args, sizeof(args)); } @@ -533,7 +588,6 @@ typedef struct Location { RegisterDefinition * reg_def; unsigned offs; unsigned size; - int notify; } Location; static Location * buf = NULL; @@ -590,12 +644,12 @@ 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->stopped && context_has_state(loc->ctx)) - str_fmt_exception(ERR_IS_RUNNING, "Cannot %s register if not stopped", setm ? "write" : "read"); + 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"); } if (loc->offs + loc->size > loc->reg_def->size) exception(ERR_INV_DATA_SIZE); @@ -642,14 +696,17 @@ static void command_getm_cache_client(void * x) { cache_exit(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, trap.error); - json_write_binary(&c->out, bbf, bbf_pos); - write_stream(&c->out, 0); - write_stream(&c->out, MARKER_EOM); + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, trap.error); + json_write_binary(&c->out, bbf, bbf_pos); + write_stream(&c->out, 0); + write_stream(&c->out, MARKER_EOM); + } loc_free(args->locs); + run_ctrl_unlock(); } static void command_getm(char * token, Channel * c) { @@ -659,6 +716,7 @@ static void command_getm(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_getm_cache_client, c, &args, sizeof(args)); } @@ -674,7 +732,6 @@ typedef struct SetmArgs { static void command_setm_cache_client(void * x) { SetmArgs * args = (SetmArgs *)x; Channel * c = cache_channel(); - int notify = 0; Trap trap; if (set_trap(&trap)) { @@ -686,9 +743,8 @@ static void command_setm_cache_client(void * x) { assert(l->frame_info == NULL); if (l->size > 0) { if (context_write_reg(l->ctx, l->reg_def, l->offs, l->size, args->data + data_pos) < 0) exception(errno); + send_event_register_changed(l->id); data_pos += l->size; - l->notify = 1; - notify = 1; } } clear_trap(&trap); @@ -696,21 +752,16 @@ static void command_setm_cache_client(void * x) { cache_exit(); - if (notify) { - unsigned locs_pos = 0; - while (locs_pos < args->locs_cnt) { - Location * l = args->locs + locs_pos++; - if (l->notify) send_event_register_changed(l->id); - } + if (!is_channel_closed(c)) { + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, trap.error); + write_stream(&c->out, MARKER_EOM); } - write_stringz(&c->out, "R"); - write_stringz(&c->out, args->token); - write_errno(&c->out, trap.error); - write_stream(&c->out, MARKER_EOM); - loc_free(args->locs); loc_free(args->data); + run_ctrl_unlock(); } static void command_setm(char * token, Channel * c) { @@ -722,6 +773,7 @@ static void command_setm(char * token, Channel * c) { json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + run_ctrl_lock(); strlcpy(args.token, token, sizeof(args.token)); cache_enter(command_setm_cache_client, c, &args, sizeof(args)); } @@ -756,6 +808,10 @@ void add_registers_event_listener(RegistersEventListener * listener, void * args listener_cnt++; } +static void cache_transaction_listener(int evt) { + if (evt == CTLE_COMMIT) flush_notifications(); +} + void ini_registers_service(Protocol * proto, TCFBroadcastGroup * bcg) { broadcast_group = bcg; add_command_handler(proto, REGISTERS, "getContext", command_get_context); @@ -765,6 +821,7 @@ void ini_registers_service(Protocol * proto, TCFBroadcastGroup * bcg) { add_command_handler(proto, REGISTERS, "getm", command_getm); add_command_handler(proto, REGISTERS, "setm", command_setm); add_command_handler(proto, REGISTERS, "search", command_search); + add_cache_transaction_listener(cache_transaction_listener); } #endif /* SERVICE_Registers */ diff --git a/agent/tcf/services/runctrl.c b/agent/tcf/services/runctrl.c index 3093d37f..9f86c62b 100644 --- a/agent/tcf/services/runctrl.c +++ b/agent/tcf/services/runctrl.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. @@ -70,6 +70,7 @@ static unsigned listener_cnt = 0; static unsigned listener_max = 0; static const char RUN_CONTROL[] = "RunControl"; +static const char CONTEXT_PROXY[] = "ContextProxy"; typedef struct ContextExtensionRC { int pending_safe_event; /* safe events are waiting for this context to be stopped */ @@ -93,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; @@ -111,10 +113,16 @@ typedef struct ContextExtensionRC { } ContextExtensionRC; static size_t context_extension_offset = 0; - #define EXT(ctx) (ctx ? ((ContextExtensionRC *)((char *)(ctx) + context_extension_offset)) : NULL) #define link2ctx(lnk) ((Context *)((char *)(lnk) - offsetof(ContextExtensionRC, link) - context_extension_offset)) +typedef struct ChannelExtensionRC { + int cache_lock; +} ChannelExtensionRC; + +static size_t channel_extension_offset = 0; +#define EXT_CH(ch) ((ChannelExtensionRC *)((char *)(ch) + channel_extension_offset)) + typedef struct SafeEvent { Context * ctx; EventCallBack * done; @@ -410,7 +418,7 @@ static int is_json(const char * s) { ByteArrayInputStream buf; InputStream * inp = create_byte_array_input_stream(&buf, s, strlen(s)); json_skip_object(inp); - if (read_stream(inp) != MARKER_EOS) exception(ERR_JSON_SYNTAX); + json_test_char(inp, MARKER_EOS); clear_trap(&trap); } return trap.error == 0; @@ -425,25 +433,31 @@ static const char * get_suspend_reason(Context * ctx) { if (ext->step_error != NULL) return errno_to_str(set_error_report_errno(ext->step_error)); if (ext->step_done != NULL) return ext->step_done; reason = context_suspend_reason(ctx); - if (reason != NULL) return reason; + if (reason != NULL) return reason; 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)); @@ -486,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, ':'); @@ -622,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) { @@ -637,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(); @@ -650,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); @@ -670,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)); } @@ -839,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; @@ -870,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) { @@ -1272,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); @@ -1296,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); } } @@ -1317,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, '['); @@ -1430,12 +1489,52 @@ static void send_event_context_exception(Context * ctx) { write_stream(out, MARKER_EOM); } +int is_ctx_stopped(Context * ctx) { + if (ctx == NULL) { + errno = ERR_INV_CONTEXT; + return 0; + } + if (ctx->stopped) return 1; + if (ctx->exited) { + errno = ERR_ALREADY_EXITED; + return 0; + } + if (!context_has_state(ctx)) { + errno = ERR_INV_CONTEXT; + return 0; + } + if (EXT(ctx)->state_name) { + set_fmt_errno(ERR_OTHER, "Context %s state: %s", ctx->name ? ctx->name : ctx->id, get_context_state_name(ctx)); + return 0; + } + errno = ERR_IS_RUNNING; + return 0; +} + int is_all_stopped(Context * grp) { LINK * l; grp = context_get_group(grp, CONTEXT_GROUP_STOP); for (l = context_root.next; l != &context_root; l = l->next) { Context * ctx = ctxl2ctxp(l); if (ctx->stopped || ctx->exited || ctx->exiting) continue; + if (!context_has_state(ctx)) continue; + if (context_get_group(ctx, CONTEXT_GROUP_STOP) != grp) continue; + if (EXT(ctx)->state_name) { + set_fmt_errno(ERR_OTHER, "Context %s state: %s", ctx->name ? ctx->name : ctx->id, get_context_state_name(ctx)); + return 0; + } + errno = ERR_IS_RUNNING; + return 0; + } + return 1; +} + +static int is_all_stopped_or_cannot_stop(Context * grp) { + LINK * l; + grp = context_get_group(grp, CONTEXT_GROUP_STOP); + for (l = context_root.next; l != &context_root; l = l->next) { + Context * ctx = ctxl2ctxp(l); + if (ctx->stopped || ctx->exited || ctx->exiting) continue; if (EXT(ctx)->cannot_stop) continue; if (!context_has_state(ctx)) continue; if (context_get_group(ctx, CONTEXT_GROUP_STOP) != grp) continue; @@ -1520,13 +1619,13 @@ static int is_hidden_function(Context * ctx, ContextAddress ip, return 0; } -#if EN_STEP_OVER - static void get_machine_code_area(CodeArea * area, void * args) { *(CodeArea **)args = (CodeArea *)tmp_alloc(sizeof(CodeArea)); memcpy(*(CodeArea **)args, area, sizeof(CodeArea)); } +#if EN_STEP_OVER + static int is_within_function_epilogue(Context * ctx, ContextAddress ip) { Symbol * sym = NULL; int sym_class = SYM_CLASS_UNKNOWN; @@ -1586,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) { @@ -1607,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) { @@ -1665,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: @@ -1955,7 +2072,6 @@ static int update_step_machine_state(Context * ctx) { } } else if (addr < ext->step_range_start || addr >= ext->step_range_end) { - int same_line = 0; int function_prologue = 0; CodeArea * area = ext->step_code_area; if (area == NULL) { @@ -1970,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; } } @@ -1987,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) { @@ -1999,39 +2117,50 @@ static int update_step_machine_state(Context * ctx) { return 0; } - same_line = is_same_line(ext->step_code_area, area); - if (!same_line) { - function_prologue = is_function_prologue(ctx, addr, ext->step_code_area); - if (cache_miss_count() > 0) { - free_code_area(ext->step_code_area); - ext->step_code_area = area; - errno = ERR_CACHE_MISS; - return -1; - } + if (ext->step_code_area->start_line == 0) { + /* Clang associates some instructions in the middle of functions to line 0. + * That is valid DWARF, we need to step over such no-line-info instructions. + */ + ext->step_range_start = ext->step_code_area->start_address; + ext->step_range_end = ext->step_code_area->end_address; + free_code_area(ext->step_code_area); + ext->step_code_area = area; } - free_code_area(area); + else { + int same_line = is_same_line(ext->step_code_area, area); + if (!same_line) { + function_prologue = is_function_prologue(ctx, addr, ext->step_code_area); + if (cache_miss_count() > 0) { + free_code_area(ext->step_code_area); + ext->step_code_area = area; + errno = ERR_CACHE_MISS; + return -1; + } + } + free_code_area(area); - /* We are doing reverse step-over/into line. The first line has already been skipped, we are now trying to reach - * the beginning of previous line. If we are still on same line but have reached the beginning of the line, then we - * are done. - */ - if (same_line && do_reverse && ext->step_line_cnt > 0 && addr == ext->step_code_area->start_address) { - ext->step_done = REASON_STEP; - return 0; - } - if (!same_line && !function_prologue) { - if (!do_reverse || - (ext->step_line_cnt == 0 && addr == ext->step_code_area->start_address) || - ext->step_line_cnt >= 2) { + /* We are doing reverse step-over/into line. The first line has already been skipped, we are now trying to reach + * the beginning of previous line. If we are still on same line but have reached the beginning of the line, then we + * are done. + */ + if (same_line && do_reverse && ext->step_line_cnt > 0 && addr == ext->step_code_area->start_address) { ext->step_done = REASON_STEP; return 0; } - /* Current IP is in the middle of a source line. - * Continue stepping to get to the beginning of the line */ - ext->step_line_cnt++; + if (!same_line && !function_prologue) { + if (!do_reverse || + (ext->step_line_cnt == 0 && addr == ext->step_code_area->start_address) || + ext->step_line_cnt >= 2) { + ext->step_done = REASON_STEP; + return 0; + } + /* Current IP is in the middle of a source line. + * Continue stepping to get to the beginning of the line */ + ext->step_line_cnt++; + } + ext->step_range_start = ext->step_code_area->start_address; + ext->step_range_end = ext->step_code_area->end_address; } - ext->step_range_start = ext->step_code_area->start_address; - ext->step_range_end = ext->step_code_area->end_address; /* When doing reverse step-into/over line, if we have already skipped the first line, we want to reach * the beginning of current line, fix step range to handle this. @@ -2049,7 +2178,7 @@ static int update_step_machine_state(Context * ctx) { return 0; } if (address_to_line(ctx, addr, addr + 1, get_machine_code_area, &area) < 0) return -1; - if (area == NULL || !is_function_prologue(ctx, addr, area)) { + if (area == NULL || (area->start_line != 0 && !is_function_prologue(ctx, addr, area))) { if (cache_miss_count() > 0) { errno = ERR_CACHE_MISS; return -1; @@ -2063,6 +2192,29 @@ static int update_step_machine_state(Context * ctx) { #endif /* EN_STEP_LINE */ case RM_STEP_OUT: case RM_REVERSE_STEP_OUT: +#if EN_STEP_LINE + { + /* Clang associates some instructions in the middle of functions to line 0. + * That is valid DWARF, we need to step over such no-line-info instructions. + */ + CodeArea * area = NULL; + if (address_to_line(ctx, addr, addr + 1, get_machine_code_area, &area) < 0) return -1; + if (area != NULL && area->start_line == 0) { + ext->step_range_start = area->start_address; + ext->step_range_end = area->end_address; + switch (ext->step_mode) { + case RM_STEP_OUT: + if (context_can_resume(ctx, ext->step_continue_mode = RM_STEP_INTO_RANGE)) return 0; + if (context_can_resume(ctx, ext->step_continue_mode = RM_STEP_INTO)) return 0; + break; + case RM_REVERSE_STEP_OUT: + if (context_can_resume(ctx, ext->step_continue_mode = RM_REVERSE_STEP_INTO_RANGE)) return 0; + if (context_can_resume(ctx, ext->step_continue_mode = RM_REVERSE_STEP_INTO)) return 0; + break; + } + } + } +#endif /* EN_STEP_LINE */ ext->step_done = REASON_STEP; return 0; default: @@ -2099,12 +2251,14 @@ static int update_step_machine_state(Context * ctx) { if (context_can_resume(ctx, ext->step_continue_mode = RM_STEP_INTO)) return 0; break; case RM_STEP_OVER_RANGE: + if (context_can_resume(ctx, ext->step_continue_mode = RM_STEP_OVER)) return 0; if (context_can_resume(ctx, ext->step_continue_mode = RM_STEP_INTO_RANGE)) return 0; break; case RM_REVERSE_STEP_OVER: if (context_can_resume(ctx, ext->step_continue_mode = RM_REVERSE_STEP_INTO)) return 0; break; case RM_REVERSE_STEP_OVER_RANGE: + if (context_can_resume(ctx, ext->step_continue_mode = RM_REVERSE_STEP_OVER)) return 0; if (context_can_resume(ctx, ext->step_continue_mode = RM_REVERSE_STEP_INTO_RANGE)) return 0; break; case RM_SKIP_PROLOGUE: @@ -2202,15 +2356,22 @@ static void check_step_breakpoint_instances(InputStream * inp, void * args) { static int check_step_breakpoint(Context * ctx) { #if SERVICE_Breakpoints /* Return error if step machine breakpoint cannot be planted */ + Trap trap; int error = 0; char * status = NULL; - ByteArrayInputStream buf; - InputStream * inp = NULL; ContextExtensionRC * ext = EXT(ctx); if (ext->step_bp_info == NULL) return 0; status = get_breakpoint_status(ext->step_bp_info); - inp = create_byte_array_input_stream(&buf, status, strlen(status)); - json_read_struct(inp, check_step_breakpoint_status, &error); + if (set_trap(&trap)) { + ByteArrayInputStream buf; + InputStream * inp = create_byte_array_input_stream(&buf, status, strlen(status)); + json_read_struct(inp, check_step_breakpoint_status, &error); + json_test_char(inp, MARKER_EOS); + clear_trap(&trap); + } + else { + error = trap.error; + } loc_free(status); if (!error) return 0; errno = error; @@ -2242,17 +2403,17 @@ static Channel * select_skip_prologue_channel(void) { #endif #ifndef NDEBUG -extern int print_not_stopped_contexts(Context * ctx) { +int print_not_stopped_contexts(Context * ctx) { LINK * l; Context * grp; - if (is_all_stopped(ctx)) return 1; + if (is_all_stopped_or_cannot_stop(ctx)) return 1; grp = context_get_group(ctx, CONTEXT_GROUP_STOP); fprintf(stderr, "Context group '%s':\n", grp->name ? grp->name : grp->id); for (l = context_root.next; l != &context_root; l = l->next) { Context * c = ctxl2ctxp(l); if (context_get_group(c, CONTEXT_GROUP_STOP) != grp) continue; - fprintf(stderr, " ID %s, stopped %d, exiting %d, exited %d, signal %d\n", - c->id, c->stopped, c->exiting, c->exited, c->signal); + fprintf(stderr, " ID %s, stopped %d, exiting %d, exited %d, signal %d, cannot stop %d\n", + c->id, c->stopped, c->exiting, c->exited, c->signal, EXT(c)->cannot_stop); } return 0; } @@ -2378,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 */ @@ -2407,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--; @@ -2444,18 +2603,28 @@ static void run_safe_events(void * arg) { if (safe_event_list == NULL) return; safe_event_pid_count = 0; + i = safe_event_list; + while (i != NULL) { + ContextExtensionRC * ext = EXT(i->ctx); + assert(i->ctx->ref_count > 0); + ext->stop_group_ctx = NULL; + ext->stop_group_mark = 0; + i = i->next; + } l = context_root.next; while (l != &context_root) { Context * ctx = ctxl2ctxp(l); ContextExtensionRC * ext = EXT(ctx); ext->stop_group_ctx = context_get_group(ctx, CONTEXT_GROUP_STOP); ext->stop_group_mark = 0; + assert(ext->stop_group_ctx != NULL); l = l->next; } i = safe_event_list; while (i != NULL) { Context * grp = EXT(i->ctx)->stop_group_ctx; - EXT(grp)->stop_group_mark = 1; + /* 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; } l = context_root.next; @@ -2464,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; @@ -2523,6 +2693,8 @@ static void run_safe_events(void * arg) { safe_event_list = i->next; if (safe_event_list == NULL) safe_event_last = NULL; if (i->done != NULL) { + assert(EXT(i->ctx)->stop_group_mark); + assert(!EXT(i->ctx)->pending_safe_event); safe_event_active = 1; if (set_trap(&trap)) { i->done(i->arg); @@ -2577,7 +2749,7 @@ int is_safe_event(void) { } void check_all_stopped(Context * ctx) { - if (is_all_stopped(ctx)) return; + if (is_all_stopped_or_cannot_stop(ctx)) return; post_safe_event(ctx, NULL, NULL); cache_wait(&safe_events_cache); } @@ -2718,9 +2890,9 @@ void rem_run_control_event_listener(RunControlEventListener * listener) { static void stop_if_safe_events(Context * ctx) { ContextExtensionRC * ext = EXT(ctx); if (safe_event_active && EXT(ctx)->stop_group_mark && - !ctx->exiting && !ctx->stopped && context_has_state(ctx)) { + !ctx->exiting && context_has_state(ctx)) { assert(run_ctrl_lock_cnt > 0); - if (!ext->safe_single_step) { + if (!ext->safe_single_step && !ctx->stopped) { context_stop(ctx); } if (!ext->pending_safe_event) { @@ -2755,8 +2927,8 @@ static void clear_context_proxy_cache(Context * ctx) { int i; for (i = 0; i < c->peer_service_cnt; i++) { char * nm = c->peer_service_list[i]; - if (strcmp(nm, "ContextProxy") == 0) { - protocol_send_command(c, "ContextProxy", "clear", context_proxy_reply, NULL); + if (strcmp(nm, CONTEXT_PROXY) == 0) { + protocol_send_command(c, CONTEXT_PROXY, "clear", context_proxy_reply, NULL); json_write_string(&c->out, ctx->id); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -2815,12 +2987,38 @@ static void event_context_exited(Context * ctx, void * args) { } static void channel_closed(Channel * c) { + ChannelExtensionRC * ext_ch = EXT_CH(c); LINK * l; for (l = context_root.next; l != &context_root; l = l ->next) { Context * ctx = ctxl2ctxp(l); ContextExtensionRC * ext = EXT(ctx); if (ext->step_channel == c) cancel_step_mode(ctx); } + if (ext_ch->cache_lock) { + ext_ch->cache_lock = 0; + run_ctrl_unlock(); + } +} + +static void context_cache_lock(Channel * c) { + ChannelExtensionRC * ext = EXT_CH(c); + json_test_char(&c->inp, MARKER_EOM); + assert(ext->cache_lock == 0); + ext->cache_lock = 1; + run_ctrl_lock(); +} + +static void context_cache_unlock(Channel * c) { + ChannelExtensionRC * ext = EXT_CH(c); + json_test_char(&c->inp, MARKER_EOM); + assert(ext->cache_lock == 1); + ext->cache_lock = 0; + run_ctrl_unlock(); +} + +static void channel_opened(Channel * c) { + add_event_handler(c, CONTEXT_PROXY, "lock", context_cache_lock); + add_event_handler(c, CONTEXT_PROXY, "unlock", context_cache_unlock); } static void event_context_disposed(Context * ctx, void * args) { @@ -2845,6 +3043,28 @@ static int cmp_parent_id(Context * ctx, const char * v) { return ctx->parent != NULL && strcmp(ctx->parent->id, v) == 0; } +static int cmp_parent_name(Context * ctx, const char * v) { + return ctx->parent != NULL && strcmp(ctx->parent->name ? ctx->parent->name : ctx->parent->id, v) == 0; +} + +static int cmp_ancestor_id(Context * ctx, const char * v) { + ctx = ctx->parent; + while (ctx != NULL) { + if (strcmp(ctx->id, v) == 0) return 1; + ctx = ctx->parent; + } + return 0; +} + +static int cmp_ancestor_name(Context * ctx, const char * v) { + ctx = ctx->parent; + while (ctx != NULL) { + if (strcmp(ctx->name ? ctx->name : ctx->id, v) == 0) return 1; + ctx = ctx->parent; + } + return 0; +} + static int cmp_creator_id(Context * ctx, const char * v) { return ctx->creator != NULL && strcmp(ctx->creator->id, v) == 0; } @@ -2866,10 +3086,13 @@ void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg) { broadcast_group = bcg; add_context_event_listener(&listener, NULL); add_channel_close_listener(channel_closed); + add_channel_open_listener(channel_opened); context_extension_offset = context_extension(sizeof(ContextExtensionRC)); + channel_extension_offset = channel_extension(sizeof(ChannelExtensionRC)); 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 @@ -2879,8 +3102,51 @@ void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg) { add_command_handler(proto, RUN_CONTROL, "detach", command_detach); add_context_query_comparator("HasState", cmp_has_state); add_context_query_comparator("ParentID", cmp_parent_id); + add_context_query_comparator("ParentName", cmp_parent_name); + add_context_query_comparator("AncestorID", cmp_ancestor_id); + add_context_query_comparator("AncestorName", cmp_ancestor_name); add_context_query_comparator("CreatorID", cmp_creator_id); add_context_query_comparator("ProcessID", cmp_process_id); } +#else + +#include <tcf/services/runctrl.h> + +int is_ctx_stopped(Context * ctx) { +#if ENABLE_DebugContext + if (ctx == NULL) { + errno = ERR_INV_CONTEXT; + return 0; + } + if (ctx->stopped) return 1; + if (ctx->exited) { + errno = ERR_ALREADY_EXITED; + return 0; + } + if (!context_has_state(ctx)) { + errno = ERR_INV_CONTEXT; + return 0; + } +#endif + errno = ERR_IS_RUNNING; + return 0; +} + +int is_all_stopped(Context * grp) { +#if ENABLE_DebugContext + LINK * l; + grp = context_get_group(grp, CONTEXT_GROUP_STOP); + for (l = context_root.next; l != &context_root; l = l->next) { + Context * ctx = ctxl2ctxp(l); + if (ctx->stopped || ctx->exited || ctx->exiting) continue; + if (!context_has_state(ctx)) continue; + if (context_get_group(ctx, CONTEXT_GROUP_STOP) != grp) continue; + errno = ERR_IS_RUNNING; + return 0; + } +#endif + return 1; +} + #endif /* SERVICE_RunControl */ diff --git a/agent/tcf/services/runctrl.h b/agent/tcf/services/runctrl.h index c1f1abab..d6d414ad 100644 --- a/agent/tcf/services/runctrl.h +++ b/agent/tcf/services/runctrl.h @@ -126,9 +126,16 @@ extern int print_not_stopped_contexts(Context * ctx); extern void wait_safe_events_done(void); /* - * Return 1 if all threads in a debuggee are stopped and handling of incoming messages - * is suspended, and it is safe to access debuggee memory, plant breakpoints, etc. + * Return 1 the context is stopped. + * Return 0 and set errno if not stopped. + */ +extern int is_ctx_stopped(Context * ctx); + +/* + * Return 1 if all threads in a debuggee are stopped and it is safe to access + * debuggee memory, plant breakpoints, etc. * Only threads that belong to CONTEXT_GROUP_STOP of 'ctx' are checked. + * Return 0 and set errno if not all stopped. */ extern int is_all_stopped(Context * ctx); @@ -232,6 +239,8 @@ extern void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg); #define is_safe_event() 0 #define post_safe_event(ctx, done, arg) ((void)ctx, post_event(done, arg)) #define check_all_stopped(x) do {} while(0) +extern int is_ctx_stopped(Context * ctx); +extern int is_all_stopped(Context * ctx); #endif /* SERVICE_RunControl */ 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 4434300c..cac913e8 100644 --- a/agent/tcf/services/stacktrace.c +++ b/agent/tcf/services/stacktrace.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2017 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. @@ -32,6 +32,7 @@ #include <tcf/framework/cache.h> #include <tcf/framework/exceptions.h> #include <tcf/services/registers.h> +#include <tcf/services/runctrl.h> #include <tcf/services/symbols.h> #include <tcf/services/linenumbers.h> #include <tcf/services/memorymap.h> @@ -78,13 +79,9 @@ static void free_frame(StackFrame * frame) { errno = error; } -static int get_frame_debug_info(StackFrame * frame, StackTracingInfo ** info) { - uint64_t ip = 0; +#if ENABLE_Symbols +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) { @@ -97,7 +94,6 @@ static int get_frame_debug_info(StackFrame * frame, StackTracingInfo ** info) { if (up->is_walked) { ip--; } -#if ENABLE_Symbols else { /* Workaround for missing frame info for return address of a function that never returns */ Symbol * sym = NULL; @@ -112,28 +108,58 @@ static int get_frame_debug_info(StackFrame * frame, StackTracingInfo ** info) { ip--; } } -#endif } } return get_stack_tracing_info(ctx, (ContextAddress)ip, 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"); @@ -141,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)); @@ -153,7 +178,7 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) { StackFrame * prev = stk->frames + stk->frame_cnt - 1; down->ctx = ctx; down->fp = frame->fp; - while (def->name != NULL) { + while (def && def->name) { if (def->dwarf_id >= 0) { #if ENABLE_StackRegisterLocations cmd.args.reg = def; @@ -165,7 +190,7 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) { #endif if (buf_size < def->size) buf = (uint8_t *)tmp_realloc(buf, buf_size = def->size); if (read_reg_bytes(prev, def, 0, def->size, buf) == 0) { - write_reg_bytes(down, def, 0, def->size, buf); + if (write_reg_bytes(down, def, 0, def->size, buf) < 0) exception(errno); down->has_reg_data = 1; } } @@ -185,41 +210,41 @@ 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); frame->is_walked = 1; } @@ -230,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; } @@ -267,7 +296,7 @@ static void trace_stack(Context * ctx, StackTrace * stack, int max_frames) { uint64_t v; RegisterDefinition * def; trace(LOG_STACK, "Frame %d", stack->frame_cnt - 1); - for (def = get_reg_definitions(ctx); def->name != NULL; def++) { + for (def = get_reg_definitions(ctx); def && def->name; def++) { if (def->no_read || def->read_once || def->bits || !def->size) continue; if (read_reg_value(frame, def, &v) != 0) continue; trace(LOG_STACK, " %-8s %16" PRIx64, def->name, v); @@ -276,7 +305,7 @@ static void trace_stack(Context * ctx, StackTrace * stack, int max_frames) { #endif if (get_next_stack_frame(frame, &down) < 0) { if (cache_miss_count() > 0) break; - trace(LOG_ALWAYS, "Stack trace error: %s", errno_to_str(errno)); + trace(LOG_STACK, "Stack trace error: %s", errno_to_str(errno)); } frame = stack->frames + frame_idx; /* stack->frames might be realloc-ed */ if (frame->is_walked == 0) { @@ -306,16 +335,14 @@ static void trace_stack(Context * ctx, StackTrace * stack, int max_frames) { uint8_t * buf0 = (uint8_t *)tmp_alloc(buf_size); uint8_t * buf1 = (uint8_t *)tmp_alloc(buf_size); RegisterDefinition * def; - for (def = get_reg_definitions(ctx); def->name != NULL; def++) { - int f0, f1; + for (def = get_reg_definitions(ctx); def && def->name; def++) { 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; } @@ -469,8 +496,8 @@ static void command_get_context_cache_client(void * x) { err = errno; break; } - if (!d->ctx->stopped) { - err = ERR_IS_RUNNING; + if (!is_ctx_stopped(d->ctx)) { + err = errno; break; } assert(d->frame >= 0); @@ -548,8 +575,8 @@ static void command_get_children_cache_client(void * x) { if (ctx == NULL || !context_has_state(ctx)) { /* no children */ } - else if (!ctx->stopped) { - err = ERR_IS_RUNNING; + else if (!is_ctx_stopped(ctx)) { + err = errno; } else if (args->all_frames) { stack = create_stack_trace(ctx, MAX_FRAMES); @@ -626,22 +653,14 @@ static void command_get_children_range(char * token, Channel * c) { } int get_top_frame(Context * ctx) { - - if (!ctx->stopped) { - errno = ERR_IS_RUNNING; - return STACK_TOP_FRAME; - } - + if (!is_ctx_stopped(ctx)) return STACK_TOP_FRAME; return 0; } int get_bottom_frame(Context * ctx) { StackTrace * stack; - if (!ctx->stopped) { - errno = ERR_IS_RUNNING; - return STACK_BOTTOM_FRAME; - } + if (!is_ctx_stopped(ctx)) return STACK_BOTTOM_FRAME; stack = create_stack_trace(ctx, MAX_FRAMES); if (stack == NULL) return STACK_BOTTOM_FRAME; @@ -694,14 +713,7 @@ int get_frame_info(Context * ctx, int frame, StackFrame ** info) { int max_frames = 0; *info = NULL; - if (ctx == NULL || !context_has_state(ctx)) { - errno = ERR_INV_CONTEXT; - return -1; - } - if (!ctx->stopped) { - errno = ERR_IS_RUNNING; - return -1; - } + if (!is_ctx_stopped(ctx)) return -1; if (frame >= 0) max_frames = frame + 1; else if (frame == STACK_TOP_FRAME) max_frames = 1; @@ -786,7 +798,8 @@ static void delete_stack_trace(Context * ctx, void * args) { memset(EXT(ctx), 0, sizeof(StackTrace)); } -static void event_map_changed(Context * ctx, void * client_data) { +#if SERVICE_MemoryMap +static void event_map_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 invalidate * stack traces on all members of the group, since they can @@ -801,40 +814,45 @@ static void event_map_changed(Context * ctx, void * client_data) { } } } +#endif void ini_stack_trace_service(Protocol * proto, TCFBroadcastGroup * bcg) { - static ContextEventListener context_listener = { - NULL, - flush_stack_trace, - NULL, - flush_stack_trace, - flush_stack_trace, - delete_stack_trace - }; + static int ini_done = 0; + if (!ini_done) { + static ContextEventListener context_listener = { + NULL, + flush_stack_trace, + NULL, + flush_stack_trace, + flush_stack_trace, + delete_stack_trace + }; #if SERVICE_Registers - static RegistersEventListener registers_listener = { - flush_on_register_change, - }; + static RegistersEventListener registers_listener = { + flush_on_register_change, + }; #endif #if SERVICE_MemoryMap - static MemoryMapEventListener map_listener = { - NULL, - NULL, - NULL, - event_map_changed, - }; + static MemoryMapEventListener map_listener = { + NULL, + NULL, + NULL, + event_map_changed, + }; #endif - add_context_event_listener(&context_listener, bcg); + ini_done = 1; + add_context_event_listener(&context_listener, NULL); #if SERVICE_Registers - add_registers_event_listener(®isters_listener, bcg); + add_registers_event_listener(®isters_listener, NULL); #endif #if SERVICE_MemoryMap - add_memory_map_event_listener(&map_listener, NULL); + add_memory_map_event_listener(&map_listener, NULL); #endif + context_extension_offset = context_extension(sizeof(StackTrace)); + } add_command_handler(proto, STACKTRACE, "getContext", command_get_context); add_command_handler(proto, STACKTRACE, "getChildren", command_get_children); add_command_handler(proto, STACKTRACE, "getChildrenRange", command_get_children_range); - context_extension_offset = context_extension(sizeof(StackTrace)); } #endif diff --git a/agent/tcf/services/streamsservice.c b/agent/tcf/services/streamsservice.c index 95a6fdf0..65e5f165 100644 --- a/agent/tcf/services/streamsservice.c +++ b/agent/tcf/services/streamsservice.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2009-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. @@ -152,7 +152,7 @@ static StreamClient * find_client(char * s, Channel * c) { l = l->next; } } - errno = set_fmt_errno(ERR_OTHER, "No such stream: %s", s); + set_fmt_errno(ERR_OTHER, "No such stream: %s", s); return NULL; } @@ -673,7 +673,6 @@ int virtual_stream_read(Channel * c, char * token, char * id, size_t size) { VirtualStream * stream = client->stream; if (client->pos == stream->pos && !stream->eos_inp) { ReadRequest * r = (ReadRequest *)loc_alloc_zero(sizeof(ReadRequest)); - list_init(&r->link_client); r->client = client; r->size = size; strlcpy(r->token, token, sizeof(r->token)); @@ -722,66 +721,78 @@ static void command_read(char * token, Channel * c) { } int virtual_stream_write(Channel * c, char * token, char * id, size_t size, InputStream * inp) { - char * data = NULL; int err = 0; - long offs = 0; + size_t offs = 0; StreamClient * client = find_client(id, c); + JsonReadBinaryState state; + size_t data_pos = 0; + char * data = NULL; + char buf[256]; if (client == NULL) err = errno; if (!err && (client->stream->access & VS_ENABLE_REMOTE_WRITE) == 0) err = ERR_UNSUPPORTED; - { - JsonReadBinaryState state; - size_t data_pos = 0; + if (!err && !list_is_empty(&client->write_requests)) data = (char *)loc_alloc(size); - if (!err && !list_is_empty(&client->write_requests)) data = (char *)loc_alloc(size); - - json_read_binary_start(&state, inp); - for (;;) { - if (data != NULL) { - size_t rd = json_read_binary_data(&state, data + data_pos, size - offs - data_pos); - if (rd == 0) break; - data_pos += rd; - } - else { - char buf[256]; - size_t rd = json_read_binary_data(&state, buf, sizeof(buf)); - if (rd == 0) break; - if (!err) { - size_t done = 0; - if (virtual_stream_add_data(client->stream, buf, rd, &done, 0) < 0) err = errno; - assert(done <= rd); - offs += done; - if (!err && done < rd) { - data = (char *)loc_alloc(size - offs); - memcpy(data, buf + done, rd - done); - data_pos = rd - done; - } - } + json_read_binary_start(&state, inp); + for (;;) { + if (err || offs + data_pos >= size) { + size_t rd = json_read_binary_data(&state, buf, sizeof(buf)); + if (rd == 0) break; + } + else if (data != NULL) { + size_t rd = json_read_binary_data(&state, data + data_pos, size - offs - data_pos); + assert(state.size_done == offs + data_pos + rd); + if (rd == 0) break; + data_pos += rd; + } + else { + size_t done = 0; + size_t rd = json_read_binary_data(&state, buf, sizeof(buf)); + if (rd == 0) break; + assert(data_pos == 0); + assert(state.size_done == offs + rd || offs == size); + if (offs + rd > size) rd = size - offs; + if (virtual_stream_add_data(client->stream, buf, rd, &done, 0) < 0) err = errno; + assert(done <= rd); + offs += done; + if (done < rd && !err) { + assert(size > offs); + data = (char *)loc_alloc(size - offs); + memcpy(data, buf + done, rd - done); + data_pos = rd - done; } } - json_read_binary_end(&state); + } + json_read_binary_end(&state); + + if (!err && state.size_done != size) { + err = ERR_INV_DATA_SIZE; + loc_free(data); + data = NULL; } if (data != NULL) { WriteRequest * r = (WriteRequest *)loc_alloc_zero(sizeof(WriteRequest)); - list_init(&r->link_client); + assert(err == 0); r->client = client; r->data = data; r->size = size - offs; strlcpy(r->token, token, sizeof(r->token)); list_add_last(&r->link_client, &client->write_requests); + return 0; } - else if (err == 0) { + + if (err == 0) { write_stringz(&c->out, "R"); write_stringz(&c->out, token); - write_errno(&c->out, err); + write_errno(&c->out, 0); write_stream(&c->out, MARKER_EOM); + return 0; } - if (err != 0) errno = err; - - return err == 0 ? 0 : -1; + errno = err; + return -1; } static void command_write(char * token, Channel * c) { @@ -800,8 +811,8 @@ static void command_write(char * token, Channel * c) { if (err != 0) { /* - * Handle reply with an error. If none error was detected, the reply - * was sent back by virtual_stream_write() or delayed. + * Handle reply with an error. If no error was detected, the reply + * was either sent back by virtual_stream_write() or delayed. */ write_stringz(&c->out, "R"); write_stringz(&c->out, token); @@ -822,22 +833,24 @@ int virtual_stream_eos(Channel * c, char * token, char * id) { if (!err && r == NULL && virtual_stream_add_data(client->stream, NULL, 0, &done, 1) < 0) err = errno; if (r != NULL) { - list_init(&r->link_client); + assert(err == 0); r->client = client; r->eos = 1; strlcpy(r->token, token, sizeof(r->token)); list_add_last(&r->link_client, &client->write_requests); + return 0; } - else if (err == 0) { + + if (err == 0) { write_stringz(&c->out, "R"); write_stringz(&c->out, token); - write_errno(&c->out, err); + write_errno(&c->out, 0); write_stream(&c->out, MARKER_EOM); + return 0; } - if (err != 0) errno = err; - - return err == 0 ? 0 : -1; + errno = err; + return -1; } static void command_eos(char * token, Channel * c) { @@ -852,8 +865,8 @@ static void command_eos(char * token, Channel * c) { if (err != 0) { /* - * Handle reply with an error. If none error was detected, the reply - * was sent back by virtual_stream_eos() or delayed. + * Handle reply with an error. If no error was detected, the reply + * was either sent back by virtual_stream_eos() or delayed. */ write_stringz(&c->out, "R"); write_stringz(&c->out, token); 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_common.c b/agent/tcf/services/symbols_common.c index 579cdda3..844c3d61 100644 --- a/agent/tcf/services/symbols_common.c +++ b/agent/tcf/services/symbols_common.c @@ -83,7 +83,7 @@ int get_symbol_offset(const Symbol * sym, ContextAddress * offset) { if (loc_info->args_cnt == 1) { /* Relative location. Only static offset can be returned. * Dynamic offset can only be computed in an expression. */ - if (loc_info->value_cmds.cnt == 3 && + if (loc_info->value_cmds.cnt == 3 && loc_info->code_size == 0 && loc_info->value_cmds.cmds[0].cmd == SFT_CMD_ARG && loc_info->value_cmds.cmds[1].cmd == SFT_CMD_NUMBER && loc_info->value_cmds.cmds[2].cmd == SFT_CMD_ADD) { diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c index fdee5deb..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. @@ -44,8 +44,10 @@ #include <tcf/services/memorymap.h> #include <tcf/services/funccall.h> #include <tcf/services/pathmap.h> +#include <tcf/services/runctrl.h> #include <tcf/services/symbols.h> #include <tcf/services/elf-symbols.h> +#include <tcf/services/elf-loader.h> #include <tcf/services/vm.h> #if ENABLE_SymbolsMux #define SYM_READER_PREFIX elf_reader_ @@ -86,6 +88,7 @@ struct Symbol { #define is_array_type_pseudo_symbol(s) (s->sym_class == SYM_CLASS_TYPE && s->obj == NULL && s->base != NULL) #define is_std_type_pseudo_symbol(s) (s->sym_class == SYM_CLASS_TYPE && s->obj == NULL && s->base == NULL) #define is_constant_pseudo_symbol(s) (s->sym_class == SYM_CLASS_VALUE && s->obj == NULL && s->base != NULL) +#define is_pointer_pseudo_symbol(s) (s->sym_class == SYM_CLASS_VALUE && s->obj == NULL && s->base == NULL && s->has_address) static Context * sym_ctx; static int sym_frame; @@ -157,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 } }; @@ -165,8 +181,6 @@ static struct BaseTypeAlias { #define equ_symbol_names(x, y) (*x == *y && cmp_symbol_names(x, y) == 0) #define check_in_range(obj, addr) dwarf_check_in_range(obj, (addr)->section, (addr)->lt_addr) -static int map_to_sym_table(ObjectInfo * obj, Symbol ** sym); - /* This function is used for DWARF reader testing */ extern ObjectInfo * get_symbol_object(Symbol * sym); ObjectInfo * get_symbol_object(Symbol * sym) { @@ -209,14 +223,7 @@ static int get_sym_context(Context * ctx, int frame, ContextAddress addr) { sym_ip = addr; } else if (is_top_frame(ctx, frame)) { - if (!ctx->stopped) { - errno = ERR_IS_RUNNING; - return -1; - } - if (ctx->exited) { - errno = ERR_ALREADY_EXITED; - return -1; - } + if (!is_ctx_stopped(ctx)) return -1; if (get_PC(ctx, &sym_ip) < 0) return -1; } else { @@ -319,7 +326,12 @@ int elf_tcf_symbol(Context * ctx, ELF_SymbolInfo * sym_info, Symbol ** symbol) { Symbol * sym = alloc_symbol(); sym->frame = STACK_NO_FRAME; - sym->ctx = context_get_group(ctx, CONTEXT_GROUP_SYMBOLS); + if (sym_info->type == STT_TLS) { + sym->ctx = ctx; + } + else { + sym->ctx = context_get_group(ctx, CONTEXT_GROUP_SYMBOLS); + } sym->tbl = sym_info->sym_section; sym->index = sym_info->sym_index; sym->dynsym = sym->tbl->type == SHT_DYNSYM; @@ -351,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); @@ -429,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; @@ -461,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; @@ -1023,6 +1039,8 @@ static int symbol_has_location(Symbol * sym) { unpack_elf_symbol_info(sym->tbl, sym->index, &info); if (info.section_index == SHN_UNDEF) return 0; if (info.section_index == SHN_COMMON) return 0; + if (info.type == STT_TLS && !context_has_state(sym->ctx)) return 0; + if (info.type == STT_COMMON) return 0; } return 1; } @@ -1034,10 +1052,55 @@ static int symbol_has_location(Symbol * sym) { /* AT_location defined, so we have an address */ return 1; } + if (sym->obj->mFlags & DOIF_data_location) { + return 1; + } if (sym->obj->mFlags & DOIF_low_pc) { /* AT_low_pc defined, so we have an address */ return 1; } + if (sym->obj->mFlags & DOIF_external) { + /* No location info in DWARF, check ELF symbols for symbol address */ + /* Do not call map_to_sym_table() - infinite recursion */ + ELF_File * file = sym->obj->mCompUnit->mFile; + if (file->debug_info_file) { + size_t n = strlen(file->name); + if (n > 6 && strcmp(file->name + n - 6, ".debug") == 0) { + char * fnm = (char *)tmp_alloc_zero(n); + memcpy(fnm, file->name, n - 6); + fnm = canonicalize_file_name(fnm); + if (fnm != NULL) { + file = elf_open(fnm); + free(fnm); + } + } + } + if (file != NULL) { + const char * name = get_linkage_name(sym->obj); + if (name != NULL) { + unsigned m = 0; + unsigned h = calc_symbol_name_hash(name); + for (m = 1; m < file->section_cnt; m++) { + unsigned n; + ELF_Section * tbl = file->sections + m; + if (tbl->sym_names_hash == NULL) continue; + n = tbl->sym_names_hash[h % tbl->sym_names_hash_size]; + while (n) { + ELF_SymbolInfo info; + unpack_elf_symbol_info(tbl, n, &info); + n = tbl->sym_names_next[n]; + if (equ_symbol_names(name, info.name) && info.bind == STB_GLOBAL) { + if (info.section_index == SHN_UNDEF) continue; + if (info.section_index == SHN_COMMON) continue; + if (info.type == STT_TLS && !context_has_state(sym->ctx)) continue; + if (info.type == STT_COMMON) continue; + return 1; + } + } + } + } + } + } } return 0; } @@ -1326,10 +1389,16 @@ static int find_in_object_tree(ObjectInfo * parent, unsigned level, while (obj != NULL) { if (obj->mTag != TAG_GNU_call_site) { if (obj->mName != NULL && equ_symbol_names(obj->mName, name)) { - /* Skip out-of-body definitions */ - ObjectInfo * container = NULL; - if (get_object_scope(obj, &container) < 0) exception(errno); - if (container == parent) add_obj_to_find_symbol_buf(find_definition(obj), level); + if (obj->mTag == TAG_lexical_block && parent->mTag == TAG_subprogram && + parent->mName != NULL && strcmp(obj->mName, parent->mName) == 0) { + /* Bad representation of inlined recursive function, skip */ + } + else { + /* Skip out-of-body definitions */ + ObjectInfo * container = NULL; + if (get_object_scope(obj, &container) < 0) exception(errno); + if (container == parent) add_obj_to_find_symbol_buf(find_definition(obj), level); + } } if (parent->mTag == TAG_subprogram && ip != 0) { if (!obj_ptr_chk) { @@ -1497,6 +1566,66 @@ static void find_by_name_in_sym_table(ELF_File * file, const char * name, int gl } } +static void find_relocate(ELF_File * file, const char * name) { + /* Psedo-symbol, which helps debugger to map link-time address to run-time address */ + size_t l = strlen(file->name); + size_t i = 0; + int ok = 0; + if (strncmp(file->name, name, l) == 0 && name[l] == ':') { + i = l + 1; + ok = 1; + } + if (!ok) { + size_t p = l; + while (p > 0 && file->name[p - 1] != '/' && file->name[p - 1] != '\\') p--; + if (strncmp(file->name + p, name, l - p) == 0 && name[l - p] == ':') { + i = l - p + 1; + ok = 1; + } + } + if (ok) { + size_t j = i; + char * section_name = NULL; + while (name[j] != 0 && name[j] != ':') j++; + if (j > i) section_name = tmp_strndup(name + i, j - i); + if (name[j++] == ':') { + ELF_Section * section = NULL; + ContextAddress addr = 0; + for (;;) { + char ch = name[j++]; + if (ch >= '0' && ch <= '9') addr = (addr << 4) | (ch - '0'); + else if (ch >= 'A' && ch <= 'F') addr = (addr << 4) | (ch - 'A' + 10); + else if (ch >= 'a' && ch <= 'f') addr = (addr << 4) | (ch - 'a' + 10); + else break; + } + if (section_name != NULL) { + unsigned n; + for (n = 1; n < file->section_cnt; n++) { + ELF_Section * s = file->sections + n; + if (s->name == NULL) continue; + if (strcmp(s->name, section_name) == 0) { + section = s; + break; + } + } + if (section == NULL) return; + } + addr = elf_map_to_run_time_address(sym_ctx, file, section, addr); + if (errno == 0) { + Symbol * sym = alloc_symbol(); + sym->ctx = context_get_group(sym_ctx, CONTEXT_GROUP_SYMBOLS); + sym->frame = STACK_NO_FRAME; + sym->sym_class = SYM_CLASS_VALUE; + sym->address = addr; + sym->size = file->elf64 ? 8 : 4; + sym->has_address = 1; + assert(is_pointer_pseudo_symbol(sym)); + add_to_find_symbol_buf(sym); + } + } + } +} + int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, const char * name, Symbol ** res) { int error = 0; ELF_File * curr_file = NULL; @@ -1631,28 +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)); - find_by_name_in_pub_names(cache, name); - find_by_name_in_sym_table(file, name, 0); - clear_trap(&trap); - } - else { - error = trap.error; - break; - } + 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; } - file = elf_list_next(sym_ctx); + 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 { + error = trap.error; + break; + } + } + 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) { @@ -1812,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; @@ -2319,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, @@ -2338,10 +2540,21 @@ int get_context_isa(Context * ctx, ContextAddress ip, const char ** isa, /* TODO: faster handling of ARM mapping symbols */ ELF_SymbolInfo sym_info; elf_find_symbol_by_address(sec, lt_addr, &sym_info); + if (sym_info.type16bit && sym_info.value + sym_info.size > lt_addr) { + *isa = "Thumb"; + assert(sym_info.size > 0); + assert(sym_info.value <= lt_addr); + *range_addr = (ContextAddress)sym_info.value; + if (file->type == ET_REL) *range_addr += (ContextAddress)sec->addr; + *range_addr += ip - lt_addr; + *range_size = sym_info.size; + return 0; + } while (sym_info.sym_section != NULL) { 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"; @@ -2352,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; @@ -2359,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; @@ -2391,7 +2611,7 @@ int get_context_isa(Context * ctx, ContextAddress ip, const char ** isa, case EM_V800 : *isa = "V800"; break; case EM_V850 : *isa = "V850"; break; case EM_AARCH64 : *isa = "A64"; break; - case EM_RISCV : *isa = file->elf64 ? "Riscv64" : NULL; break; + case EM_RISCV : *isa = file->elf64 ? "Riscv64" : "Riscv32"; break; } } { @@ -2424,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)); @@ -2493,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; } } @@ -2589,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; @@ -2597,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; @@ -2640,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; @@ -2687,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); } @@ -2937,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; @@ -3142,6 +3408,10 @@ int get_symbol_type_class(const Symbol * sym, int * type_class) { *type_class = sym->dimension; return 0; } + if (is_pointer_pseudo_symbol(sym)) { + *type_class = TYPE_CLASS_POINTER; + return 0; + } if (unpack(sym) < 0) return -1; *type_class = TYPE_CLASS_UNKNOWN; get_object_type_class(sym->obj, type_class); @@ -3151,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; @@ -3189,19 +3459,24 @@ int get_symbol_name(const Symbol * sym, char ** name) { else if (sym->tbl != NULL) { ELF_SymbolInfo sym_info; if (sym->dimension == 0) { - size_t i; - unpack_elf_symbol_info(sym->tbl, sym->index, &sym_info); - for (i = 0;; i++) { - if (sym_info.name[i] == 0) { - *name = sym_info.name; - break; - } - if (sym_info.name[i] == '@' && sym_info.name[i + 1] == '@') { - *name = (char *)tmp_alloc_zero(i + 1); - memcpy(*name, sym_info.name, i); - break; + if (elf_symbol_info(sym, &sym_info) < 0) return -1; + if (sym_info.name != NULL) { + size_t i; + for (i = 0;; i++) { + if (sym_info.name[i] == 0) { + *name = sym_info.name; + break; + } + if (sym_info.name[i] == '@' && sym_info.name[i + 1] == '@') { + *name = (char *)tmp_alloc_zero(i + 1); + memcpy(*name, sym_info.name, i); + break; + } } } + else { + *name = NULL; + } } else { ContextAddress sym_offs = 0; @@ -3264,6 +3539,10 @@ int get_symbol_size(const Symbol * sym, ContextAddress * size) { *size = sym->cardinal; return 0; } + if (is_pointer_pseudo_symbol(sym)) { + *size = sym->size; + return 0; + } if (unpack(sym) < 0) return -1; *size = 0; if (obj != NULL) { @@ -3309,8 +3588,8 @@ 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 (IS_PPC64_FUNC_OPD(sym->tbl->file, &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 * described by the .<name> symbol or, if this symbol does not @@ -3323,16 +3602,16 @@ int get_symbol_size(const Symbol * sym, ContextAddress * size) { if (find_symbol_list != NULL) return get_symbol_size(find_symbol_list, size); } switch (info.type) { - case STT_NOTYPE: - case STT_OBJECT: - case STT_FUNC: - *size = (ContextAddress)info.size; - break; case STT_GNU_IFUNC: set_errno(ERR_OTHER, "Size not available: indirect symbol"); return -1; default: - *size = info.sym_section->file->elf64 ? 8 : 4; + if (elf_symbol_has_address(&info)) { + *size = (ContextAddress)info.size; + } + else { + *size = info.sym_section->file->elf64 ? 8 : 4; + } break; } } @@ -3712,6 +3991,22 @@ static void add_dwarf_location_command(LocationInfo * l, PropertyValue * v) { l->code_size = info->code_addr + info->code_size - l->code_addr; } } + if (info->expr_size >= 2 && info->expr_addr[0] == OP_plus_uconst) { + unsigned pos = 1; + int64_t offs = 0; + unsigned i; + for (i = 0;; i += 7) { + U1_T n = info->expr_addr[pos++]; + offs |= (n & 0x7f) << i; + if ((n & 0x80) == 0) break; + if (pos >= info->expr_size) exception(ERR_INV_DWARF); + } + if (pos == info->expr_size) { + add_location_command(l, SFT_CMD_NUMBER)->args.num = offs; + add_location_command(l, SFT_CMD_ADD); + return; + } + } /* Only create the command if no exception was thrown */ cmd = add_location_command(l, SFT_CMD_LOCATION); cmd->args.loc.code_addr = info->expr_addr; @@ -3724,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); @@ -3805,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; } @@ -3857,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; } @@ -3871,7 +4200,7 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { assert(sym->magic == SYMBOL_MAGIC); - if (sym->has_address) { + if (sym->has_address && sym->sym_class != SYM_CLASS_VALUE) { info->big_endian = big_endian_host(); add_location_command(info, SFT_CMD_NUMBER)->args.num = sym->address; return 0; @@ -3899,6 +4228,21 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { return err_wrong_obj(); } + if (is_pointer_pseudo_symbol(sym)) { + void const * value = NULL; + LocationExpressionCommand * cmd = add_location_command(info, SFT_CMD_PIECE); + + info->big_endian = big_endian_host(); + cmd->args.piece.bit_size = (unsigned)(sym->size * 8); + cmd->args.piece.value = tmp_alloc((size_t)sym->size); + value = &sym->address; + if (big_endian_host() && sym->size < sizeof(ContextAddress)) { + value = (uint8_t *)value + (sizeof(ContextAddress) - sym->size); + } + memcpy(cmd->args.piece.value, value, (size_t)sym->size); + return 0; + } + if (unpack(sym) < 0) return -1; if (obj != NULL) { @@ -3926,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; } @@ -3952,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; } @@ -4029,17 +4373,57 @@ 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; return 0; } + if (obj->mTag == TAG_variable && (obj->mFlags & DOIF_external) != 0 && obj->mCompUnit->mFile->type == ET_DYN) { + /* Check if symbol is victim of "copy relocation" */ + const char * name = get_linkage_name(obj); + if (name != NULL) { + unsigned h = calc_symbol_name_hash(name); + ELF_File * file = elf_list_first(sym_ctx, 0, ~(ContextAddress)0); + if (file == NULL && errno) return -1; + while (file != NULL) { + unsigned m = 0; + for (m = 1; m < file->section_cnt; m++) { + unsigned n; + ELF_Section * tbl = file->sections + m; + 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; + if (strcmp(sym_info.section->name, ".bss") != 0) continue; + if (!equ_symbol_names(name, sym_info.name)) continue; + if (elf_symbol_has_address(&sym_info)) { + ContextAddress address = 0; + if (elf_symbol_address(sym_ctx, &sym_info, &address)) return -1; + add_location_command(info, SFT_CMD_NUMBER)->args.num = address; + elf_list_done(sym_ctx); + return 0; + } + } + } + file = elf_list_next(sym_ctx); + if (file == NULL && errno) return -1; + } + elf_list_done(sym_ctx); + } + } #if 0 #if SERVICE_StackTrace || ENABLE_ContextProxy if (obj->mTag == TAG_formal_parameter) { @@ -4138,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; @@ -4169,6 +4553,15 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { return -1; } } + if (elf_sym_info.type == STT_TLS) { + Trap trap; + if (!set_trap(&trap)) return -1; + address = get_tls_address(sym->ctx, elf_sym_info.sym_section->file); + clear_trap(&trap); + cmd = add_location_command(info, SFT_CMD_NUMBER); + cmd->args.num = address + elf_sym_info.value; + return 0; + } if (elf_symbol_has_address(&elf_sym_info)) { if (elf_symbol_address(sym_ctx, &elf_sym_info, &address)) return -1; add_location_command(info, SFT_CMD_NUMBER)->args.num = address; @@ -4208,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; @@ -4299,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_mux.c b/agent/tcf/services/symbols_mux.c index 55288fa8..4ac10296 100644 --- a/agent/tcf/services/symbols_mux.c +++ b/agent/tcf/services/symbols_mux.c @@ -30,6 +30,7 @@ #include <tcf/framework/cache.h> #include <tcf/framework/myalloc.h> #include <tcf/framework/context.h> +#include <tcf/services/runctrl.h> #include <tcf/services/symbols.h> #include <tcf/services/symbols_mux.h> #include <tcf/services/memorymap.h> @@ -46,14 +47,7 @@ static int get_sym_addr(Context * ctx, int frame, ContextAddress addr, ContextAd *sym_addr = addr; } else if (is_top_frame(ctx, frame)) { - if (!ctx->stopped) { - errno = ERR_IS_RUNNING; - return -1; - } - if (ctx->exited) { - errno = ERR_ALREADY_EXITED; - return -1; - } + if (!is_ctx_stopped(ctx)) return -1; if (get_PC(ctx, sym_addr) < 0) return -1; } else { diff --git a/agent/tcf/services/symbols_proxy.c b/agent/tcf/services/symbols_proxy.c index ed258db7..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. @@ -31,6 +31,7 @@ #include <tcf/framework/exceptions.h> #include <tcf/services/stacktrace.h> #include <tcf/services/memorymap.h> +#include <tcf/services/runctrl.h> #include <tcf/services/linenumbers.h> #include <tcf/services/symbols.h> #include <tcf/services/vm.h> @@ -285,7 +286,9 @@ static void symbols_cleanup_event(void * arg) { if (!list_is_empty(&flush_rc) || !list_is_empty(&flush_mm)) { post_event_with_delay(symbols_cleanup_event, NULL, SYMBOLS_PROXY_CLEANUP_DELAY); } - else symbols_cleanup_posted = 0; + else { + symbols_cleanup_posted = 0; + } } static Symbol * alloc_symbol(void) { @@ -472,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); @@ -486,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); } } @@ -626,8 +636,7 @@ static uint64_t get_symbol_ip(Context * ctx, int * frame, ContextAddress addr) { } else if (is_top_frame(ctx, *frame)) { ContextAddress pc = 0; - if (!ctx->stopped) exception(ERR_IS_RUNNING); - if (ctx->exited) exception(ERR_ALREADY_EXITED); + if (!is_ctx_stopped(ctx)) exception(errno); *frame = get_top_frame(ctx); if (get_PC(ctx, &pc) < 0) exception(errno); ip = (uint64_t)pc; @@ -670,7 +679,6 @@ static void read_context_data(InputStream * inp, const char * name, void * args) } static void validate_context(Channel * c, void * args, int error) { - Trap trap; SymInfoCache * s = (SymInfoCache *)args; assert(s->magic == MAGIC_INFO); assert(s->pending_get_context != NULL); @@ -678,10 +686,11 @@ static void validate_context(Channel * c, void * args, int error) { assert(s->update_owner == NULL); assert(!s->done_context); assert(!s->degraded); - if (set_trap(&trap)) { - s->pending_get_context = NULL; - s->done_context = 1; - if (!error) { + s->pending_get_context = NULL; + s->done_context = 1; + if (!error) { + Trap trap; + if (set_trap(&trap)) { error = read_errno(&c->inp); json_read_struct(&c->inp, read_context_data, s); json_test_char(&c->inp, MARKER_EOA); @@ -692,17 +701,18 @@ static void validate_context(Channel * c, void * args, int error) { list_remove(&s->link_flush); list_add_last(&s->link_flush, &flush_rc); } + clear_trap(&trap); + } + else { + error = trap.error; + s->update_owner = NULL; } - clear_trap(&trap); - if (s->update_owner != NULL) context_lock(s->update_owner); - } - else { - error = trap.error; - s->update_owner = NULL; } + if (s->update_owner != NULL) context_lock(s->update_owner); s->error_get_context = get_error_report(error); cache_notify_later(&s->cache); if (s->disposed) free_sym_info_cache(s); + run_ctrl_unlock(); } static SymInfoCache * get_sym_info_cache(const Symbol * sym, int acc_mode) { @@ -732,7 +742,7 @@ static SymInfoCache * get_sym_info_cache(const Symbol * sym, int acc_mode) { break; } if (update) { - if (!s->update_owner->stopped) exception(ERR_IS_RUNNING); + if (!is_ctx_stopped(s->update_owner)) exception(errno); s->degraded = 0; s->done_context = 0; s->has_size = 0; @@ -757,6 +767,7 @@ static SymInfoCache * get_sym_info_cache(const Symbol * sym, int acc_mode) { if (!s->done_context) { Channel * c = cache_channel(); if (c == NULL || is_channel_closed(c)) exception(ERR_SYM_NOT_FOUND); + run_ctrl_lock(); s->pending_get_context = protocol_send_command(c, SYMBOLS, "getContext", validate_context, s); json_write_string(&c->out, s->id); write_stream(&c->out, 0); @@ -787,27 +798,28 @@ static char ** read_symbol_list(InputStream * inp, int * id_cnt) { } static void validate_find(Channel * c, void * args, int error) { - Trap trap; FindSymCache * f = (FindSymCache *)args; assert(f->magic == MAGIC_FIND); assert(f->pending != NULL); assert(f->error == NULL); - if (set_trap(&trap)) { - f->pending = NULL; - if (!error) { + f->pending = NULL; + if (!error) { + Trap trap; + if (set_trap(&trap)) { error = read_errno(&c->inp); f->id_buf = read_symbol_list(&c->inp, &f->id_cnt); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + clear_trap(&trap); + } + else { + error = trap.error; } - clear_trap(&trap); - } - else { - error = trap.error; } f->error = get_error_report(error); cache_notify_later(&f->cache); if (f->disposed) free_find_sym_cache(f); + run_ctrl_unlock(); } int find_symbol_by_name(Context * ctx, int frame, ContextAddress addr, const char * name, Symbol ** sym) { @@ -841,13 +853,20 @@ int find_symbol_by_name(Context * ctx, int frame, ContextAddress addr, const cha Channel * c = get_channel(syms); f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache)); list_add_first(&f->link_syms, syms->link_find_by_name + h); - list_add_last(&f->link_flush, &flush_mm); + if (ip) { + list_add_last(&f->link_flush, &flush_rc); + f->update_policy = UPDATE_ON_EXE_STATE_CHANGES; + } + else { + list_add_last(&f->link_flush, &flush_mm); + f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; + } context_lock(f->ctx = ctx); + run_ctrl_lock(); f->magic = MAGIC_FIND; f->frame = frame; f->ip = ip; f->name = loc_strdup(name); - f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; f->pending = protocol_send_command(c, SYMBOLS, "findByName", validate_find, f); if (frame != STACK_NO_FRAME) { json_write_string(&c->out, frame2id(ctx, frame)); @@ -917,6 +936,7 @@ int find_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol ** f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; } context_lock(f->ctx = ctx); + run_ctrl_lock(); f->magic = MAGIC_FIND; f->frame = frame; f->ip = ip; @@ -984,14 +1004,21 @@ int find_symbol_in_scope(Context * ctx, int frame, ContextAddress addr, Symbol * Channel * c = get_channel(syms); f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache)); list_add_first(&f->link_syms, syms->link_find_in_scope + h); - list_add_last(&f->link_flush, &flush_mm); + if (ip) { + list_add_last(&f->link_flush, &flush_rc); + f->update_policy = UPDATE_ON_EXE_STATE_CHANGES; + } + else { + list_add_last(&f->link_flush, &flush_mm); + f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; + } context_lock(f->ctx = ctx); + run_ctrl_lock(); f->magic = MAGIC_FIND; f->frame = frame; f->ip = ip; if (scope != NULL) f->scope = loc_strdup(scope->cache->id); f->name = loc_strdup(name); - f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; f->pending = protocol_send_command(c, SYMBOLS, "findInScope", validate_find, f); if (frame != STACK_NO_FRAME) { json_write_string(&c->out, frame2id(ctx, frame)); @@ -1064,12 +1091,19 @@ int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * func, Channel * c = get_channel(syms); f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache)); list_add_first(&f->link_syms, syms->link_list + h); - list_add_last(&f->link_flush, &flush_mm); + if (ip) { + list_add_last(&f->link_flush, &flush_rc); + f->update_policy = UPDATE_ON_EXE_STATE_CHANGES; + } + else { + list_add_last(&f->link_flush, &flush_mm); + f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; + } context_lock(f->ctx = ctx); + run_ctrl_lock(); f->magic = MAGIC_FIND; f->frame = frame; f->ip = ip; - f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; f->pending = protocol_send_command(c, SYMBOLS, "list", validate_find, f); if (frame != STACK_NO_FRAME) { json_write_string(&c->out, frame2id(ctx, frame)); @@ -1271,29 +1305,30 @@ int get_symbol_frame(const Symbol * sym, Context ** ctx, int * frame) { } static void validate_children(Channel * c, void * args, int error) { - Trap trap; SymInfoCache * s = (SymInfoCache *)args; assert(s->magic == MAGIC_INFO); assert(s->pending_get_children != NULL); assert(s->error_get_children == NULL); assert(!s->done_children); - if (set_trap(&trap)) { - s->pending_get_children = NULL; - s->done_children = 1; - if (!error) { + s->pending_get_children = NULL; + s->done_children = 1; + if (!error) { + Trap trap; + if (set_trap(&trap)) { error = read_errno(&c->inp); s->children_ids = read_symbol_list(&c->inp, &s->children_count); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + clear_trap(&trap); + } + else { + error = trap.error; } - clear_trap(&trap); - } - else { - error = trap.error; } s->error_get_children = get_error_report(error); cache_notify_later(&s->cache); if (s->disposed) free_sym_info_cache(s); + run_ctrl_unlock(); } int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) { @@ -1312,6 +1347,7 @@ int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) { else if (!s->done_children) { Channel * c = cache_channel(); if (c == NULL || is_channel_closed(c)) exception(ERR_SYM_NOT_FOUND); + run_ctrl_lock(); s->pending_get_children = protocol_send_command(c, SYMBOLS, "getChildren", validate_children, s); json_write_string(&c->out, s->id); write_stream(&c->out, 0); @@ -1332,28 +1368,29 @@ int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) { } static void validate_array_type_id(Channel * c, void * args, int error) { - Trap trap; ArraySymCache * s = (ArraySymCache *)args; assert(s->magic == MAGIC_ARRAY); assert(s->pending != NULL); assert(s->error == NULL); assert(s->id == NULL); - if (set_trap(&trap)) { - s->pending = NULL; - if (!error) { + s->pending = NULL; + if (!error) { + Trap trap; + if (set_trap(&trap)) { error = read_errno(&c->inp); s->id = json_read_alloc_string(&c->inp); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + clear_trap(&trap); + } + else { + error = trap.error; } - clear_trap(&trap); - } - else { - error = trap.error; } s->error = get_error_report(error); cache_notify_later(&s->cache); if (s->disposed) free_arr_sym_cache(s); + run_ctrl_unlock(); } int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { @@ -1375,6 +1412,7 @@ int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { if (c == NULL || is_channel_closed(c)) exception(ERR_SYM_NOT_FOUND); a = (ArraySymCache *)loc_alloc_zero(sizeof(*a)); list_add_first(&a->link_sym, &s->array_syms); + run_ctrl_lock(); a->magic = MAGIC_ARRAY; a->length = length; a->pending = protocol_send_command(c, SYMBOLS, "getArrayType", validate_array_type_id, a); @@ -1410,23 +1448,23 @@ static void read_address_attrs(InputStream * inp, const char * name, void * x) { } static void validate_address_info(Channel * c, void * args, int error) { - Trap trap; AddressInfoCache * f = (AddressInfoCache *)args; assert(f->magic == MAGIC_ADDR); assert(f->pending != NULL); assert(f->error == NULL); - if (set_trap(&trap)) { - f->pending = NULL; - if (!error) { + f->pending = NULL; + if (!error) { + Trap trap; + if (set_trap(&trap)) { error = read_errno(&c->inp); json_read_struct(&c->inp, read_address_attrs, f); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + clear_trap(&trap); + } + else { + error = trap.error; } - clear_trap(&trap); - } - else { - error = trap.error; } if (f->range_addr != 0 || f->range_size != 0) { if (f->range_addr + f->range_size < f->range_addr) { @@ -1441,6 +1479,7 @@ static void validate_address_info(Channel * c, void * args, int error) { f->error = get_error_report(error); cache_notify_later(&f->cache); if (f->disposed) free_address_info_cache(f); + run_ctrl_unlock(); } static int get_address_info(Context * ctx, ContextAddress addr, AddressInfoCache ** info) { @@ -1485,6 +1524,7 @@ static int get_address_info(Context * ctx, ContextAddress addr, AddressInfoCache list_add_first(&f->link_syms, syms->link_address + h); list_add_last(&f->link_flush, &flush_mm); context_lock(f->ctx = ctx); + run_ctrl_lock(); f->magic = MAGIC_ADDR; f->addr = addr; context_lock(f->ctx = ctx); @@ -1540,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; @@ -1683,29 +1727,30 @@ static void read_location_attrs(InputStream * inp, const char * name, void * x) } static void validate_location_info(Channel * c, void * args, int error) { - Trap trap; LocationInfoCache * f = (LocationInfoCache *)args; assert(f->magic == MAGIC_LOC); assert(f->pending != NULL); assert(f->error == NULL); - if (set_trap(&trap)) { - f->pending = NULL; - if (!error) { + f->pending = NULL; + if (!error) { + Trap trap; + if (set_trap(&trap)) { id2register_error = 0; error = read_errno(&c->inp); json_read_struct(&c->inp, read_location_attrs, f); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); if (!error && id2register_error) error = id2register_error; + clear_trap(&trap); + } + else { + error = trap.error; } - clear_trap(&trap); - } - else { - error = trap.error; } f->error = get_error_report(error); cache_notify_later(&f->cache); if (f->disposed) free_location_info_cache(f); + run_ctrl_unlock(); } int get_location_info(const Symbol * sym, LocationInfo ** loc) { @@ -1759,6 +1804,7 @@ int get_location_info(const Symbol * sym, LocationInfo ** loc) { } if (f->sym_id == NULL) { Channel * c = get_channel(syms); + run_ctrl_lock(); f->sym_id = loc_strdup(sym_cache->id); f->pending = protocol_send_command(c, SYMBOLS, "getLocationInfo", validate_location_info, f); json_write_string(&c->out, f->sym_id); @@ -1801,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); @@ -1831,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)) { @@ -1853,19 +1946,20 @@ 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); } static void validate_frame(Channel * c, void * args, int error) { - Trap trap; StackFrameCache * f = (StackFrameCache *)args; assert(f->magic == MAGIC_FRAME); assert(f->pending != NULL); assert(f->error == NULL); - if (set_trap(&trap)) { - f->pending = NULL; - if (!error) { + f->pending = NULL; + if (!error) { + Trap trap; + if (set_trap(&trap)) { id2register_error = 0; error = read_errno(&c->inp); if (f->command_props) { @@ -1885,21 +1979,22 @@ static void validate_frame(Channel * c, void * args, int error) { } json_test_char(&c->inp, MARKER_EOM); if (!error && id2register_error) error = id2register_error; + clear_trap(&trap); } - if (error || f->sti.size == 0) { - f->sti.addr = (ContextAddress)f->ip; - f->sti.size = 1; + else { + error = trap.error; } - assert(f->sti.addr <= f->ip); - assert(f->sti.addr + f->sti.size == 0 || f->sti.addr + f->sti.size > f->ip); - clear_trap(&trap); } - else { - error = trap.error; + if (error || f->sti.size == 0) { + f->sti.addr = (ContextAddress)f->ip; + f->sti.size = 1; } + assert(f->sti.addr <= f->ip); + assert(f->sti.addr + f->sti.size == 0 || f->sti.addr + f->sti.size > f->ip); f->error = get_error_report(error); cache_notify_later(&f->cache); if (f->disposed) free_stack_frame_cache(f); + run_ctrl_unlock(); } int get_stack_tracing_info(Context * ctx, ContextAddress ip, StackTracingInfo ** info) { @@ -1954,6 +2049,7 @@ int get_stack_tracing_info(Context * ctx, ContextAddress ip, StackTracingInfo ** list_add_first(&f->link_syms, syms->link_frame + h); list_add_last(&f->link_flush, &flush_mm); context_lock(f->ctx = ctx); + run_ctrl_lock(); f->magic = MAGIC_FRAME; f->ip = ip; if (syms->no_find_frame_props) { @@ -2015,27 +2111,28 @@ static void read_file_info_props(InputStream * inp, const char * name, void * ar } static void validate_file(Channel * c, void * args, int error) { - Trap trap; FileInfoCache * f = (FileInfoCache *)args; assert(f->magic == MAGIC_FILE); assert(f->pending != NULL); assert(f->error == NULL); - if (set_trap(&trap)) { - f->pending = NULL; - if (!error) { + f->pending = NULL; + if (!error) { + Trap trap; + if (set_trap(&trap)) { error = read_errno(&c->inp); json_read_struct(&c->inp, read_file_info_props, f); json_test_char(&c->inp, MARKER_EOA); json_test_char(&c->inp, MARKER_EOM); + clear_trap(&trap); + } + else { + error = trap.error; } - clear_trap(&trap); - } - else { - error = trap.error; } if (get_error_code(error) != ERR_INV_COMMAND) f->error = get_error_report(error); cache_notify_later(&f->cache); if (f->disposed) free_file_info_cache(f); + run_ctrl_unlock(); } static FileInfoCache * get_file_info_cache(Context * ctx, ContextAddress addr) { @@ -2077,6 +2174,7 @@ static FileInfoCache * get_file_info_cache(Context * ctx, ContextAddress addr) { list_add_first(&f->link_syms, syms->link_file + h); list_add_last(&f->link_flush, &flush_mm); context_lock(f->ctx = ctx); + run_ctrl_lock(); f->magic = MAGIC_FILE; f->addr = addr; f->pending = protocol_send_command(c, SYMBOLS, "getSymFileInfo", validate_file, f); 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 8174b975..1b3900ec 100644 --- a/agent/tcf/services/tcf_elf.c +++ b/agent/tcf/services/tcf_elf.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007-2018 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. @@ -250,9 +250,13 @@ static void elf_cleanup_cache_client(void * arg) { file = files; while (file != NULL) { if (event_cnt % 5 == 0) { - struct stat st; - if (!file->mtime_changed && stat(file->name, &st) == 0 && file->mtime != st.st_mtime) { - file->mtime_changed = 1; + if (!file->mtime_changed) { + struct stat st; + if (stat(file->name, &st) < 0 || + file->size != st.st_size || + file->mtime != st.st_mtime || + (st.st_ino != 0 && st.st_ino != file->ino)) + file->mtime_changed = 1; } } file = file->next; @@ -463,6 +467,7 @@ static char * get_debug_info_file_name(ELF_File * file, int * error) { lnm = apply_path_map(NULL, NULL, lnm, PATH_MAP_TO_LOCAL); #endif if (stat(lnm, &buf) == 0) return loc_strdup(lnm); + trace(LOG_ALWAYS, "Cannot open debug info file '%s': %s", lnm, errno_to_str(errno)); } offs += desc_sz; while (offs % 4 != 0) offs++; @@ -490,6 +495,7 @@ static char * get_debug_info_file_name(ELF_File * file, int * error) { lnm = apply_path_map(NULL, NULL, lnm, PATH_MAP_TO_LOCAL); #endif if (stat(lnm, &buf) == 0) return loc_strdup(lnm); + trace(LOG_ALWAYS, "Cannot open debug info file '%s': %s", lnm, errno_to_str(errno)); } } } @@ -539,7 +545,7 @@ static char * get_dwz_file_name(ELF_File * file, int * error) { lnm = apply_path_map(NULL, NULL, lnm, PATH_MAP_TO_LOCAL); #endif if (stat(lnm, &buf) == 0) return loc_strdup(lnm); - trace(LOG_ALWAYS, "Cannot open DWZ file: %s", lnm); + trace(LOG_ALWAYS, "Cannot open DWZ file '%s': %s", lnm, errno_to_str(errno)); } } } @@ -1270,26 +1276,28 @@ static MemoryRegion * add_region(MemoryMap * map) { return r; } -static void program_headers_ranges(ELF_File * file, ContextAddress addr0, ContextAddress addr1, MemoryMap * res) { +static void program_headers_ranges(ELF_File * file, ContextAddress addr0, ContextAddress addr1, MemoryMap * res, ContextAddress base_addr) { unsigned j; for (j = 0; j < file->pheader_cnt; j++) { ELF_PHeader * p = file->pheaders + j; - if (p->mem_size == 0) continue; - if (p->type != PT_LOAD) continue; - if (p->address <= addr1 && p->address + p->mem_size - 1 >= addr0) { - MemoryRegion * x = add_region(res); - x->addr = (ContextAddress)p->address; - x->size = (ContextAddress)p->mem_size; - x->dev = file->dev; - x->ino = file->ino; - x->file_name = file->name; - x->file_offs = p->offset; - x->file_size = p->file_size; - x->bss = p->file_size == 0 && p->mem_size != 0; - if (p->flags & PF_R) x->flags |= MM_FLAG_R; - if (p->flags & PF_W) x->flags |= MM_FLAG_W; - if (p->flags & PF_X) x->flags |= MM_FLAG_X; - x->valid = MM_VALID_ADDR | MM_VALID_SIZE | MM_VALID_FILE_OFFS | MM_VALID_FILE_SIZE; + if (p->type == PT_LOAD && p->mem_size > 0) { + ContextAddress p_addr0 = (ContextAddress)p->address + base_addr; + ContextAddress p_addr1 = (ContextAddress)(p->address + p->mem_size - 1) + base_addr; + if (p_addr0 <= addr1 && p_addr1 >= addr0) { + MemoryRegion * x = add_region(res); + x->addr = p_addr0; + x->size = (ContextAddress)p->mem_size; + x->dev = file->dev; + x->ino = file->ino; + x->file_name = file->name; + x->file_offs = p->offset; + x->file_size = p->file_size; + x->bss = p->file_size == 0 && p->mem_size != 0; + if (p->flags & PF_R) x->flags |= MM_FLAG_R; + if (p->flags & PF_W) x->flags |= MM_FLAG_W; + if (p->flags & PF_X) x->flags |= MM_FLAG_X; + x->valid = MM_VALID_ADDR | MM_VALID_SIZE | MM_VALID_FILE_OFFS | MM_VALID_FILE_SIZE; + } } } } @@ -1413,25 +1421,29 @@ static void search_regions(MemoryMap * map, ContextAddress addr0, ContextAddress if (no_addr && no_size && no_file_offs && no_file_size && r->sect_name == NULL) { ELF_File * file = elf_open_memory_region_file(r, NULL); if (file != NULL) { + ContextAddress base_addr = 0; KernelModuleAddress * module = NULL; - if (r->attrs != NULL) { - MemoryRegionAttribute * a = r->attrs; - while (a != NULL) { - if (strcmp(a->name, "KernelModule") == 0) { - ByteArrayInputStream buf; - InputStream * inp = create_byte_array_input_stream(&buf, a->value, strlen(a->value)); - module = (KernelModuleAddress *)tmp_alloc_zero(sizeof(KernelModuleAddress)); - json_read_struct(inp, read_module_struct, module); - break; - } - a = a->next; + MemoryRegionAttribute * a = r->attrs; + while (a != NULL) { + ByteArrayInputStream buf; + if (strcmp(a->name, "KernelModule") == 0) { + InputStream * inp = create_byte_array_input_stream(&buf, a->value, strlen(a->value)); + module = (KernelModuleAddress *)tmp_alloc_zero(sizeof(KernelModuleAddress)); + json_read_struct(inp, read_module_struct, module); + json_test_char(inp, MARKER_EOS); + } + else if (strcmp(a->name, "BaseAddress") == 0) { + InputStream * inp = create_byte_array_input_stream(&buf, a->value, strlen(a->value)); + base_addr = (ContextAddress)json_read_uint64(inp); + json_test_char(inp, MARKER_EOS); } + a = a->next; } if (module != NULL) { linux_kernel_module_ranges(file, module, addr0, addr1, res); } else { - program_headers_ranges(file, addr0, addr1, res); + program_headers_ranges(file, addr0, addr1, res, base_addr); } } } @@ -1443,33 +1455,17 @@ static void search_regions(MemoryMap * map, ContextAddress addr0, ContextAddress ELF_File * file = elf_open_memory_region_file(r, NULL); if (file != NULL) { unsigned j; + uint64_t base_offs = ~(uint64_t)0; ContextAddress base_addr = 0; for (j = 0; j < file->pheader_cnt; j++) { ELF_PHeader * p = file->pheaders + j; - if (p->type == PT_LOAD && p->offset == 0) { + if (p->type == PT_LOAD && p->offset < base_offs) { base_addr = r->addr - (ContextAddress)p->address; - break; - } - } - for (j = 0; j < file->pheader_cnt; j++) { - ELF_PHeader * p = file->pheaders + j; - if (p->type == PT_LOAD && p->mem_size > 0) { - ContextAddress p_addr0 = (ContextAddress)p->address + base_addr; - ContextAddress p_addr1 = (ContextAddress)(p->address + p->mem_size - 1) + base_addr; - if (p_addr0 <= addr1 && p_addr1 >= addr0) { - MemoryRegion * x = add_region(res); - x->addr = p_addr0; - x->size = (ContextAddress)p->mem_size; - x->dev = file->dev; - x->ino = file->ino; - x->file_name = file->name; - x->file_offs = p->offset; - x->file_size = p->file_size; - x->flags = MM_FLAG_R | MM_FLAG_W | MM_FLAG_X; - x->valid = MM_VALID_ADDR | MM_VALID_SIZE | MM_VALID_FILE_OFFS | MM_VALID_FILE_SIZE; - } + base_offs = p->offset; + if (p->offset == 0) break; } } + program_headers_ranges(file, addr0, addr1, res, base_addr); } } } @@ -1803,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) { @@ -1824,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); @@ -1846,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++; @@ -1878,7 +1879,7 @@ ContextAddress elf_map_to_run_time_address(Context * ctx, ELF_File * file, ELF_S errno = 0; return addr; } - errno = set_errno(ERR_INV_ADDRESS, "Invalid memory map, cannot compute run-time address"); + set_errno(ERR_INV_ADDRESS, "Invalid memory map, cannot compute run-time address"); return 0; } @@ -2075,9 +2076,17 @@ void unpack_elf_symbol_info(ELF_Section * sym_sec, U4_T index, ELF_SymbolInfo * } if (file->machine == EM_ARM) { - if (info->type == STT_FUNC || info->type == STT_ARM_TFUNC) { - info->value = info->value & ~ (U8_T)1; + if (info->type == STT_ARM_16BIT) { + info->type = STT_OBJECT; + info->type16bit = 1; + } + if (info->type == STT_ARM_TFUNC) { info->type = STT_FUNC; + info->type16bit = 1; + } + if (info->type == STT_FUNC || info->type16bit) { + if (info->value & 1) info->type16bit = 1; + info->value = info->value & ~(U8_T)1; } } else if (IS_PPC64_FUNC_OPD(file, info)) { @@ -2154,11 +2163,22 @@ static void create_symbol_addr_search_index(ELF_Section * sec) { int add = 0; U8_T addr = 0; U1_T type = 0; + + /* this is a workaround for the extra relocs for local symbols in the binutils RISC-V port */ + if (file->machine == EM_RISCV && file->type == ET_REL) { + ELF_SymbolInfo sym_info = {0}; + unpack_elf_symbol_info(tbl, n, &sym_info); + if (sym_info.name && sym_info.name[0] == '.' && sym_info.name[1] == 'L') { + n++; + continue; + } + } + if (file->machine == EM_PPC64) { ELF_SymbolInfo sym_info; unpack_elf_symbol_info(tbl, n, &sym_info); /* Don't register PPC64 dot function name */ - add = IS_PPC64_FUNC_OPD(file, &sym_info)|| \ + add = IS_PPC64_FUNC_OPD(file, &sym_info) || \ (sym_info.section == sec && !IS_PPC64_FUNC_DOT(file, &sym_info) && sym_info.type != STT_GNU_IFUNC); if (add) { addr = sym_info.value + (rel ? sec->addr : 0); @@ -2205,8 +2225,8 @@ static void create_symbol_addr_search_index(ELF_Section * sec) { } add = add && type != STT_GNU_IFUNC; if (add && file->machine == EM_ARM) { - if (type == STT_FUNC || type == STT_ARM_TFUNC) { - addr = addr & ~(U8_T) 1; + if (type == STT_FUNC || type == STT_ARM_TFUNC || type == STT_ARM_16BIT) { + addr = addr & ~(U8_T)1; } } } @@ -2434,7 +2454,7 @@ int elf_get_plt_entry_size(ELF_File * file, unsigned * first_size, unsigned * en *entry_size = 16; return 0; } - errno = set_errno(ERR_OTHER, "Unknown PLT entry size"); + set_errno(ERR_OTHER, "Unknown PLT entry size"); return -1; } @@ -2443,15 +2463,18 @@ void elf_invalidate(void) { ELF_File * file = files; while (file != NULL) { ELF_File * next = file->next; - struct stat st; + if (!file->mtime_changed) { + struct stat st; + if (stat(file->name, &st) < 0 || + file->size != st.st_size || + file->mtime != st.st_mtime || + (st.st_ino != 0 && st.st_ino != file->ino)) + file->mtime_changed = 1; + } if (file->lock_cnt > 0) { prev = file; } - else if (file->mtime_changed || - stat(file->name, &st) < 0 || - file->size != st.st_size || - file->mtime != st.st_mtime || - (st.st_ino != 0 && st.st_ino != file->ino)) { + else if (file->mtime_changed) { if (prev == NULL) files = next; else prev->next = next; elf_dispose(file); diff --git a/agent/tcf/services/tcf_elf.h b/agent/tcf/services/tcf_elf.h index cab6162c..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 @@ -126,9 +123,12 @@ #define STT_FUNC 2 #define STT_SECTION 3 #define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 #define STT_LOPROC 13 #define STT_HIPROC 15 #define STT_ARM_TFUNC STT_LOPROC +#define STT_ARM_16BIT STT_HIPROC #define PT_NULL 0 #define PT_LOAD 1 @@ -180,9 +180,13 @@ #define DT_NUM 34 #define DT_LOOS 0x6000000d #define DT_HIOS 0x6ffff000 +#define DT_FLAGS_1 0x6ffffffb #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff +/* Values of DT_FLAGS_1 */ +#define DF_1_PIE 0x08000000 + typedef uint32_t Elf32_Addr; typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Off; @@ -391,9 +395,22 @@ 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 +#ifndef DT_FLAGS_1 +#define DT_FLAGS_1 0x6ffffffb +#endif +#ifndef DF_1_PIE +#define DF_1_PIE 0x08000000 +#endif typedef struct ElfX_Sym { union { @@ -488,6 +505,7 @@ struct ELF_SymbolInfo { char * name; U1_T bind; U1_T type; + U1_T type16bit; U8_T value; U8_T size; U8_T other; diff --git a/agent/tcf/services/terminals.c b/agent/tcf/services/terminals.c index a9691b82..033e7f32 100644 --- a/agent/tcf/services/terminals.c +++ b/agent/tcf/services/terminals.c @@ -230,6 +230,15 @@ static void send_event_terminal_win_size_changed(OutputStream * out, Terminal * write_stream(out, MARKER_EOM); } +#if !defined(_WIN32) && !defined(__CYGWIN__) +static void kill_term_event(void * args) { + Terminal * term = (Terminal *)args; + int pid = get_process_pid(term->prs); + post_event_with_delay(kill_term_event, term, 1000000); + kill(pid, SIGKILL); +} +#endif + static int kill_term(Terminal * term) { int err = 0; int pid = get_process_pid(term->prs); @@ -244,7 +253,9 @@ static int kill_term(Terminal * term) { if (!CloseHandle(h) && !err) err = set_win32_errno(GetLastError()); } #else - if (kill(pid, get_process_out_state(term->prs) ? TERM_EXIT_SIGNAL : SIGKILL) < 0) err = errno; + int sig = get_process_out_state(term->prs) ? TERM_EXIT_SIGNAL : SIGKILL; + if (kill(pid, sig) < 0) err = errno; + if (!err && sig != SIGKILL) post_event_with_delay(kill_term_event, term, 10000000); #endif term->terminated = 1; return err; @@ -291,6 +302,9 @@ static void terminal_exited(void * args) { list_remove(&term->link); broadcast_group_unlock(term->bcg); channel_unlock_with_msg(term->channel, TERMINALS); +#if !defined(_WIN32) && !defined(__CYGWIN__) + cancel_event(kill_term_event, term, 0); +#endif loc_free(term); } diff --git a/agent/tcf/services/vm.c b/agent/tcf/services/vm.c index 8f7e19c1..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,23 +863,126 @@ 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; } } break; +#if ENABLE_Symbols case OP_GNU_variable_value: { const char * id = (const char *)(code + code_pos); @@ -775,6 +1004,7 @@ static void evaluate_expression(void) { state->stk_pos++; } break; +#endif case OP_TCF_switch: check_e_stack(1); { @@ -849,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 diff --git a/cmake-tcf-lib.txt b/cmake-tcf-lib.txt index 83c205c3..c7a0c1dd 100644 --- a/cmake-tcf-lib.txt +++ b/cmake-tcf-lib.txt @@ -41,6 +41,12 @@ file(GLOB TCF_SRCS_REL RELATIVE ${TCF_BASE_DIR} ${TCF_BASE_DIR}/tcf/main/*.c ${TCF_BASE_DIR}/tcf/http/*.c) +if(TCF_MACHINE STREQUAL "a64") + list(APPEND TCF_SRCS_REL machine/arm/tcf/stack-crawl-arm.c) + list(APPEND TCF_SRCS_REL machine/arm/tcf/disassembler-arm.c) + list(APPEND TCF_SRCS_REL machine/arm/tcf/disassembler-thumb.c) +endif() + # remove non-library files file(GLOB TCF_MAIN_REL RELATIVE ${TCF_BASE_DIR} ${TCF_BASE_DIR}/tcf/main/main*.c) diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..5e62d480 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,26 @@ +FROM debian:buster + +RUN apt update -y && apt install -y \ + make \ + clang \ + mingw-w64 \ + gcc-aarch64-linux-gnu \ + gcc-arm-linux-gnueabihf \ + gcc-powerpc-linux-gnu \ + gcc-powerpc64-linux-gnu \ + gcc-powerpc64le-linux-gnu \ + gcc-riscv64-linux-gnu + +RUN dpkg --add-architecture arm64 \ + && dpkg --add-architecture armhf \ + && dpkg --add-architecture ppc64el + +RUN apt update -y && apt install -y \ + libssl-dev libssl-dev:arm64 libssl-dev:armhf libssl-dev:ppc64el \ + uuid-dev uuid-dev:arm64 uuid-dev:armhf uuid-dev:ppc64el + +COPY ./build-agents.sh /bin/ +RUN chmod +x /bin/build-agents.sh + +WORKDIR /src +CMD ["/bin/build-agents.sh"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 00000000..bec384b1 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,30 @@ +Introduction +============ + +This Dockerfile provides a debian based image with the following +host and cross compilers targeting Linux: + + * x86_64 (+ Windows) + * aarch64 + * arm + * powerpc64 + * riscv64 + +The prerequisite to build and use this image is a docker-ce installation. + +To build the docker image do: + +```console +$ cd org.eclipse.tcf.agent +$ docker build -t tcf-builder docker +``` + +To build the tcf agent with the above mentioned host and target compilers do: +```console +$ docker run -it --rm -v $PWD/agent:/src -u (id -u):(id -g) tcf-builder +``` + +To get a shell and invoke one of the compilers in the image do: +```console +$ docker run -it --rm -v $PWD/agent:/src -u (id -u):(id -g) tcf-builder bash +``` diff --git a/docker/build-agents.sh b/docker/build-agents.sh new file mode 100755 index 00000000..33118784 --- /dev/null +++ b/docker/build-agents.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e +JOBS="-j $(nproc)" + +make $JOBS MACHINE=x86_64 CC=clang +make $JOBS MACHINE=x86_64 OPSYS=MinGW CC=x86_64-w64-mingw32-gcc MKDIR="mkdir -p \$(1)" +make $JOBS MACHINE=a64 CC=aarch64-linux-gnu-gcc +make $JOBS MACHINE=arm CC=arm-linux-gnueabihf-gcc +make $JOBS MACHINE=powerpc CC=powerpc64le-linux-gnu-gcc +make $JOBS MACHINE=powerpc CC=powerpc64-linux-gnu-gcc NO_SSL=1 NO_UUID=1 BINDIR=obj/GNU/Linux/powerpc-be/Debug +make $JOBS MACHINE=powerpc CC=powerpc-linux-gnu-gcc NO_SSL=1 NO_UUID=1 BINDIR=obj/GNU/Linux/powerpc-32-be/Debug +make $JOBS MACHINE=riscv64 CC=riscv64-linux-gnu-gcc NO_SSL=1 NO_UUID=1 diff --git a/examples/daytime/readme.txt b/examples/daytime/readme.txt index 8f0cb8af..7a6fd199 100644 --- a/examples/daytime/readme.txt +++ b/examples/daytime/readme.txt @@ -33,8 +33,8 @@ git clone http://git.eclipse.org/gitroot/tcf/org.eclipse.tcf.agent.git cd org.eclipse.tcf.agent/examples/daytime make NO_SSL=1 NO_UUID=1 make -C ../../agent NO_SSL=1 NO_UUID=1 -obj/*/*/Debug/agent -L- & -../../agent/obj/*/*/Debug/client <<<EOF +obj/*/*/*/Debug/agent -L- & +../../agent/obj/*/*/*/Debug/client <<<EOF connect TCP::1534 services tcf Daytime getTimeOfDay "de" diff --git a/server/msvc/server-vc2015.vcxproj b/server/msvc/server-vc2015.vcxproj index 36e164ea..3789e51f 100644 --- a/server/msvc/server-vc2015.vcxproj +++ b/server/msvc/server-vc2015.vcxproj @@ -196,6 +196,7 @@ <ClCompile Include="..\..\agent\tcf\http\http.c" />
<ClCompile Include="..\..\agent\tcf\services\disassembly.c" />
<ClCompile Include="..\..\agent\tcf\services\elf-symbols.c" />
+ <ClCompile Include="..\..\agent\tcf\services\runctrl.c" />
<ClCompile Include="..\tcf\services\context-proxy.c" />
<ClCompile Include="..\..\agent\tcf\services\contextquery.c" />
<ClCompile Include="..\..\agent\tcf\services\diagnostics.c" />
@@ -278,6 +279,7 @@ <ClInclude Include="..\..\agent\tcf\services\disassembly.h" />
<ClInclude Include="..\..\agent\tcf\services\elf-symbols-ext.h" />
<ClInclude Include="..\..\agent\tcf\services\elf-symbols.h" />
+ <ClInclude Include="..\..\agent\tcf\services\runctrl.h" />
<ClInclude Include="..\tcf\services\context-proxy.h" />
<ClInclude Include="..\..\agent\tcf\services\contextquery.h" />
<ClInclude Include="..\..\agent\tcf\services\diagnostics.h" />
diff --git a/server/msvc/server-vc2015.vcxproj.filters b/server/msvc/server-vc2015.vcxproj.filters index 936accb8..9d399512 100644 --- a/server/msvc/server-vc2015.vcxproj.filters +++ b/server/msvc/server-vc2015.vcxproj.filters @@ -216,6 +216,9 @@ <ClCompile Include="..\..\agent\tcf\http\http-tcf.c">
<Filter>http</Filter>
</ClCompile>
+ <ClCompile Include="..\..\agent\tcf\services\runctrl.c">
+ <Filter>services</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tcf\services\context-proxy.h">
@@ -462,5 +465,8 @@ <ClInclude Include="..\..\agent\tcf\http\http-tcf.h">
<Filter>http</Filter>
</ClInclude>
+ <ClInclude Include="..\..\agent\tcf\services\runctrl.h">
+ <Filter>services</Filter>
+ </ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/server/tcf/config.h b/server/tcf/config.h index 317e0a01..8612a5dc 100644 --- a/server/tcf/config.h +++ b/server/tcf/config.h @@ -151,6 +151,10 @@ #define ENABLE_ContextExtraProperties 0 #endif +#if !defined(ENABLE_ServiceOverride) +#define ENABLE_ServiceOverride 0 +#endif + #define ENABLE_RCBP_TEST 0 #define ENABLE_ContextMemoryProperties 0 diff --git a/server/tcf/main/server.c b/server/tcf/main/server.c index 9b3996e8..0968be2b 100644 --- a/server/tcf/main/server.c +++ b/server/tcf/main/server.c @@ -31,6 +31,8 @@ #include <tcf/services/pathmap.h> #include <tcf/services/disassembly.h> #include <tcf/services/context-proxy.h> +#include <tcf/services/stacktrace.h> +#include <tcf/services/memorymap.h> #include <tcf/main/server.h> #include <tcf/main/server_hooks.h> @@ -46,6 +48,11 @@ #define SERVER_ADDPROP_HOOK do {} while(0) #endif +/* Hook for initializing extra services */ +#ifndef EXTRA_SERVICE_INIT_HOOK +#define EXTRA_SERVICE_INIT_HOOK do {} while(0) +#endif + #ifndef PROXY_NAME #define PROXY_NAME "TCF Proxy" #endif @@ -94,6 +101,12 @@ static void channel_redirection_listener(Channel * host, Channel * target) { #if SERVICE_Disassembly int service_da = 0; #endif +#if SERVICE_StackTrace + int service_st = 0; +#endif +#if SERVICE_MemoryMap + int service_mm = 0; +#endif #if ENABLE_DebugContext && ENABLE_ContextProxy int forward_pm = 0; #endif @@ -103,20 +116,29 @@ static void channel_redirection_listener(Channel * host, Channel * target) { * services below are defined (note that nm may be used * in TARGET_SERVICE_CHECK_HOOK() macro). */ (void)nm; +#if !ENABLE_ServiceOverride #if SERVICE_LineNumbers if (strcmp(nm, "LineNumbers") == 0) service_ln = 1; #endif #if SERVICE_Symbols if (strcmp(nm, "Symbols") == 0) service_sm = 1; #endif +#if SERVICE_Disassembly + if (strcmp(nm, "Disassembly") == 0) service_da = 1; +#endif +#if SERVICE_StackTrace + if (strcmp(nm, "StackTrace") == 0) service_st = 1; +#endif +#if SERVICE_MemoryMap + if (strcmp(nm, "MemoryMap") == 0) service_mm = 1; +#endif +#endif /* ENABLE_ServiceOverride */ + #if SERVICE_PathMap # if ENABLE_DebugContext && ENABLE_ContextProxy if (strcmp(nm, "PathMap") == 0) service_pm = 1; # endif #endif -#if SERVICE_Disassembly - if (strcmp(nm, "Disassembly") == 0) service_da = 1; -#endif TARGET_SERVICE_CHECK_HOOK; } #if SERVICE_PathMap @@ -134,9 +156,18 @@ static void channel_redirection_listener(Channel * host, Channel * target) { #if SERVICE_Disassembly if (!service_da) ini_disassembly_service(host->protocol); #endif +#if SERVICE_StackTrace + if (!service_st) ini_stack_trace_service(host->protocol, + EXT(host)->serv->bcg); +#endif +#if SERVICE_MemoryMap + if (!service_mm) ini_memory_map_service(host->protocol, + EXT(host)->serv->bcg); +#endif #if SERVICE_Expressions ini_expressions_service(host->protocol); #endif + EXTRA_SERVICE_INIT_HOOK; #if ENABLE_DebugContext && ENABLE_ContextProxy create_context_proxy(host, target, forward_pm); #endif diff --git a/server/tcf/services/context-proxy.c b/server/tcf/services/context-proxy.c index 4b8264ec..483fd221 100644 --- a/server/tcf/services/context-proxy.c +++ b/server/tcf/services/context-proxy.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2016 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2019 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. @@ -190,6 +190,7 @@ struct PeerCache { ForwardingInputStream fwd_buf; InputStream * bck_inp; InputStream * fwd_inp; + int cache_lock; /* Initial Run Control context tree retrieval */ int rc_done; @@ -237,9 +238,11 @@ static char * str_buf = NULL; static unsigned str_buf_max = 0; static unsigned str_buf_pos = 0; +#if !SERVICE_MemoryMap static MMListener * mm_listeners = NULL; static unsigned mm_listener_cnt = 0; static unsigned mm_listener_max = 0; +#endif static size_t context_extension_offset = 0; @@ -252,6 +255,8 @@ static const char PATH_MAP[] = "PathMap"; static const char MEMORY[] = "Memory"; static const char REGISTERS[] = "Registers"; +static unsigned pending_cache_cnt = 0; + #if ENABLE_ContextMux /* * When Context Multiplexer is enabled, all context APIs must be defined even for proxy context @@ -957,6 +962,19 @@ static void command_path_map_set(char * token, Channel * c, void * args) { json_test_char(p->fwd_inp, MARKER_EOM); } +static ReplyHandlerInfo * send_command(PeerCache * p, + const char * service, const char * name, ReplyHandlerCB handler, void * client_data) { + if (pending_cache_cnt > 0 && p->cache_lock == 0) { + OutputStream * out = &p->target->out; + write_stringz(out, "E"); + write_stringz(out, CONTEXT_PROXY); + write_stringz(out, "lock"); + write_stream(out, MARKER_EOM); + p->cache_lock = 1; + } + return protocol_send_command(p->target, service, name, handler, client_data); +} + static void validate_peer_cache_children(Channel * c, void * args, int error); void create_context_proxy(Channel * host, Channel * target, int forward_pm) { @@ -988,7 +1006,7 @@ void create_context_proxy(Channel * host, Channel * target, int forward_pm) { add_event_handler2(target, REGISTERS, "registerChanged", event_register_changed, p); if (forward_pm) add_command_handler2(host->protocol, PATH_MAP, "set", command_path_map_set, p); /* Retrieve initial set of run control contexts */ - protocol_send_command(p->target, RUN_CONTROL, "getChildren", validate_peer_cache_children, p); + send_command(p, RUN_CONTROL, "getChildren", validate_peer_cache_children, p); write_stringz(&p->target->out, "null"); write_stream(&p->target->out, MARKER_EOM); p->rc_pending_cnt++; @@ -1007,7 +1025,7 @@ static void read_rc_children_item(InputStream * inp, void * args) { ContextCache * c = (ContextCache *)loc_alloc_zero(sizeof(ContextCache)); strcpy(c->id, id); c->peer = p; - protocol_send_command(p->target, RUN_CONTROL, "getContext", validate_peer_cache_context, c); + send_command(p, RUN_CONTROL, "getContext", validate_peer_cache_context, c); json_write_string(&p->target->out, c->id); write_stream(&p->target->out, 0); write_stream(&p->target->out, MARKER_EOM); @@ -1083,7 +1101,7 @@ static void validate_peer_cache_context(Channel * c, void * args, int error) { free_context_cache(x); } else if (x->has_state) { - protocol_send_command(p->target, RUN_CONTROL, "getState", validate_peer_cache_state, x); + send_command(p, RUN_CONTROL, "getState", validate_peer_cache_state, x); json_write_string(&p->target->out, x->id); write_stream(&p->target->out, 0); write_stream(&p->target->out, MARKER_EOM); @@ -1091,7 +1109,7 @@ static void validate_peer_cache_context(Channel * c, void * args, int error) { } else { add_context_cache(p, x); - protocol_send_command(p->target, RUN_CONTROL, "getChildren", validate_peer_cache_children, p); + send_command(p, RUN_CONTROL, "getChildren", validate_peer_cache_children, p); json_write_string(&p->target->out, x->id); write_stream(&p->target->out, 0); write_stream(&p->target->out, MARKER_EOM); @@ -1142,7 +1160,7 @@ static void validate_peer_cache_state(Channel * c, void * args, int error) { if (x->intercepted) { clear_context_cache(x); } - protocol_send_command(p->target, RUN_CONTROL, "getChildren", validate_peer_cache_children, p); + send_command(p, RUN_CONTROL, "getChildren", validate_peer_cache_children, p); json_write_string(&p->target->out, x->id); write_stream(&p->target->out, 0); write_stream(&p->target->out, MARKER_EOM); @@ -1325,7 +1343,7 @@ int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t s m->addr = address; m->buf = loc_alloc(size); m->size = size; - m->pending = protocol_send_command(c, "Memory", "get", validate_memory_cache, m); + m->pending = send_command(cache->peer, MEMORY, "get", validate_memory_cache, m); json_write_string(&c->out, cache->ctx->id); write_stream(&c->out, 0); json_write_int64(&c->out, m->addr); @@ -1489,7 +1507,7 @@ int read_reg_bytes(StackFrame * frame, RegisterDefinition * reg_def, unsigned of if (is_channel_closed(c)) exception(ERR_CHANNEL_CLOSED); if (fc->pending != NULL) cache_wait(&fc->cache); fc->reg_pending = rn; - fc->pending = protocol_send_command(c, "Registers", "get", validate_top_frame_reg_values_cache, fc); + fc->pending = send_command(fc->ctx->peer, REGISTERS, "get", validate_top_frame_reg_values_cache, fc); json_write_string(&c->out, fc->ctx->reg_props[rn].id); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -1509,7 +1527,7 @@ int read_reg_bytes(StackFrame * frame, RegisterDefinition * reg_def, unsigned of if (!set_trap(&trap)) return -1; if (is_channel_closed(c)) exception(ERR_CHANNEL_CLOSED); if (fc->pending != NULL) cache_wait(&fc->cache); - fc->pending = protocol_send_command(c, "Registers", "getm", validate_mid_frame_reg_values_cache, fc); + fc->pending = send_command(fc->ctx->peer, REGISTERS, "getm", validate_mid_frame_reg_values_cache, fc); write_stream(&c->out, '['); for (n = 0; n < fc->reg_cnt; n++) { RegisterDefinition * reg = fc->reg_defs[n]; @@ -1688,11 +1706,11 @@ static ContextCache * get_memory_map_cache(Context * ctx) { assert(cache->ctx == ctx); if (!set_trap(&trap)) return NULL; if (is_channel_closed(c)) exception(ERR_CHANNEL_CLOSED); - if (cache->peer != NULL && !cache->peer->rc_done) cache_wait(&cache->peer->rc_cache); + if (!cache->peer->rc_done) cache_wait(&cache->peer->rc_cache); if (cache->pending_get_mmap != NULL) cache_wait(&cache->mmap_cache); if (cache->mmap_is_valid == 0 && cache->peer != NULL) { - cache->pending_get_mmap = protocol_send_command(c, MEMORY_MAP, "get", validate_memory_map_cache, cache); + cache->pending_get_mmap = send_command(cache->peer, MEMORY_MAP, "get", validate_memory_map_cache, cache); json_write_string(&c->out, cache->id); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -1747,6 +1765,7 @@ int context_get_memory_map(Context * ctx, MemoryMap * map) { return 0; } +#if !SERVICE_MemoryMap int memory_map_get(Context * ctx, MemoryMap ** client_map, MemoryMap ** target_map) { ContextCache * cache = get_memory_map_cache(ctx); if (cache == NULL) return -1; @@ -1774,6 +1793,7 @@ void memory_map_event_mapping_changed(Context * ctx) { l->listener->mapping_changed(ctx, l->args); } } +#endif static void read_ids_item(InputStream * inp, void * args) { int n; @@ -1854,7 +1874,7 @@ static void validate_registers_cache(Channel * c, void * args, int error) { json_test_char(&c->inp, MARKER_EOM); for (i = 0; i < ids_buf_pos; i++) { cache->pending_regs_cnt++; - protocol_send_command(c, "Registers", "getContext", validate_registers_cache, cache); + send_command(cache->peer, REGISTERS, "getContext", validate_registers_cache, cache); json_write_string(&c->out, str_buf + ids_buf[i]); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -1884,7 +1904,7 @@ static void validate_registers_cache(Channel * c, void * args, int error) { cache->reg_props[i] = props; cache->reg_defs[i] = props.def; cache->pending_regs_cnt++; - protocol_send_command(c, "Registers", "getChildren", validate_registers_cache, cache); + send_command(cache->peer, REGISTERS, "getChildren", validate_registers_cache, cache); json_write_string(&c->out, props.id); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -1928,7 +1948,7 @@ static void check_registers_cache(ContextCache * cache) { if (!cache->regs_done) { Channel * c = cache->peer->target; cache->pending_regs_cnt++; - protocol_send_command(c, "Registers", "getChildren", validate_registers_cache, cache); + send_command(cache->peer, REGISTERS, "getChildren", validate_registers_cache, cache); json_write_string(&c->out, cache->ctx->id); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -2020,7 +2040,7 @@ static void validate_stack_frame_cache(Channel * c, void * args, int error) { error = read_errno(&c->inp); json_test_char(&c->inp, MARKER_EOM); if (!error && !s->disposed && !s->info.is_top_frame) { - s->pending = protocol_send_command(c, "Registers", "getChildren", validate_reg_children_cache, s); + s->pending = send_command(s->ctx->peer, REGISTERS, "getChildren", validate_reg_children_cache, s); json_write_string(&c->out, frame2id(s->ctx->ctx, s->info.frame)); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -2088,7 +2108,7 @@ int get_frame_info(Context * ctx, int frame, StackFrame ** info) { s->info.regs = &s->reg_data; s->reg_data.data = (uint8_t *)loc_alloc_zero(cache->reg_size); s->reg_data.mask = (uint8_t *)loc_alloc_zero(cache->reg_size); - s->pending = protocol_send_command(c, "StackTrace", "getContext", validate_stack_frame_cache, s); + s->pending = send_command(cache->peer, "StackTrace", "getContext", validate_stack_frame_cache, s); write_stream(&c->out, '['); json_write_string(&c->out, id); write_stream(&c->out, ']'); @@ -2223,7 +2243,7 @@ static int get_context_defisa_from_rc(Context * ctx, ContextISA * isa) { } i->ctx = cache; - i->pending = protocol_send_command(c, "RunControl", "getISA", validate_cache_isa, i); + i->pending = send_command(cache->peer, RUN_CONTROL, "getISA", validate_cache_isa, i); json_write_string(&c->out, cache->ctx->id); write_stream(&c->out, 0); json_write_uint64(&c->out, (uint64_t)0); @@ -2244,12 +2264,12 @@ int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa) { } #endif -static void channel_close_listener(Channel * c) { +static void channel_close_listener(Channel * ch) { LINK * l = NULL; for (l = peers.next; l != &peers; l = l->next) { PeerCache * p = peers2peer(l); - if (p->target == c) { + if (p->target == ch) { int i; assert(p->rc_pending_cnt == 0); for (i = 0; i < CTX_ID_HASH_SIZE; i++) { @@ -2294,6 +2314,32 @@ static void event_path_mapping_changed(Channel * c, void * args) { } } +static void cache_transaction_listener(int e) { + switch (e) { + case CTLE_START: + pending_cache_cnt++; + break; + case CTLE_COMMIT: + assert(pending_cache_cnt > 0); + pending_cache_cnt--; + if (pending_cache_cnt == 0) { + LINK * l = NULL; + for (l = peers.next; l != &peers; l = l->next) { + PeerCache * p = peers2peer(l); + if (p->cache_lock) { + OutputStream * out = &p->target->out; + write_stringz(out, "E"); + write_stringz(out, CONTEXT_PROXY); + write_stringz(out, "unlock"); + write_stream(out, MARKER_EOM); + p->cache_lock = 0; + } + } + } + break; + } +} + void init_contexts_sys_dep(void) { static PathMapEventListener path_map_listener = { event_path_mapping_changed, @@ -2309,6 +2355,7 @@ void init_contexts_sys_dep(void) { add_path_map_event_listener(&path_map_listener, NULL); add_context_event_listener(&context_event_listener, NULL); add_channel_close_listener(channel_close_listener); + add_cache_transaction_listener(cache_transaction_listener); context_extension_offset = context_extension(sizeof(ContextCache *)); } diff --git a/tests/test-dwarf/tcf/backend/backend.c b/tests/test-dwarf/tcf/backend/backend.c index efe25df2..85243642 100644 --- a/tests/test-dwarf/tcf/backend/backend.c +++ b/tests/test-dwarf/tcf/backend/backend.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010-2018 Wind River Systems, Inc. and others. + * Copyright (c) 2010-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. @@ -387,14 +387,14 @@ static char * esc(char * s) { size_t i = 0; char * t = s; for (i = 0; s[i]; i++) { - if (s[i] == '\\') n++; + if (s[i] == '\\' || s[i] == '"') n++; } if (n > 0) { size_t sz = i + n + 1; t = (char *)tmp_alloc(sz); for (i = 0, n = 0; s[i]; i++) { + if (s[i] == '\\' || s[i] == '"') t[n++] = '\\'; t[n++] = s[i]; - if (s[i] == '\\') t[n++] = '\\'; } t[n++] = 0; assert(n == sz); @@ -559,7 +559,7 @@ static void test_variant_part(Symbol * part) { } } -static void test_composite_type(Symbol * type) { +static void test_composite_type(Symbol * type, char * var, unsigned level) { int i; int count = 0; char * type_name = NULL; @@ -583,6 +583,7 @@ static void test_composite_type(Symbol * type) { } for (i = 0; i < count; i++) { int member_class = 0; + char * member_name = NULL; Symbol * member_container = NULL; int container_class = 0; ContextAddress offs = 0; @@ -591,6 +592,9 @@ static void test_composite_type(Symbol * type) { if (get_symbol_class(children[i], &member_class) < 0) { error_sym("get_symbol_class", children[i]); } + if (get_symbol_name(children[i], &member_name) < 0) { + error_sym("get_symbol_name", children[i]); + } if (get_symbol_container(children[i], &member_container) < 0) { error_sym("get_symbol_container", children[i]); } @@ -614,6 +618,7 @@ static void test_composite_type(Symbol * type) { if (member_class == SYM_CLASS_REFERENCE) { Symbol * member_type = NULL; int member_type_class = 0; + LocationInfo * member_loc_info = NULL; if (get_symbol_type(children[i], &member_type) < 0) { error_sym("get_symbol_type", children[i]); } @@ -639,9 +644,8 @@ static void test_composite_type(Symbol * type) { else if (!is_cpp_reference(member_type)) { Value v; uint64_t n = 0; - char * expr = (char *)tmp_alloc(512); unsigned base = (rand() & 0xffff) << 4; - sprintf(expr, "&(((${%s} *)%u)->${%s})", tmp_strdup(symbol2id(type)), base, tmp_strdup(symbol2id(children[i]))); + char * expr = tmp_printf("&(((${%s} *)%u)->${%s})", tmp_strdup(symbol2id(type)), base, tmp_strdup(symbol2id(children[i]))); if (evaluate_expression(elf_ctx, STACK_TOP_FRAME, 0, expr, 0, &v) < 0) { error("evaluate_expression"); } @@ -654,12 +658,43 @@ static void test_composite_type(Symbol * type) { } } } + if (get_location_info(children[i], &member_loc_info) < 0) { +#if 0 + error("get_location_info"); +#endif + member_loc_info = NULL; + } if (get_symbol_size(children[i], &size) < 0) { error_sym("get_symbol_size", children[i]); } if (member_type_class == TYPE_CLASS_ARRAY && get_symbol_length(children[i], &length) < 0) { error_sym("get_symbol_length", children[i]); } + if (var != NULL && member_loc_info != NULL) { + Value v; + char * expr = tmp_printf("%s.${%s}", var, symbol2id(children[i])); + if (evaluate_expression(elf_ctx, STACK_TOP_FRAME, 0, expr, 0, &v) < 0) { + error("evaluate_expression"); + } + if (member_name != NULL) { + expr = tmp_printf("%s.$\"%s\"", var, esc(member_name)); + if (evaluate_expression(elf_ctx, STACK_TOP_FRAME, 0, expr, 0, &v) < 0) { + error("evaluate_expression"); + } + } + if (member_type_class != v.type_class) { + if (member_type_class == TYPE_CLASS_POINTER && is_cpp_reference(member_type)) { + /* OK */ + } + else { + errno = ERR_OTHER; + error("invalid result of evaluate_expression"); + } + } + if (member_type_class == TYPE_CLASS_COMPOSITE && level < 4) { + test_composite_type(member_type, expr, level + 1); + } + } } else if (member_class == SYM_CLASS_VALUE) { void * value = NULL; @@ -1219,6 +1254,15 @@ static void loc_var_func(void * args, Symbol * sym) { if (!addr_ok) continue; error_sym("evaluate_expression", sym); } + if (v.loc != NULL) { + unsigned i, n = 0; + for (i = 0; i < v.loc->pieces_cnt; i++) { + if (v.loc->pieces[i].implicit_pointer) n++; + } + if (v.loc->pieces_cnt == n) continue; + set_errno(ERR_OTHER, "Unexpected location pieces"); + error_sym("evaluate_expression", sym); + } if (!addr_ok) { set_errno(ERR_OTHER, "Expression expected to return error"); error_sym("evaluate_expression", sym); @@ -1247,7 +1291,10 @@ static void loc_var_func(void * args, Symbol * sym) { if (evaluate_expression(elf_ctx, frame, pc, expr, 0, &v) < 0) { error_sym("evaluate_expression", sym); } - if (v.size != (elf_file->elf64 ? 8 : 4)) { + if (v.loc != NULL) { + /* Implicit pointer */ + } + else if (v.size != (elf_file->elf64 ? 8 : 4)) { errno = ERR_INV_ADDRESS; error_sym("evaluate_expression", sym); } @@ -1490,8 +1537,14 @@ static void loc_var_func(void * args, Symbol * sym) { error_sym("get_symbol_size", base_type); } if (base_type_size * length > size) { - errno = ERR_OTHER; - error("Invalid size of base type"); + ObjectInfo * obj = get_symbol_object(sym); + if (obj != NULL && obj->mDefinition != NULL && obj->mDefinition != obj) { + /* Size of object declaration can differ from real size */ + } + else { + errno = ERR_OTHER; + error("Invalid size of base type"); + } } } if (get_symbol_lower_bound(sym, &lower_bound) < 0) { @@ -1531,13 +1584,25 @@ static void loc_var_func(void * args, Symbol * sym) { test_enumeration_type(type); } else if (type_class == TYPE_CLASS_COMPOSITE) { - test_composite_type(type); + char * var = NULL; + ContextAddress type_size = 0; + if (symbol_class == SYM_CLASS_REFERENCE && loc_state != NULL) { + if (get_symbol_size(type, &type_size) < 0) error_sym("get_symbol_size", type); + if (loc_state->pieces_cnt == 1 && loc_state->pieces->reg != NULL && loc_state->pieces->reg->size < type_size) { + /* Either incorrect register definition or invalid debug info. + * Skip access test - it will fail. */ + } + else { + var = tmp_printf("${%s}", symbol2id(sym)); + } + } + test_composite_type(type, var, 0); } else if (type_class == TYPE_CLASS_POINTER) { if (base_type_class == TYPE_CLASS_COMPOSITE && (flags & SYM_FLAG_PARAMETER) && (flags & SYM_FLAG_ARTIFICIAL) && name != NULL && strcmp(name, "this") == 0) { - test_composite_type(base_type); + test_composite_type(base_type, NULL, 0); test_this_pointer(base_type); } } @@ -1594,19 +1659,28 @@ static void test_public_names(void) { if (find_symbol_by_name(elf_ctx, STACK_NO_FRAME, 0, obj->mName, &sym1) < 0) { error("find_symbol_by_name"); } - if (obj->mCompUnit->mLanguage == LANG_C) { + for (;;) { + if (get_symbol_object(sym1) == obj) break; + if (find_next_symbol(&sym1) == 0) continue; + set_errno(ERR_OTHER, "Cannot find symbol by name"); + error("find_symbol_by_name"); + } + if (obj->mCompUnit->mLanguage == LANG_C || obj->mCompUnit->mLanguage == LANG_C89 || + obj->mCompUnit->mLanguage == LANG_C99 || obj->mCompUnit->mLanguage == LANG_C11) { /* Note: this test fails for C++ because of name overloading */ - SYM_FLAGS flags = 0; - if (get_symbol_flags(sym1, &flags) < 0) error("get_symbol_flags"); - if (obj->mTag == TAG_subprogram && (flags & SYM_FLAG_EXTERNAL) != 0 && get_symbol_address(sym1, &addr) == 0) { - /* Check weak symbol is not the first symbol */ - while (find_next_symbol(&sym2) == 0) { - ContextAddress nxt_addr = 0; - if (get_symbol_object(sym2) == NULL && get_symbol_address(sym2, &nxt_addr) == 0) { - if (get_symbol_flags(sym2, &flags) < 0) error("get_symbol_flags"); - if ((flags & SYM_FLAG_EXTERNAL) != 0 && addr != nxt_addr) { - set_errno(ERR_OTHER, "Invalid address - weak symbol?"); - error("find_symbol_by_name"); + if (obj->mTag == TAG_subprogram && (obj->mFlags & DOIF_inlined) == 0) { + SYM_FLAGS flags = 0; + if (get_symbol_flags(sym1, &flags) < 0) error("get_symbol_flags"); + if ((flags & SYM_FLAG_EXTERNAL) != 0 && get_symbol_address(sym1, &addr) == 0) { + /* Check weak symbol is not the first symbol */ + while (find_next_symbol(&sym2) == 0) { + ContextAddress nxt_addr = 0; + if (get_symbol_object(sym2) == NULL && get_symbol_address(sym2, &nxt_addr) == 0) { + if (get_symbol_flags(sym2, &flags) < 0) error("get_symbol_flags"); + if ((flags & SYM_FLAG_EXTERNAL) != 0 && addr != nxt_addr) { + set_errno(ERR_OTHER, "Invalid address - weak symbol?"); + error("find_symbol_by_name"); + } } } } @@ -1813,7 +1887,16 @@ static void next_region(void) { error_sym("get_symbol_address", sym); } if (get_symbol_size(sym, &func_size) < 0) { - error_sym("get_symbol_size", sym); + int error = errno; + if (errcmp(error, "Object has no size attribute") == 0 && + func_object != NULL && (func_object->mFlags & DOIF_ranges)) { + // OK - function with ranges + assert(func_size == 0); + } + else { + errno = error; + error_sym("get_symbol_size", sym); + } } if (get_symbol_flags(sym, &flags) < 0) { error_sym("get_symbol_flags", sym); @@ -1861,8 +1944,14 @@ static void next_region(void) { } } if (pc < func_addr || (func_size > 0 && pc >= func_addr + func_size)) { - errno = ERR_OTHER; - error("invalid symbol address"); + if (func_object != NULL && (func_object->mFlags & DOIF_ranges)) { + // OK - function with ranges + assert(func_size == 0); + } + else { + errno = ERR_OTHER; + error("invalid symbol address"); + } } if (func_name != NULL) { Symbol * fnd_sym = NULL; @@ -1894,7 +1983,12 @@ static void next_region(void) { if (get_symbol_address(fnd_sym, &fnd_addr) == 0) { Value v; SYM_FLAGS flags = 0; + ContextAddress exp_addr = 0; + int fnd_class = 0; char * expr = (char *)tmp_alloc(strlen(func_name) + 16); + if (get_symbol_class(fnd_sym, &fnd_class) < 0) { + error_sym("get_symbol_class", fnd_sym); + } if (get_symbol_flags(fnd_sym, &flags) < 0) { error_sym("get_symbol_flags", fnd_sym); } @@ -1902,6 +1996,27 @@ static void next_region(void) { if (evaluate_expression(elf_ctx, STACK_TOP_FRAME, 0, expr, 0, &v) < 0) { error_sym("evaluate_expression", fnd_sym); } + if (fnd_class == SYM_CLASS_FUNCTION) { + if (value_to_address(&v, &exp_addr) < 0) { + error_sym("value_to_address", fnd_sym); + } + if (fnd_addr != exp_addr) { + error_sym("fnd_addr != exp_addr", fnd_sym); + } + } + sprintf(expr, "&$\"%s\"", esc(func_name)); + if (evaluate_expression(elf_ctx, STACK_TOP_FRAME, 0, expr, 0, &v) < 0) { + error_sym("evaluate_expression", fnd_sym); + } + if (value_to_address(&v, &exp_addr) < 0) { + error_sym("value_to_address", fnd_sym); + } + if (fnd_addr != exp_addr) { + error_sym("fnd_addr != exp_addr", fnd_sym); + } + if (fnd_class == SYM_CLASS_FUNCTION && v.sym == NULL) { + error_sym("v.sym == NULL", fnd_sym); + } if (flags & SYM_FLAG_EXTERNAL) { if (find_symbol_by_name(elf_ctx, STACK_NO_FRAME, 0, func_name, &fnd_sym) < 0) { if (get_error_code(errno) == ERR_SYM_NOT_FOUND && func_object != NULL && func_object->mParent->mTag == TAG_namespace) { @@ -2111,7 +2226,7 @@ static void next_region(void) { } clear_trap(&trap); } - else if (trap.error != ERR_SYM_NOT_FOUND) { + else if (get_error_code(trap.error) != ERR_SYM_NOT_FOUND) { error("AT_frame_base"); } } @@ -2259,9 +2374,6 @@ static void next_file(void) { r->dev = st.st_dev; r->ino = st.st_ino; } - if (r != NULL && (p->flags & PF_X) == 0 && (r->addr + r->size) % p->align != 0) { - r->size = r->size + p->align - (r->addr + r->size) % p->align; - } } } @@ -2349,11 +2461,11 @@ static void test(void * args) { test_posted = 0; if (elf_file_name == NULL || mem_region_pos >= (int)mem_map.region_cnt) { if (file_has_line_info) { + check_line_info(); if (line_info_cnt == 0) { set_errno(ERR_OTHER, "Line info not accessable"); error("address_to_line"); } - check_line_info(); } next_file(); } |