Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md45
-rw-r--r--agent/Makefile4
-rw-r--r--agent/Makefile.inc35
-rwxr-xr-xagent/bin/create-agent-project328
-rw-r--r--agent/machine/a64/tcf/cpudefs-mdep.c243
-rw-r--r--agent/machine/a64/tcf/cpudefs-mdep.h16
-rw-r--r--agent/machine/a64/tcf/dwarfreloc-mdep.h6
-rw-r--r--agent/machine/a64/tcf/regset-mdep.h31
-rw-r--r--agent/machine/a64/tcf/stack-crawl-a64.c46
-rw-r--r--agent/machine/arm/tcf/cpudefs-mdep.c357
-rw-r--r--agent/machine/arm/tcf/disassembler-arm.c47
-rw-r--r--agent/machine/arm/tcf/disassembler-arm.h8
-rw-r--r--agent/machine/arm/tcf/disassembler-thumb.c61
-rw-r--r--agent/machine/arm/tcf/dwarfreloc-mdep.h6
-rw-r--r--agent/machine/arm/tcf/regset-mdep.h13
-rw-r--r--agent/machine/arm/tcf/stack-crawl-arm-ext.h2
-rw-r--r--agent/machine/arm/tcf/stack-crawl-arm.c150
-rw-r--r--agent/machine/i386/tcf/cpu-regs-gdb.h4
-rw-r--r--agent/machine/i386/tcf/dwarfreloc-mdep.h4
-rw-r--r--agent/machine/i386/tcf/regset-mdep.h37
-rw-r--r--agent/machine/i686/tcf/regset-mdep.h37
-rw-r--r--agent/machine/microblaze/tcf/disassembler-microblaze.c35
-rw-r--r--agent/machine/microblaze/tcf/dwarfreloc-mdep.h4
-rw-r--r--agent/machine/microblaze/tcf/stack-crawl-microblaze.c23
-rw-r--r--agent/machine/powerpc/tcf/cpudefs-mdep.c2
-rw-r--r--agent/machine/powerpc/tcf/dwarfreloc-mdep.h4
-rw-r--r--agent/machine/ppc64/tcf/dwarfreloc-mdep.h4
-rw-r--r--agent/machine/riscv/tcf/cpu-regs-gdb.h61
-rw-r--r--agent/machine/riscv/tcf/disassembler-riscv.c1880
-rw-r--r--agent/machine/riscv/tcf/disassembler-riscv.h32
-rw-r--r--agent/machine/riscv/tcf/stack-crawl-riscv.c1505
-rw-r--r--agent/machine/riscv/tcf/stack-crawl-riscv.h31
-rw-r--r--agent/machine/riscv/tcf/uxlen.h221
-rw-r--r--agent/machine/riscv64/tcf/cpu-regs-gdb.h61
-rw-r--r--agent/machine/riscv64/tcf/cpudefs-mdep.c244
-rw-r--r--agent/machine/riscv64/tcf/cpudefs-mdep.h15
-rw-r--r--agent/machine/riscv64/tcf/disassembler-riscv64.c16
-rw-r--r--agent/machine/riscv64/tcf/disassembler-riscv64.h16
-rw-r--r--agent/machine/riscv64/tcf/dwarfreloc-mdep.h118
-rw-r--r--agent/machine/riscv64/tcf/regset-mdep.h2
-rw-r--r--agent/machine/riscv64/tcf/stack-crawl-riscv64.c16
-rw-r--r--agent/machine/riscv64/tcf/stack-crawl-riscv64.h16
-rw-r--r--agent/machine/sparc/tcf/dwarfreloc-mdep.h4
-rw-r--r--agent/machine/x86_64/tcf/cpu-regs-gdb.h4
-rw-r--r--agent/machine/x86_64/tcf/cpudefs-mdep.c237
-rw-r--r--agent/machine/x86_64/tcf/cpudefs-mdep.h2
-rw-r--r--agent/machine/x86_64/tcf/disassembler-x86_64.c1957
-rw-r--r--agent/machine/x86_64/tcf/disassembler-x86_64.h5
-rw-r--r--agent/machine/x86_64/tcf/dwarfreloc-mdep.h10
-rw-r--r--agent/machine/x86_64/tcf/regset-mdep.h48
-rw-r--r--agent/msvc/agent-vc2015.vcxproj20
-rw-r--r--agent/msvc/agent-vc2015.vcxproj.filters36
-rw-r--r--agent/system/GNU/Linux/tcf/context-linux.c517
-rw-r--r--agent/system/Windows/tcf/context-win32.c6
-rw-r--r--agent/system/Windows/tcf/pthreads-win32.c36
-rw-r--r--agent/system/Windows/tcf/pthreads-win32.h2
-rw-r--r--agent/system/Windows/tcf/windbgcache.c4
-rw-r--r--agent/system/Windows/tcf/windbgcache.h2
-rw-r--r--agent/tcf/config.h2
-rw-r--r--agent/tcf/framework/asyncreq.c62
-rw-r--r--agent/tcf/framework/cache.c18
-rw-r--r--agent/tcf/framework/cache.h3
-rw-r--r--agent/tcf/framework/channel.c8
-rw-r--r--agent/tcf/framework/channel_lws.c4
-rw-r--r--agent/tcf/framework/channel_tcp.c104
-rw-r--r--agent/tcf/framework/compression.c2
-rw-r--r--agent/tcf/framework/config.h2
-rw-r--r--agent/tcf/framework/context.c12
-rw-r--r--agent/tcf/framework/context.h6
-rw-r--r--agent/tcf/framework/cpudefs-ext.h17
-rw-r--r--agent/tcf/framework/cpudefs.c111
-rw-r--r--agent/tcf/framework/cpudefs.h34
-rw-r--r--agent/tcf/framework/errors.c37
-rw-r--r--agent/tcf/framework/errors.h3
-rw-r--r--agent/tcf/framework/events.c2
-rw-r--r--agent/tcf/framework/inputbuf.c8
-rw-r--r--agent/tcf/framework/json.c39
-rw-r--r--agent/tcf/framework/mdep-inet.h9
-rw-r--r--agent/tcf/framework/mdep-ptrace.h9
-rw-r--r--agent/tcf/framework/mdep-threads.h8
-rw-r--r--agent/tcf/framework/mdep.c224
-rw-r--r--agent/tcf/framework/mdep.h64
-rw-r--r--agent/tcf/framework/myalloc.c85
-rw-r--r--agent/tcf/framework/myalloc.h5
-rw-r--r--agent/tcf/framework/streams.c15
-rw-r--r--agent/tcf/framework/tcf.h4
-rw-r--r--agent/tcf/framework/trace.c14
-rw-r--r--agent/tcf/framework/trace.h20
-rw-r--r--agent/tcf/framework/waitpid.c12
-rw-r--r--agent/tcf/framework/waitpid.h6
-rw-r--r--agent/tcf/http/http-tcf.c95
-rw-r--r--agent/tcf/http/http-tcf.h3
-rw-r--r--agent/tcf/http/http.c129
-rw-r--r--agent/tcf/http/http.h4
-rw-r--r--agent/tcf/main/cmdline.c6
-rw-r--r--agent/tcf/main/gdb-rsp.c210
-rw-r--r--agent/tcf/main/logfilter.c8
-rw-r--r--agent/tcf/main/main.c19
-rw-r--r--agent/tcf/main/main_lua.c6
-rw-r--r--agent/tcf/main/tcf-agent.spec2
-rw-r--r--agent/tcf/main/test.c91
-rw-r--r--agent/tcf/services/breakpoints.c301
-rw-r--r--agent/tcf/services/breakpoints.h12
-rw-r--r--agent/tcf/services/contextreset.h1
-rw-r--r--agent/tcf/services/disassembly.c41
-rw-r--r--agent/tcf/services/disassembly.h7
-rw-r--r--agent/tcf/services/dprintf.c4
-rw-r--r--agent/tcf/services/dwarf.h137
-rw-r--r--agent/tcf/services/dwarfcache.c611
-rw-r--r--agent/tcf/services/dwarfcache.h79
-rw-r--r--agent/tcf/services/dwarfecomp.c200
-rw-r--r--agent/tcf/services/dwarfexpr.c214
-rw-r--r--agent/tcf/services/dwarfframe.c77
-rw-r--r--agent/tcf/services/dwarfio.c610
-rw-r--r--agent/tcf/services/dwarfio.h27
-rw-r--r--agent/tcf/services/dwarfreloc.c77
-rw-r--r--agent/tcf/services/elf-loader.c113
-rw-r--r--agent/tcf/services/elf-symbols.h4
-rw-r--r--agent/tcf/services/expressions.c1072
-rw-r--r--agent/tcf/services/filesystem.c2
-rw-r--r--agent/tcf/services/funccall.c26
-rw-r--r--agent/tcf/services/linenumbers_elf.c26
-rw-r--r--agent/tcf/services/memorymap.c83
-rw-r--r--agent/tcf/services/memorymap.h2
-rw-r--r--agent/tcf/services/memoryservice.c139
-rw-r--r--agent/tcf/services/pathmap.c81
-rw-r--r--agent/tcf/services/pathmap.h7
-rw-r--r--agent/tcf/services/processes.c8
-rw-r--r--agent/tcf/services/profiler.c2
-rw-r--r--agent/tcf/services/profiler_sst.c11
-rw-r--r--agent/tcf/services/registers.c203
-rw-r--r--agent/tcf/services/runctrl.c410
-rw-r--r--agent/tcf/services/runctrl.h13
-rw-r--r--agent/tcf/services/stacktrace-ext.h15
-rw-r--r--agent/tcf/services/stacktrace.c192
-rw-r--r--agent/tcf/services/streamsservice.c111
-rw-r--r--agent/tcf/services/symbols.c35
-rw-r--r--agent/tcf/services/symbols.h15
-rw-r--r--agent/tcf/services/symbols_common.c2
-rw-r--r--agent/tcf/services/symbols_elf.c729
-rw-r--r--agent/tcf/services/symbols_mux.c10
-rw-r--r--agent/tcf/services/symbols_proxy.c272
-rw-r--r--agent/tcf/services/sysmon.c2
-rw-r--r--agent/tcf/services/tcf_elf.c217
-rw-r--r--agent/tcf/services/tcf_elf.h28
-rw-r--r--agent/tcf/services/terminals.c16
-rw-r--r--agent/tcf/services/vm.c293
-rw-r--r--cmake-tcf-lib.txt6
-rw-r--r--docker/Dockerfile26
-rw-r--r--docker/README.md30
-rwxr-xr-xdocker/build-agents.sh13
-rw-r--r--examples/daytime/readme.txt4
-rw-r--r--server/msvc/server-vc2015.vcxproj2
-rw-r--r--server/msvc/server-vc2015.vcxproj.filters6
-rw-r--r--server/tcf/config.h4
-rw-r--r--server/tcf/main/server.c37
-rw-r--r--server/tcf/services/context-proxy.c85
-rw-r--r--tests/test-dwarf/tcf/backend/backend.c174
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(&reg_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(&reg_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(&reg_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, &reg_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, &reg_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(&reg_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, &reg_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, &reg_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, &reg_num) < 0) return -1;
+ if (id2reg_num(id, &ctx_id, frame, &reg_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(&registers_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), &section, &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), &section, &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), &section, &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, &section, &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, &section, &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(&reg_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, &reg_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, &reg_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, &reg_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), &reg_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(&notifications)) {
+ 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 != &notifications; 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, &notifications);
- 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(&registers_listener, bcg);
+ add_registers_event_listener(&registers_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();
}

Back to the top