diff --git a/samples/Basic_Debug/.cproject b/samples/Basic_Debug/.cproject
new file mode 100644
index 0000000..e70c39e
--- /dev/null
+++ b/samples/Basic_Debug/.cproject
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/Basic_Debug/.project b/samples/Basic_Debug/.project
new file mode 100644
index 0000000..c82d25f
--- /dev/null
+++ b/samples/Basic_Debug/.project
@@ -0,0 +1,28 @@
+
+
+ Basic_Debug
+
+
+ SmingFramework
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/samples/Basic_Debug/Makefile b/samples/Basic_Debug/Makefile
new file mode 100644
index 0000000..16d76cd
--- /dev/null
+++ b/samples/Basic_Debug/Makefile
@@ -0,0 +1,24 @@
+#####################################################################
+#### Please don't change this file. Use Makefile-user.mk instead ####
+#####################################################################
+# Including user Makefile.
+# Should be used to set project-specific parameters
+include ./Makefile-user.mk
+
+# Important parameters check.
+# We need to make sure SMING_HOME and ESP_HOME variables are set.
+# You can use Makefile-user.mk in each project or use enviromental variables to set it globally.
+
+ifndef SMING_HOME
+$(error SMING_HOME is not set. Please configure it in Makefile-user.mk)
+endif
+ifndef ESP_HOME
+$(error ESP_HOME is not set. Please configure it in Makefile-user.mk)
+endif
+
+# Include main Sming Makefile
+ifeq ($(RBOOT_ENABLED), 1)
+include $(SMING_HOME)/Makefile-rboot.mk
+else
+include $(SMING_HOME)/Makefile-project.mk
+endif
diff --git a/samples/Basic_Debug/Makefile-user.mk b/samples/Basic_Debug/Makefile-user.mk
new file mode 100644
index 0000000..9eb219a
--- /dev/null
+++ b/samples/Basic_Debug/Makefile-user.mk
@@ -0,0 +1,33 @@
+## Local build configuration
+## Parameters configured here will override default and ENV values.
+## Uncomment and change examples:
+
+#Add your source directories here separated by space
+MODULES = app
+
+## ESP_HOME sets the path where ESP tools and SDK are located.
+## Windows:
+# ESP_HOME = c:/Espressif
+
+## MacOS / Linux:
+#ESP_HOME = /opt/esp-open-sdk
+
+## SMING_HOME sets the path where Sming framework is located.
+## Windows:
+# SMING_HOME = c:/tools/sming/Sming
+
+# MacOS / Linux
+# SMING_HOME = /opt/sming/Sming
+
+## COM port parameter is reqruied to flash firmware correctly.
+## Windows:
+# COM_PORT = COM3
+
+# MacOS / Linux:
+# COM_PORT = /dev/tty.usbserial
+
+# Com port speed
+# COM_SPEED = 115200
+ENABLE_GDB=1
+
+DISABLE_SPIFFS=1
diff --git a/samples/Basic_Debug/README.md b/samples/Basic_Debug/README.md
new file mode 100644
index 0000000..335fc9d
--- /dev/null
+++ b/samples/Basic_Debug/README.md
@@ -0,0 +1,81 @@
+This project is an example of how to integrate GDB debugging into your project.
+It relies on the GDBStub project to do the heavy-lifting.
+
+Exception Handling
+------------------
+If there is an exception in your code usually ESP prints a message like the following one:
+
+```
+Fatal exception (0):
+epc1=0x4020997c, epc2=0x00000000, epc3=0x00000000, excvaddr=0x00000000, depc=0x00000000
+```
+
+That information can help you discover the function call that caused the exception.
+Using the value of epc1 and executing a command like the one below:
+
+```bash
+xtensa-lx106-elf-objdump -dtr out/build/app.out | grep 4020997c
+```
+
+can give you an idea about the function. In my test case this is:
+```
+4020997c: fffe61 l32r a6, 40209974
+```
+
+But that information might not be enough to find the issue. And finding the
+root cause may take quite some time.
+
+GDB Debugging
+-------------
+Debugging is a powerful technique giving better understanding of the code and
+the things that went wrong.
+
+There is already existing GDBStub that tries to make it easier to use software
+debugger. And this project is an example of what you need to do in order to
+integrate it.
+
+Here are the commands that you need to execute:
+
+1. You will need a version of the SmingRTOS library with enabled GDBStub functionality.
+For that purpose you should compile SmingRTOS with ENABLE_GDB flag. Under Linux
+you should do the following:
+
+```bash
+cd /SmingRTOS
+make clean
+make ENABLE_GDB=1
+```
+
+2. In your project inside of your Makefile-user.mk file you should add the following
+variable:
+
+```make
+ENABLE_GDB=1
+```
+
+If you are looking for an example then take a look at the Makefile-user.mk file
+that is in the same directory as this README.md file.
+
+3. Now compile your project and flash it to the board.
+```bash
+make
+make flash
+```
+
+4. Run gdb immediately after resetting the board or after it has run into an exception.
+The easiest way to do it is to use the provided script:
+```bash
+xtensa-lx106-elf-gdb -x /Basic_Debug/gdbcmds -b 115200
+```
+
+115200 stands for the baud rate your program is using. Change it accordingly.
+You may also need to change the gdbcmds script to fit the configuration of your hardware and build environment.
+
+7. Software breakpoints ('br') only work on code that is in RAM. During development you can use the GDB_IRAM_ATTR attribute in your function declarations.
+Code in flash can only have a hardware breakpoint ('hbr').
+
+8. If you need help working with the command line debugger or with the visual debugger in Eclipse then take a look at that article [Live debugging with open-source tools](https://blog.attachix.com/live-debugging-with-open-source-tools-programming-for-esp8266-part-4/). The paragraphs that you should read are named **"Live Debugging with GDB from Command Line"** and **"Live Debugging with Eclipse CDT"**.
+
+9. Recommended GDB version - make sure that you have version 7.5.x or newer. Windows users can download GDB.exe with the recommended version from [here](http://sysprogs.com/files/gnutoolchains/esp8266/esp8266-gcc5.2.0-r5.exe).
+
+Read the [Notes](https://github.com/espressif/esp-gdbstub#notes) for more information.
diff --git a/samples/Basic_Debug/app/application.cpp b/samples/Basic_Debug/app/application.cpp
new file mode 100644
index 0000000..eeabb6e
--- /dev/null
+++ b/samples/Basic_Debug/app/application.cpp
@@ -0,0 +1,23 @@
+#include
+#include
+
+#define LED_PIN 2 // GPIO2
+
+Timer procTimer;
+bool state = true;
+
+/*
+* Notice: Software breakpoints work only on code that is in RAM.
+* In Sming you have to use the GDB_IRAM_ATTR to do this.
+*/
+void GDB_IRAM_ATTR blink()
+{
+ digitalWrite(LED_PIN, state);
+ state = !state;
+}
+
+void GDB_IRAM_ATTR init()
+{
+ pinMode(LED_PIN, OUTPUT);
+ procTimer.initializeMs(1000, blink).start();
+}
diff --git a/samples/Basic_Debug/include/user_config.h b/samples/Basic_Debug/include/user_config.h
new file mode 100644
index 0000000..f2a508f
--- /dev/null
+++ b/samples/Basic_Debug/include/user_config.h
@@ -0,0 +1,7 @@
+#ifndef __USER_CONFIG_H__
+#define __USER_CONFIG_H__
+
+// In this file you can define Sming Runtime parameters
+// For possible options see : ....
+
+#endif
diff --git a/sming/Makefile b/sming/Makefile
index a45a7c6..02bba46 100644
--- a/sming/Makefile
+++ b/sming/Makefile
@@ -62,7 +62,7 @@ LIBS = microc gcc hal phy pp net80211 wpa crypto main freertos lwip minic pwm
# compiler flags using during compilation of source files
#CFLAGS = -g -save-temps -Os -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -mno-serialize-volatile -D__ets__ -DICACHE_FLASH
-CFLAGS = -Os -g -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 $(USER_CFLAGS)
+CFLAGS = -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 $(USER_CFLAGS)
WIFI_SSID ?= ""
WIFI_PWD ?= ""
@@ -76,6 +76,15 @@ endif
CFLAGS += -DNDEBUG=1
CFLAGS += -DLWIP_DEBUG=0
# CXXFLAGS = $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
+ifeq ($(ENABLE_GDB), 1)
+ CFLAGS += -Og -ggdb -DGDBSTUB_FREERTOS=1 -DENABLE_GDB=1
+ MODULES += gdbstub
+ EXTRA_INCDIR += gdbstub
+else
+ CFLAGS += -Os -g
+endif
+
+
CXXFLAGS = $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11 -felide-constructors -Wno-literal-suffix
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static -Wl,-Map=$(BUILD_BASE)/firmware.map
@@ -97,6 +106,7 @@ SDK_INCDIR += include/lwip/ipv6
SDK_INCDIR += include/freertos
# select which tools to use as compiler, librarian and linker
+AS := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
CC := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
CXX := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-g++
AR := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-ar
@@ -111,10 +121,20 @@ USER_LIBDIR := compiler/lib
SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR))
SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR))
+
+AS_SRC=
+ifeq ($(ENABLE_GDB), 1)
+ AS_SRC += $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.S))
+endif
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c*))
C_OBJ := $(patsubst %.c,%.o,$(SRC))
CXX_OBJ := $(patsubst %.cpp,%.o,$(C_OBJ))
OBJ := $(patsubst %.o,$(BUILD_BASE)/%.o,$(CXX_OBJ))
+AS_OBJ=
+ifeq ($(ENABLE_GDB), 1)
+ AS_OBJ += $(patsubst %.S,%.o,$(AS_SRC))
+ OBJ += $(patsubst %.o,$(BUILD_BASE)/%.o,$(AS_OBJ))
+endif
LIBS := $(addprefix -l,$(LIBS))
APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET).a)
@@ -135,8 +155,16 @@ endif
vpath %.c $(SRC_DIR)
vpath %.cpp $(SRC_DIR)
+ifeq ($(ENABLE_GDB), 1)
+ vpath %.S $(SRC_DIR)
+endif
define compile-objects
+ifeq ($(ENABLE_GDB), 1)
+$1/%.o: %.S
+ $(vecho) "AS $$<"
+ $(Q) $(AS) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
+endif
$1/%.o: %.c
$(vecho) "CC $$<"
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
diff --git a/sming/Makefile-project.mk b/sming/Makefile-project.mk
index 78787f8..e0162a8 100644
--- a/sming/Makefile-project.mk
+++ b/sming/Makefile-project.mk
@@ -159,7 +159,13 @@ USER_LIBDIR = $(SMING_HOME)/compiler/lib/
LIBS = microc gcc hal phy pp net80211 wpa crypto main freertos lwip minic pwm sming
# compiler flags using during compilation of source files
-CFLAGS = -Os -g -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 $(USER_CFLAGS)
+CFLAGS = -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 $(USER_CFLAGS)
+ifeq ($(ENABLE_GDB), 1)
+ CFLAGS += -Og -ggdb -DGDBSTUB_FREERTOS=1 -DENABLE_GDB=1
+ EXTRA_INCDIR += $(SMING_HOME)/gdbstub
+else
+ CFLAGS += -Os -g
+endif
CXXFLAGS = $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11 -felide-constructors -Wno-literal-suffix
# we will use global WiFi settings from Eclipse Environment Variables, if possible
diff --git a/sming/Makefile-rboot.mk b/sming/Makefile-rboot.mk
index 760d9cb..6e591ff 100644
--- a/sming/Makefile-rboot.mk
+++ b/sming/Makefile-rboot.mk
@@ -153,7 +153,13 @@ EXTRA_INCDIR += $(SDK_BASE)/include/espressif
# compiler flags using during compilation of source files
-CFLAGS = -Os -g -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 $(USER_CFLAGS)
+CFLAGS = -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 $(USER_CFLAGS)
+ifeq ($(ENABLE_GDB), 1)
+ CFLAGS += -Og -ggdb -DGDBSTUB_FREERTOS=1 -DENABLE_GDB=1
+ EXTRA_INCDIR += $(SMING_HOME)/gdbstub
+else
+ CFLAGS += -Os -g
+endif
CXXFLAGS = $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11 -felide-constructors -Wno-literal-suffix
# libmain must be modified for rBoot big flash support (just one symbol gets weakened)
diff --git a/sming/gdbstub/.gitignore b/sming/gdbstub/.gitignore
new file mode 100644
index 0000000..b67c661
--- /dev/null
+++ b/sming/gdbstub/.gitignore
@@ -0,0 +1 @@
+.output/
diff --git a/sming/gdbstub/License b/sming/gdbstub/License
new file mode 100644
index 0000000..a0f05cb
--- /dev/null
+++ b/sming/gdbstub/License
@@ -0,0 +1,24 @@
+ESPRESSIF MIT License
+
+Copyright (c) 2015
+
+Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, it is free of charge, to any person obtaining a copy of this software and associated documentation files (the ��Software��), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED ��AS IS��, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+���� MIT ����֤
+
+��Ȩ (c) 2015 <������Ϣ�Ƽ����Ϻ�������˾>
+
+������֤��Ȩ������������Ϣ�Ƽ� ESP8266 ��Ʒ��Ӧ�ÿ������ڴ�����£�������֤�����Ȩ�κλ�ø�������������ĵ���ͳ��Ϊ�������������������Ƶؾ�Ӫ�����������������Ƶ�ʹ�á����ơ��ġ��ϲ������淢�С�ɢ��������Ȩ������������������������Ȩ��������Ȩ����������ЩȨ����ͬʱ������������������
+
+�����������������и����ж�����������ϵİ�Ȩ��������Ȩ������
+
+�������������������ṩ��û���κ���ȷ���ĵ������������������ڹ��������ԡ��ʺ�ijһ�ض���;�ͷ���Ȩ�ı�֤�����ߺͰ�Ȩ���������κ�����¾�����������������ʹ��������Ժ�ͬ��ʽ��������Ȩ��������ʽ������κ����⡢���������θ���
+
+
+
+
diff --git a/sming/gdbstub/Makefile b/sming/gdbstub/Makefile
new file mode 100644
index 0000000..4e6e8b4
--- /dev/null
+++ b/sming/gdbstub/Makefile
@@ -0,0 +1,45 @@
+
+#############################################################
+# Required variables for each makefile
+# Discard this section from all parent makefiles
+# Expected variables (with automatic defaults):
+# CSRCS (all "C" files in the dir)
+# SUBDIRS (all subdirs with a Makefile)
+# GEN_LIBS - list of libs to be generated ()
+# GEN_IMAGES - list of images to be generated ()
+# COMPONENTS_xxx - a list of libs/objs in the form
+# subdir/lib to be extracted and rolled up into
+# a generated lib/image xxx.a ()
+#
+ifndef PDIR
+GEN_LIBS = libgdbstub.a
+endif
+
+
+#############################################################
+# Configuration i.e. compile options etc.
+# Target specific stuff (defines etc.) goes in here!
+# Generally values applying to a tree are captured in the
+# makefile at its root level - these are then overridden
+# for a subtree within the makefile rooted therein
+#
+#DEFINES +=
+
+#############################################################
+# Recursion Magic - Don't touch this!!
+#
+# Each subtree potentially has an include directory
+# corresponding to the common APIs applicable to modules
+# rooted at that subtree. Accordingly, the INCLUDE PATH
+# of a module can only contain the include directories up
+# its parent path, and not its siblings
+#
+# Required for each makefile to inherit from the parent
+#
+
+INCLUDES += -I $(PDIR)include
+INCLUDES += -I ./
+INCLUDES += -I ../../include/ets
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+
diff --git a/sming/gdbstub/README.md b/sming/gdbstub/README.md
new file mode 100644
index 0000000..0883a2c
--- /dev/null
+++ b/sming/gdbstub/README.md
@@ -0,0 +1,69 @@
+
+GDBSTUB
+=======
+
+Intro
+-----
+
+While the ESP8266 supports the standard Gnu set of C programming utilities, for now the choice of debuggers
+has been limited: there is an attempt at [OpenOCD support](https://github.com/projectgus/openocd), but at
+the time of writing, it doesn't support hardware watchpoints and breakpoints yet, and it needs a separate
+JTAG adapter connecting to the ESP8266s JTAG pins. As an alternative, [Cesanta](https://www.cesanta.com/)
+has implemented a barebones[GDB stub](https://blog.cesanta.com/esp8266-gdb) in their Smart.js solution -
+unfortunately, this only supports exception catching and needs some work before you can use it outside of
+the Smart.js platform. Moreover, it also does not work with FreeRTOS.
+
+For internal use, we at Espressif desired a GDB stub that works with FreeRTOS and is a bit more capable,
+so we designed our own implementation of it. This stub works both under FreeRTOS as well as the OS-less
+SDK and is able to catch exceptions and do backtraces on them, read and write memory, forward [os_]printf
+statements to gdb, single-step instructions and set hardware break- and watchpoints. It connects to the
+host machine (which runs gdb) using the standard serial connection that's also used for programming.
+
+In order to be useful the gdbstub has to be used in conjunction with an xtensa-lx106-elf-gdb, for example
+as generated by the [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk) project.
+
+Usage
+-----
+ * Grab the gdbstub project and put the files in a directory called 'gdbstub' in your project. You can do this
+either by checking out the Git repo, or adding the Git repo as a submodule to your project if it's already
+in Git.
+ * Modify your Makefile. You'll need to include the gdbstub sources: if your Makefile is structured like the
+ones in the Espressif examples, you can add `gdbstub` to the `SUBDIRS` define and `gdbstub/libgdbstub.a` to the
+`COMPONENTS_eagle.app.v6` define. Also, you probably want to add `-ggdb` to your compiler flags (`TARGET_LDFLAGS`)
+and, if you are debugging, change any optimation flags (-Os, -O2 etc) into `-Og`. Finally, make sure your Makefile
+also compiles .S files.
+ * Configure gdbstub by editting `gdbstub-cfg.h`. There are a bunch of options you can tweak: FreeRTOS or bare SDK,
+private exception/breakpoint stack, console redirection to GDB, wait till debugger attachment etc. You can also
+configure the options by including the proper -Dwhatever gcc flags in your Makefiles.
+ * In your user_main.c, add an `#include <../gdbstub/gdbstub.h>` and call `gdbstub_init();` somewhere in user_main.
+ * Compile and flash your board.
+ * Run gdb, depending on your configuration immediately after resetting the board or after it has run into
+an exception. The easiest way to do it is to use the provided script: xtensa-lx106-elf-gdb -x gdbcmds -b 38400
+Change the '38400' into the baud rate your code uses. You may need to change the gdbcmds script to fit the
+configuration of your hardware and build environment.
+
+Notes
+-----
+ * Using software breakpoints ('br') only works on code that's in RAM. Code in flash can only have a hardware
+breakpoint ('hbr').
+ * Due to hardware limitations, only one hardware breakpount and one hardware watchpoint are available.
+ * Pressing control-C to interrupt the running program depends on gdbstub hooking the UART interrupt.
+If some code re-hooks this afterwards, gdbstub won't be able to receive characters. If gdbstub handles
+the interrupt, the user code will not receive any characters.
+ * Continuing from an exception is not (yet) supported in FreeRTOS mode.
+ * The WiFi hardware is designed to be serviced by software periodically. It has some buffers so it
+will behave OK when some data comes in while the processor is busy, but these buffers are not infinite.
+If the WiFi hardware receives lots of data while the debugger has stopped the CPU, it is bound
+to crash. This will happen mostly when working with UDP and/or ICMP; TCP-connections in general will
+not send much more data when the other side doesn't send any ACKs.
+
+License
+-------
+This gdbstub is licensed under the Espressif MIT license, as described in the License file.
+
+
+Thanks
+------
+ * Cesanta, for their initial ESP8266 exception handling only gdbstub,
+ * jcmvbkbc, for providing an incompatible but interesting gdbstub for other Xtensa CPUs,
+ * Sysprogs (makers of VisualGDB), for their suggestions and bugreports.
diff --git a/sming/gdbstub/gdbcmds b/sming/gdbstub/gdbcmds
new file mode 100644
index 0000000..dfec48a
--- /dev/null
+++ b/sming/gdbstub/gdbcmds
@@ -0,0 +1,8 @@
+file ../.output/eagle/debug/image/eagle.app.v6.out
+#set remotedebug 1
+set remotelogfile gdb_rsp_logfile.txt
+#set serial baud 115200
+set remote hardware-breakpoint-limit 1
+set remote hardware-watchpoint-limit 1
+#set debug xtensa 4
+target remote /dev/ttyUSB0
diff --git a/sming/gdbstub/gdbstub-cfg.h b/sming/gdbstub/gdbstub-cfg.h
new file mode 100644
index 0000000..06d1c35
--- /dev/null
+++ b/sming/gdbstub/gdbstub-cfg.h
@@ -0,0 +1,62 @@
+#ifndef GDBSTUB_CFG_H
+#define GDBSTUB_CFG_H
+
+/*
+Enable this define if you're using the RTOS SDK. It will use a custom exception handler instead of the HAL
+and do some other magic to make everything work and compile under FreeRTOS.
+*/
+#ifndef GDBSTUB_FREERTOS
+#define GDBSTUB_FREERTOS 1
+#endif
+
+/*
+Enable this to make the exception and debugging handlers switch to a private stack. This will use
+up 1K of RAM, but may be useful if you're debugging stack or stack pointer corruption problems. It's
+normally disabled because not many situations need it. If for some reason the GDB communication
+stops when you run into an error in your code, try enabling this.
+*/
+#ifndef GDBSTUB_USE_OWN_STACK
+#define GDBSTUB_USE_OWN_STACK 0
+#endif
+
+/*
+If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. it does this by
+hooking the UART interrupt. Unfortunately, this means receiving stuff over the serial port won't
+work for your program anymore. This will fail if your program sets an UART interrupt handler after
+the gdbstub_init call.
+*/
+#ifndef GDBSTUB_CTRLC_BREAK
+#define GDBSTUB_CTRLC_BREAK 1
+#endif
+
+/*
+Enabling this will redirect console output to GDB. This basically means that printf/os_printf output
+will show up in your gdb session, which is useful if you use gdb to do stuff. It also means that if
+you use a normal terminal, you can't read the printfs anymore.
+*/
+#ifndef GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 1
+#endif
+
+/*
+Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by
+breaking in the init routine; use the gdb 'c' command (continue) to start the program.
+*/
+#ifndef GDBSTUB_BREAK_ON_INIT
+#define GDBSTUB_BREAK_ON_INIT 1
+#endif
+
+/*
+Function attributes for function types.
+Gdbstub functions are placed in flash or IRAM using attributes, as defined here. The gdbinit function
+(and related) can always be in flash, because it's called in the normal code flow. The rest of the
+gdbstub functions can be in flash too, but only if there's no chance of them being called when the
+flash somehow is disabled (eg during SPI operations or flash write/erase operations). If the routines
+are called when the flash is disabled (eg due to a Ctrl-C at the wrong time), the ESP8266 will most
+likely crash.
+*/
+#define ATTR_GDBINIT ICACHE_FLASH_ATTR
+#define ATTR_GDBFN
+
+#endif
+
diff --git a/sming/gdbstub/gdbstub-entry.S b/sming/gdbstub/gdbstub-entry.S
new file mode 100644
index 0000000..b6a969a
--- /dev/null
+++ b/sming/gdbstub/gdbstub-entry.S
@@ -0,0 +1,406 @@
+/******************************************************************************
+ * Copyright 2015 Espressif Systems
+ *
+ * Description: Assembly routines for the gdbstub
+ *
+ * License: ESPRESSIF MIT License
+ *******************************************************************************/
+
+
+#include "gdbstub-cfg.h"
+
+#include
+#include
+#include
+
+#define DEBUG_PC (EPC + XCHAL_DEBUGLEVEL)
+#define DEBUG_EXCSAVE (EXCSAVE + XCHAL_DEBUGLEVEL)
+#define DEBUG_PS (EPS + XCHAL_DEBUGLEVEL)
+
+
+.global gdbstub_savedRegs
+
+#if GDBSTUB_USE_OWN_STACK
+.global gdbstub_exceptionStack
+#endif
+
+ .text
+.literal_position
+
+ .text
+ .align 4
+
+/*
+The savedRegs struct:
+ uint32_t pc;
+ uint32_t ps;
+ uint32_t sar;
+ uint32_t vpri;
+ uint32_t a0;
+ uint32_t a[14]; //a2..a15
+ uint32_t litbase;
+ uint32_t sr176;
+ uint32_t sr208;
+ uint32_t a1;
+ uint32_t reason;
+*/
+
+/*
+This is the debugging exception routine; it's called by the debugging vector
+
+We arrive here with all regs intact except for a2. The old contents of A2 are saved
+into the DEBUG_EXCSAVE special function register. EPC is the original PC.
+*/
+gdbstub_debug_exception_entry:
+/*
+ //Minimum no-op debug exception handler, for debug
+ rsr a2,DEBUG_PC
+ addi a2,a2,3
+ wsr a2,DEBUG_PC
+ xsr a2, DEBUG_EXCSAVE
+ rfi XCHAL_DEBUGLEVEL
+*/
+
+//Save all regs to structure
+ movi a2, gdbstub_savedRegs
+ s32i a0, a2, 0x10
+ s32i a1, a2, 0x58
+ rsr a0, DEBUG_PS
+ s32i a0, a2, 0x04
+ rsr a0, DEBUG_EXCSAVE //was R2
+ s32i a0, a2, 0x14
+ s32i a3, a2, 0x18
+ s32i a4, a2, 0x1c
+ s32i a5, a2, 0x20
+ s32i a6, a2, 0x24
+ s32i a7, a2, 0x28
+ s32i a8, a2, 0x2c
+ s32i a9, a2, 0x30
+ s32i a10, a2, 0x34
+ s32i a11, a2, 0x38
+ s32i a12, a2, 0x3c
+ s32i a13, a2, 0x40
+ s32i a14, a2, 0x44
+ s32i a15, a2, 0x48
+ rsr a0, SAR
+ s32i a0, a2, 0x08
+ rsr a0, LITBASE
+ s32i a0, a2, 0x4C
+ rsr a0, 176
+ s32i a0, a2, 0x50
+ rsr a0, 208
+ s32i a0, a2, 0x54
+ rsr a0, DEBUGCAUSE
+ s32i a0, a2, 0x5C
+ rsr a4, DEBUG_PC
+ s32i a4, a2, 0x00
+
+#if GDBSTUB_USE_OWN_STACK
+ //Move to our own stack
+ movi a1, exceptionStack+255*4
+#endif
+
+//If ICOUNT is -1, disable it by setting it to 0, otherwise we will keep triggering on the same instruction.
+ rsr a2, ICOUNT
+ movi a3, -1
+ bne a2, a3, noIcountReset
+ movi a3, 0
+ wsr a3, ICOUNT
+noIcountReset:
+
+ rsr a2, ps
+ addi a2, a2, -PS_EXCM_MASK
+ wsr a2, ps
+ rsync
+
+//Call into the C code to do the actual handling.
+ call0 gdbstub_handle_debug_exception
+
+DebugExceptionExit:
+
+ rsr a2, ps
+ addi a2, a2, PS_EXCM_MASK
+ wsr a2, ps
+ rsync
+
+ //Restore registers from the gdbstub_savedRegs struct
+ movi a2, gdbstub_savedRegs
+ l32i a0, a2, 0x00
+ wsr a0, DEBUG_PC
+// l32i a0, a2, 0x54
+// wsr a0, 208
+ l32i a0, a2, 0x50
+ //wsr a0, 176 //Some versions of gcc do not understand this...
+ .byte 0x00, 176, 0x13 //so we hand-assemble the instruction.
+ l32i a0, a2, 0x4C
+ wsr a0, LITBASE
+ l32i a0, a2, 0x08
+ wsr a0, SAR
+ l32i a15, a2, 0x48
+ l32i a14, a2, 0x44
+ l32i a13, a2, 0x40
+ l32i a12, a2, 0x3c
+ l32i a11, a2, 0x38
+ l32i a10, a2, 0x34
+ l32i a9, a2, 0x30
+ l32i a8, a2, 0x2c
+ l32i a7, a2, 0x28
+ l32i a6, a2, 0x24
+ l32i a5, a2, 0x20
+ l32i a4, a2, 0x1c
+ l32i a3, a2, 0x18
+ l32i a0, a2, 0x14
+ wsr a0, DEBUG_EXCSAVE //was R2
+ l32i a0, a2, 0x04
+ wsr a0, DEBUG_PS
+ l32i a1, a2, 0x58
+ l32i a0, a2, 0x10
+
+ //Read back vector-saved a2 value, put back address of this routine.
+ movi a2, gdbstub_debug_exception_entry
+ xsr a2, DEBUG_EXCSAVE
+
+ //All done. Return to where we came from.
+ rfi XCHAL_DEBUGLEVEL
+
+
+
+#if GDBSTUB_FREERTOS
+/*
+FreeRTOS exception handling code. For some reason or another, we can't just hook the main exception vector: it
+seems FreeRTOS uses that for something else too (interrupts). FreeRTOS has its own fatal exception handler, and we
+hook that. Unfortunately, that one is called from a few different places (eg directly in the DoubleExceptionVector)
+so the precise location of the original register values are somewhat of a mystery when we arrive here...
+
+As a 'solution', we'll just decode the most common case of the user_fatal_exception_handler being called from
+the user exception handler vector:
+- excsave1 - orig a0
+- a1: stack frame:
+ sf+16: orig a1
+ sf+8: ps
+ sf+4: epc
+ sf+12: orig a0
+ sf: magic no?
+*/
+ .global gdbstub_handle_user_exception
+ .global gdbstub_user_exception_entry
+ .align 4
+gdbstub_user_exception_entry:
+//Save all regs to structure
+ movi a0, gdbstub_savedRegs
+ s32i a1, a0, 0x14 //was a2
+ s32i a3, a0, 0x18
+ s32i a4, a0, 0x1c
+ s32i a5, a0, 0x20
+ s32i a6, a0, 0x24
+ s32i a7, a0, 0x28
+ s32i a8, a0, 0x2c
+ s32i a9, a0, 0x30
+ s32i a10, a0, 0x34
+ s32i a11, a0, 0x38
+ s32i a12, a0, 0x3c
+ s32i a13, a0, 0x40
+ s32i a14, a0, 0x44
+ s32i a15, a0, 0x48
+ rsr a2, SAR
+ s32i a2, a0, 0x08
+ rsr a2, LITBASE
+ s32i a2, a0, 0x4C
+ rsr a2, 176
+ s32i a2, a0, 0x50
+ rsr a2, 208
+ s32i a2, a0, 0x54
+ rsr a2, EXCCAUSE
+ s32i a2, a0, 0x5C
+
+//Get the rest of the regs from the stack struct
+ l32i a3, a1, 12
+ s32i a3, a0, 0x10
+ l32i a3, a1, 16
+ s32i a3, a0, 0x58
+ l32i a3, a1, 8
+ s32i a3, a0, 0x04
+ l32i a3, a1, 4
+ s32i a3, a0, 0x00
+
+#if GDBSTUB_USE_OWN_STACK
+ movi a1, exceptionStack+255*4
+#endif
+
+ rsr a2, ps
+ addi a2, a2, -PS_EXCM_MASK
+ wsr a2, ps
+ rsync
+
+ call0 gdbstub_handle_user_exception
+
+UserExceptionExit:
+
+/*
+Okay, from here on, it Does Not Work. There's not really any continuing from an exception in the
+FreeRTOS case; there isn't any effort put in reversing the mess the exception code made yet. Maybe this
+is still something we need to implement later, if there's any demand for it, or maybe we should modify
+FreeRTOS to allow this in the future. (Which will then kill backwards compatibility... hmmm.)
+*/
+ j UserExceptionExit
+
+
+ .global gdbstub_handle_uart_int
+ .global gdbstub_uart_entry
+ .align 4
+gdbstub_uart_entry:
+ //On entry, the stack frame is at SP+16.
+ //This is a small stub to present that as the first arg to the gdbstub_handle_uart function.
+ movi a2, 16
+ add a2, a2, a1
+ movi a3, gdbstub_handle_uart_int
+ jx a3
+
+#endif
+
+
+
+ .global gdbstub_save_extra_sfrs_for_exception
+ .align 4
+//The Xtensa OS HAL does not save all the special function register things. This bit of assembly
+//fills the gdbstub_savedRegs struct with them.
+gdbstub_save_extra_sfrs_for_exception:
+ movi a2, gdbstub_savedRegs
+ rsr a3, LITBASE
+ s32i a3, a2, 0x4C
+ rsr a3, 176
+ s32i a3, a2, 0x50
+ rsr a3, 208
+ s32i a3, a2, 0x54
+ rsr a3, EXCCAUSE
+ s32i a3, a2, 0x5C
+ ret
+
+ .global gdbstub_init_debug_entry
+ .global _DebugExceptionVector
+ .align 4
+gdbstub_init_debug_entry:
+//This puts the following 2 instructions into the debug exception vector:
+// xsr a2, DEBUG_EXCSAVE
+// jx a2
+ movi a2, _DebugExceptionVector
+ movi a3, 0xa061d220
+ s32i a3, a2, 0
+ movi a3, 0x00000002
+ s32i a3, a2, 4
+
+//Tell the just-installed debug vector where to go.
+ movi a2, gdbstub_debug_exception_entry
+ wsr a2, DEBUG_EXCSAVE
+
+ ret
+
+
+//Set up ICOUNT register to step one single instruction
+ .global gdbstub_icount_ena_single_step
+ .align 4
+gdbstub_icount_ena_single_step:
+ movi a3, XCHAL_DEBUGLEVEL //Only count steps in non-debug mode
+ movi a2, -2
+ wsr a3, ICOUNTLEVEL
+ wsr a2, ICOUNT
+ isync
+ ret
+
+
+//These routines all assume only one breakpoint and watchpoint is available, which
+//is the case for the ESP8266 Xtensa core.
+
+
+ .global gdbstub_set_hw_breakpoint
+gdbstub_set_hw_breakpoint:
+ //a2 - addr, a3 - len (unused here)
+ rsr a4, IBREAKENABLE
+ bbsi a4, 0, return_w_error
+ wsr a2, IBREAKA
+ movi a2, 1
+ wsr a2, IBREAKENABLE
+ isync
+ movi a2, 1
+ ret
+
+ .global gdbstub_del_hw_breakpoint
+gdbstub_del_hw_breakpoint:
+ //a2 - addr
+ rsr a5, IBREAKENABLE
+ bbci a5, 0, return_w_error
+ rsr a3, IBREAKA
+ bne a3, a2, return_w_error
+ movi a2,0
+ wsr a2, IBREAKENABLE
+ isync
+ movi a2, 1
+ ret
+
+ .global gdbstub_set_hw_watchpoint
+ //a2 - addr, a3 - mask, a4 - type (1=read, 2=write, 3=access)
+gdbstub_set_hw_watchpoint:
+ //Check if any of the masked address bits are set. If so, that is an error.
+ movi a5,0x0000003F
+ xor a5, a5, a3
+ bany a2, a5, return_w_error
+ //Check if watchpoint already is set
+ rsr a5, DBREAKC
+ movi a6, 0xC0000000
+ bany a6, a5, return_w_error
+ //Set watchpoint
+ wsr a2, DBREAKA
+
+ //Combine type and mask
+ movi a6, 0x3F
+ and a3, a3, a6
+ slli a4, a4, 30
+ or a3, a3, a4
+ wsr a3, DBREAKC
+
+// movi a2, 1
+ mov a2, a3
+ isync
+ ret
+
+
+ .global gdbstub_del_hw_watchpoint
+ //a2 - addr
+gdbstub_del_hw_watchpoint:
+ //See if the address matches
+ rsr a3, DBREAKA
+ bne a3, a2, return_w_error
+ //See if the bp actually is set
+ rsr a3, DBREAKC
+ movi a2, 0xC0000000
+ bnone a3, a2, return_w_error
+ //Disable bp
+ movi a2,0
+ wsr a2,DBREAKC
+ movi a2,1
+ isync
+ ret
+
+return_w_error:
+ movi a2, 0
+ ret
+
+
+//Breakpoint, with an attempt at a functional function prologue and epilogue...
+ .global gdbstub_do_break_breakpoint_addr
+ .global gdbstub_do_break
+ .align 4
+gdbstub_do_break:
+ addi a1, a1, -16
+ s32i a15, a1, 12
+ mov a15, a1
+
+gdbstub_do_break_breakpoint_addr:
+ break 0,0
+
+ mov a1, a15
+ l32i a15, a1, 12
+ addi a1, a1, 16
+ ret
+
+
diff --git a/sming/gdbstub/gdbstub-entry.h b/sming/gdbstub/gdbstub-entry.h
new file mode 100644
index 0000000..3e5461e
--- /dev/null
+++ b/sming/gdbstub/gdbstub-entry.h
@@ -0,0 +1,25 @@
+#ifndef GDBSTUB_ENTRY_H
+#define GDBSTUB_ENTRY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gdbstub_init_debug_entry();
+void gdbstub_do_break();
+void gdbstub_icount_ena_single_step();
+void gdbstub_save_extra_sfrs_for_exception();
+void gdbstub_uart_entry();
+
+int gdbstub_set_hw_breakpoint(int addr, int len);
+int gdbstub_set_hw_watchpoint(int addr, int len, int type);
+int gdbstub_del_hw_breakpoint(int addr);
+int gdbstub_del_hw_watchpoint(int addr);
+
+extern void* gdbstub_do_break_breakpoint_addr;
+
+#ifdef __cplusplus
+{
+#endif
+
+#endif
\ No newline at end of file
diff --git a/sming/gdbstub/gdbstub.c b/sming/gdbstub/gdbstub.c
new file mode 100644
index 0000000..73b2605
--- /dev/null
+++ b/sming/gdbstub/gdbstub.c
@@ -0,0 +1,787 @@
+/******************************************************************************
+ * Copyright 2015 Espressif Systems
+ *
+ * Description: A stub to make the ESP8266 debuggable by GDB over the serial
+ * port.
+ *
+ * License: ESPRESSIF MIT License
+ *******************************************************************************/
+
+#include "gdbstub.h"
+#include "c_types.h"
+#include "espressif/esp8266/ets_sys.h"
+#include "espressif/esp8266/eagle_soc.h"
+#include "gpio.h"
+#include "xtensa/corebits.h"
+
+#include "gdbstub.h"
+#include "gdbstub-entry.h"
+#include "gdbstub-cfg.h"
+
+
+//From xtruntime-frames.h
+struct XTensa_exception_frame_s {
+ uint32_t pc;
+ uint32_t ps;
+ uint32_t sar;
+ uint32_t vpri;
+ uint32_t a0;
+ uint32_t a[14]; //a2..a15
+//These are added manually by the exception code; the HAL doesn't set these on an exception.
+ uint32_t litbase;
+ uint32_t sr176;
+ uint32_t sr208;
+ uint32_t a1;
+ //'reason' is abused for both the debug and the exception vector: if bit 7 is set,
+ //this contains an exception reason, otherwise it contains a debug vector bitmap.
+ uint32_t reason;
+};
+
+
+struct XTensa_rtos_int_frame_s {
+ uint32_t exitPtr;
+ uint32_t pc;
+ uint32_t ps;
+ uint32_t a[16];
+ uint32_t sar;
+};
+
+#if GDBSTUB_FREERTOS
+/*
+Definitions for FreeRTOS. This redefines some os_* functions to use their non-os* counterparts. It
+also sets up some function pointers for ROM functions that aren't in the FreeRTOS ld files.
+*/
+#include
+#include
+void _xt_isr_attach(int inum, void *fn);
+void _xt_isr_unmask(int inum);
+void os_install_putc1(void (*p)(char c));
+#define os_printf(...) printf(__VA_ARGS__)
+#define os_memcpy(a,b,c) memcpy(a,b,c)
+typedef void wdtfntype();
+static wdtfntype *ets_wdt_disable=(wdtfntype *)0x400030f0;
+static wdtfntype *ets_wdt_enable=(wdtfntype *)0x40002fa0;
+
+#else
+/*
+OS-less SDK defines. Defines some headers for things that aren't in the include files, plus
+the xthal stack frame struct.
+*/
+#include "osapi.h"
+#include "user_interface.h"
+
+void _xtos_set_exception_handler(int cause, void (exhandler)(struct XTensa_exception_frame_s *frame));
+int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+#endif
+
+#define EXCEPTION_GDB_SP_OFFSET 0x100
+
+
+//We need some UART register defines.
+#define ETS_UART_INUM 5
+#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00)
+#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C)
+#define UART_RXFIFO_CNT 0x000000FF
+#define UART_RXFIFO_CNT_S 0
+#define UART_TXFIFO_CNT 0x000000FF
+#define UART_TXFIFO_CNT_S 16
+#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0)
+#define UART_INT_ENA(i) (REG_UART_BASE(i) + 0xC)
+#define UART_INT_CLR(i) (REG_UART_BASE(i) + 0x10)
+#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
+#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
+#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
+#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
+
+
+
+
+//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
+//implies a minimum size of about 190 bytes.
+#define PBUFLEN 256
+//Length of gdb stdout buffer, for console redirection
+#define OBUFLEN 32
+
+//The asm stub saves the Xtensa registers here when a debugging exception happens.
+struct XTensa_exception_frame_s gdbstub_savedRegs;
+#if GDBSTUB_USE_OWN_STACK
+//This is the debugging exception stack.
+int exceptionStack[256];
+#endif
+
+static unsigned char cmd[PBUFLEN]; //GDB command input buffer
+static char chsum; //Running checksum of the output packet
+#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+static unsigned char obuf[OBUFLEN]; //GDB stdout buffer
+static int obufpos=0; //Current position in the buffer
+#endif
+static int32_t singleStepPs=-1; //Stores ps when single-stepping instruction. -1 when not in use.
+
+//Small function to feed the hardware watchdog. Needed to stop the ESP from resetting
+//due to a watchdog timeout while reading a command.
+static void ATTR_GDBFN keepWDTalive() {
+ uint64_t *wdtval=(uint64_t*)0x3ff21048;
+ uint64_t *wdtovf=(uint64_t*)0x3ff210cc;
+ int *wdtctl=(int*)0x3ff210c8;
+ *wdtovf=*wdtval+1600000;
+ *wdtctl|=(1<<31);
+}
+
+//Receive a char from the uart. Uses polling and feeds the watchdog.
+static int ATTR_GDBFN gdbRecvChar() {
+ int i;
+ while (((READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0) {
+ keepWDTalive();
+ }
+ i=READ_PERI_REG(UART_FIFO(0));
+ return i;
+}
+
+//Send a char to the uart.
+static void ATTR_GDBFN gdbSendChar(char c) {
+ while (((READ_PERI_REG(UART_STATUS(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
+ WRITE_PERI_REG(UART_FIFO(0), c);
+}
+
+//Send the start of a packet; reset checksum calculation.
+static void ATTR_GDBFN gdbPacketStart() {
+ chsum=0;
+ gdbSendChar('$');
+}
+
+//Send a char as part of a packet
+static void ATTR_GDBFN gdbPacketChar(char c) {
+ if (c=='#' || c=='$' || c=='}' || c=='*') {
+ gdbSendChar('}');
+ gdbSendChar(c^0x20);
+ chsum+=(c^0x20)+'}';
+ } else {
+ gdbSendChar(c);
+ chsum+=c;
+ }
+}
+
+//Send a string as part of a packet
+static void ATTR_GDBFN gdbPacketStr(char *c) {
+ while (*c!=0) {
+ gdbPacketChar(*c);
+ c++;
+ }
+}
+
+//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
+static void ATTR_GDBFN gdbPacketHex(int val, int bits) {
+ char hexChars[]="0123456789abcdef";
+ int i;
+ for (i=bits; i>0; i-=4) {
+ gdbPacketChar(hexChars[(val>>(i-4))&0xf]);
+ }
+}
+
+//Finish sending a packet.
+static void ATTR_GDBFN gdbPacketEnd() {
+ gdbSendChar('#');
+ gdbPacketHex(chsum, 8);
+}
+
+//Error states used by the routines that grab stuff from the incoming gdb packet
+#define ST_ENDPACKET -1
+#define ST_ERR -2
+#define ST_OK -3
+#define ST_CONT -4
+
+//Grab a hex value from the gdb packet. Ptr will get positioned on the end
+//of the hex string, as far as the routine has read into it. Bits/4 indicates
+//the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much
+//hex chars as possible.
+static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) {
+ int i;
+ int no;
+ unsigned int v=0;
+ char c;
+ no=bits/4;
+ if (bits==-1) no=64;
+ for (i=0; i='0' && c<='9') {
+ v<<=4;
+ v|=(c-'0');
+ } else if (c>='A' && c<='F') {
+ v<<=4;
+ v|=(c-'A')+10;
+ } else if (c>='a' && c<='f') {
+ v<<=4;
+ v|=(c-'a')+10;
+ } else if (c=='#') {
+ if (bits==-1) {
+ (*ptr)--;
+ return v;
+ }
+ return ST_ENDPACKET;
+ } else {
+ if (bits==-1) {
+ (*ptr)--;
+ return v;
+ }
+ return ST_ERR;
+ }
+ }
+ return v;
+}
+
+//Swap an int into the form gdb wants it
+static int ATTR_GDBFN iswap(int i) {
+ int r;
+ r=((i>>24)&0xff);
+ r|=((i>>16)&0xff)<<8;
+ r|=((i>>8)&0xff)<<16;
+ r|=((i>>0)&0xff)<<24;
+ return r;
+}
+
+//Read a byte from the ESP8266 memory.
+static unsigned char ATTR_GDBFN readbyte(unsigned int p) {
+ int *i=(int*)(p&(~3));
+ if (p<0x20000000 || p>=0x60000000) return -1;
+ return *i>>((p&3)*8);
+}
+
+//Write a byte to the ESP8266 memory.
+static void ATTR_GDBFN writeByte(unsigned int p, unsigned char d) {
+ int *i=(int*)(p&(~3));
+ if (p<0x20000000 || p>=0x60000000) return;
+ if ((p&3)==0) *i=(*i&0xffffff00)|(d<<0);
+ if ((p&3)==1) *i=(*i&0xffff00ff)|(d<<8);
+ if ((p&3)==2) *i=(*i&0xff00ffff)|(d<<16);
+ if ((p&3)==3) *i=(*i&0x00ffffff)|(d<<24);
+}
+
+//Returns 1 if it makes sense to write to addr p
+static int ATTR_GDBFN validWrAddr(int p) {
+ if (p>=0x3ff00000 && p<0x40000000) return 1;
+ if (p>=0x40100000 && p<0x40140000) return 1;
+ if (p>=0x60000000 && p<0x60002000) return 1;
+ return 0;
+}
+
+/*
+Register file in the format lx106 gdb port expects it.
+Inspired by gdb/regformats/reg-xtensa.dat from
+https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar
+As decoded by Cesanta.
+*/
+struct regfile {
+ uint32_t a[16];
+ uint32_t pc;
+ uint32_t sar;
+ uint32_t litbase;
+ uint32_t sr176;
+ uint32_t sr208;
+ uint32_t ps;
+};
+
+
+//Send the reason execution is stopped to GDB.
+static void ATTR_GDBFN sendReason() {
+#if 0
+ char *reason=""; //default
+#endif
+ //exception-to-signal mapping
+ char exceptionSignal[]={4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7};
+ int i=0;
+ gdbPacketStart();
+ gdbPacketChar('T');
+ if (gdbstub_savedRegs.reason==0xff) {
+ gdbPacketHex(2, 8); //sigint
+ } else if (gdbstub_savedRegs.reason&0x80) {
+ //We stopped because of an exception. Convert exception code to a signal number and send it.
+ i=gdbstub_savedRegs.reason&0x7f;
+ if (i=PBUFLEN) return ST_ERR;
+ }
+ //A # has been received. Get and check the received chsum.
+ sentchs[0]=gdbRecvChar();
+ sentchs[1]=gdbRecvChar();
+ ptr=&sentchs[0];
+ rchsum=gdbGetHexVal(&ptr, 8);
+// os_printf("c %x r %x\n", chsum, rchsum);
+ if (rchsum!=chsum) {
+ gdbSendChar('-');
+ return ST_ERR;
+ } else {
+ gdbSendChar('+');
+ return gdbHandleCommand(cmd, p);
+ }
+}
+
+//Get the value of one of the A registers
+static unsigned int ATTR_GDBFN getaregval(int reg) {
+ if (reg==0) return gdbstub_savedRegs.a0;
+ if (reg==1) return gdbstub_savedRegs.a1;
+ return gdbstub_savedRegs.a[reg-2];
+}
+
+//Set the value of one of the A registers
+static void ATTR_GDBFN setaregval(int reg, unsigned int val) {
+ os_printf("%x -> %x\n", val, reg);
+ if (reg==0) gdbstub_savedRegs.a0=val;
+ if (reg==1) gdbstub_savedRegs.a1=val;
+ gdbstub_savedRegs.a[reg-2]=val;
+}
+
+//Emulate the l32i/s32i instruction we're stopped at.
+static void ATTR_GDBFN emulLdSt() {
+ unsigned char i0=readbyte(gdbstub_savedRegs.pc);
+ unsigned char i1=readbyte(gdbstub_savedRegs.pc+1);
+ unsigned char i2=readbyte(gdbstub_savedRegs.pc+2);
+ int *p;
+ if ((i0&0xf)==2 && (i1&0xf0)==0x20) {
+ //l32i
+ p=(int*)getaregval(i1&0xf)+(i2*4);
+ setaregval(i0>>4, *p);
+ gdbstub_savedRegs.pc+=3;
+ } else if ((i0&0xf)==0x8) {
+ //l32i.n
+ p=(int*)getaregval(i1&0xf)+((i1>>4)*4);
+ setaregval(i0>>4, *p);
+ gdbstub_savedRegs.pc+=2;
+ } else if ((i0&0xf)==2 && (i1&0xf0)==0x60) {
+ //s32i
+ p=(int*)getaregval(i1&0xf)+(i2*4);
+ *p=getaregval(i0>>4);
+ gdbstub_savedRegs.pc+=3;
+ } else if ((i0&0xf)==0x9) {
+ //s32i.n
+ p=(int*)getaregval(i1&0xf)+((i1>>4)*4);
+ *p=getaregval(i0>>4);
+ gdbstub_savedRegs.pc+=2;
+ } else {
+ os_printf("GDBSTUB: No l32i/s32i instruction: %x %x %x. Huh?", i2, i1, i0);
+ }
+}
+
+//We just caught a debug exception and need to handle it. This is called from an assembly
+//routine in gdbstub-entry.S
+void ATTR_GDBFN gdbstub_handle_debug_exception() {
+ ets_wdt_disable();
+
+ if (singleStepPs!=-1) {
+ //We come here after single-stepping an instruction. Interrupts are disabled
+ //for the single step. Re-enable them here.
+ gdbstub_savedRegs.ps=(gdbstub_savedRegs.ps&~0xf)|(singleStepPs&0xf);
+ singleStepPs=-1;
+ }
+
+ sendReason();
+ while(gdbReadCommand()!=ST_CONT);
+ if ((gdbstub_savedRegs.reason&0x84)==0x4) {
+ //We stopped due to a watchpoint. We can't re-execute the current instruction
+ //because it will happily re-trigger the same watchpoint, so we emulate it
+ //while we're still in debugger space.
+ emulLdSt();
+ } else if ((gdbstub_savedRegs.reason&0x88)==0x8) {
+ //We stopped due to a BREAK instruction. Skip over it.
+ //Check the instruction first; gdb may have replaced it with the original instruction
+ //if it's one of the breakpoints it set.
+ if (readbyte(gdbstub_savedRegs.pc+2)==0 &&
+ (readbyte(gdbstub_savedRegs.pc+1)&0xf0)==0x40 &&
+ (readbyte(gdbstub_savedRegs.pc)&0x0f)==0x00) {
+ gdbstub_savedRegs.pc+=3;
+ }
+ } else if ((gdbstub_savedRegs.reason&0x90)==0x10) {
+ //We stopped due to a BREAK.N instruction. Skip over it, after making sure the instruction
+ //actually is a BREAK.N
+ if ((readbyte(gdbstub_savedRegs.pc+1)&0xf0)==0xf0 &&
+ readbyte(gdbstub_savedRegs.pc)==0x2d) {
+ gdbstub_savedRegs.pc+=3;
+ }
+ }
+ ets_wdt_enable();
+}
+
+
+#if GDBSTUB_FREERTOS
+//Freetos exception. This routine is called by an assembly routine in gdbstub-entry.S
+void ATTR_GDBFN gdbstub_handle_user_exception() {
+ ets_wdt_disable();
+ gdbstub_savedRegs.reason|=0x80; //mark as an exception reason
+ sendReason();
+ while(gdbReadCommand()!=ST_CONT);
+ ets_wdt_enable();
+}
+#else
+
+//Non-OS exception handler. Gets called by the Xtensa HAL.
+static void ATTR_GDBFN gdb_exception_handler(struct XTensa_exception_frame_s *frame) {
+ //Save the extra registers the Xtensa HAL doesn't save
+ gdbstub_save_extra_sfrs_for_exception();
+ //Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+ os_memcpy(&gdbstub_savedRegs, frame, 19*4);
+ //Credits go to Cesanta for this trick. A1 seems to be destroyed, but because it
+ //has a fixed offset from the address of the passed frame, we can recover it.
+ gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
+
+ gdbstub_savedRegs.reason|=0x80; //mark as an exception reason
+
+ ets_wdt_disable();
+ sendReason();
+ while(gdbReadCommand()!=ST_CONT);
+ ets_wdt_enable();
+
+ //Copy any changed registers back to the frame the Xtensa HAL uses.
+ os_memcpy(frame, &gdbstub_savedRegs, 19*4);
+}
+#endif
+
+#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+//Replacement putchar1 routine. Instead of spitting out the character directly, it will buffer up to
+//OBUFLEN characters (or up to a \n, whichever comes earlier) and send it out as a gdb stdout packet.
+static void ATTR_GDBFN gdb_semihost_putchar1(char c) {
+ int i;
+ obuf[obufpos++]=c;
+ if (c=='\n' || obufpos==OBUFLEN) {
+ gdbPacketStart();
+ gdbPacketChar('O');
+ for (i=0; i>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
+ while (fifolen!=0) {
+ if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
+ fifolen--;
+ }
+ WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
+
+ if (doDebug) {
+ //Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+ os_memcpy(&gdbstub_savedRegs, frame, 19*4);
+ gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
+
+ gdbstub_savedRegs.reason=0xff; //mark as user break reason
+
+ ets_wdt_disable();
+ sendReason();
+ while(gdbReadCommand()!=ST_CONT);
+ ets_wdt_enable();
+ //Copy any changed registers back to the frame the Xtensa HAL uses.
+ os_memcpy(frame, &gdbstub_savedRegs, 19*4);
+ }
+}
+
+static void ATTR_GDBINIT install_uart_hdlr() {
+ ets_isr_attach(ETS_UART_INUM, uart_hdlr, NULL);
+ SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+ ets_isr_unmask((1<>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
+ while (fifolen!=0) {
+ if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
+ fifolen--;
+ }
+ WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
+
+ if (doDebug) {
+ //Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+ gdbstub_savedRegs.pc=frame->pc;
+ gdbstub_savedRegs.ps=frame->ps;
+ gdbstub_savedRegs.sar=frame->sar;
+ gdbstub_savedRegs.a0=frame->a[0];
+ gdbstub_savedRegs.a1=frame->a[1];
+ for (x=2; x<16; x++) gdbstub_savedRegs.a[x-2]=frame->a[x];
+
+// gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
+
+ gdbstub_savedRegs.reason=0xff; //mark as user break reason
+
+// ets_wdt_disable();
+ sendReason();
+ while(gdbReadCommand()!=ST_CONT);
+// ets_wdt_enable();
+ //Copy any changed registers back to the frame the Xtensa HAL uses.
+ frame->pc=gdbstub_savedRegs.pc;
+ frame->ps=gdbstub_savedRegs.ps;
+ frame->sar=gdbstub_savedRegs.sar;
+ frame->a[0]=gdbstub_savedRegs.a0;
+ frame->a[1]=gdbstub_savedRegs.a1;
+ for (x=2; x<16; x++) frame->a[x]=gdbstub_savedRegs.a[x-2];
+ }
+}
+
+static void ATTR_GDBINIT install_uart_hdlr() {
+ _xt_isr_attach(ETS_UART_INUM, gdbstub_uart_entry);
+ SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+ _xt_isr_unmask((1<