Commit bbeb09b6 authored by Terry Ellison's avatar Terry Ellison Committed by Marcel Stör
Browse files

Squashed updates do get Lua51 and Lua53 working (#3075)

-  Lots of minor but nasty bugfixes to get all tests to run clean
-  core lua and test suite fixes to allow luac -F to run cleanly against test suite
-  next tranch to get LFS working
-  luac.cross -a options plus fixes from feedback
-  UART fixes and lua.c merge
-  commit of wip prior to rebaselining against current dev
-  more tweaks
parent 99aba344
...@@ -3,31 +3,39 @@ ...@@ -3,31 +3,39 @@
| :----- | :-------------------- | :---------- | :------ | | :----- | :-------------------- | :---------- | :------ |
| 2016-09-18 | [Philip Gladstone](https://github.com/pjsg) | [Philip Gladstone](https://github.com/pjsg) | [gdbstub.c](../../app/modules/gdbstub.c)| | 2016-09-18 | [Philip Gladstone](https://github.com/pjsg) | [Philip Gladstone](https://github.com/pjsg) | [gdbstub.c](../../app/modules/gdbstub.c)|
This module provides basic source code debugging of the firmware when used in conjunction with a version of gdb built for the lx106. If you enable this module, then fatal errors (like invalid memory reads) will trap into the gdbstub. This uses UART0 to talk to GDB. If this happens while the UART0 is connected to a terminal (or some IDE like esplorer) then you will see a string starting with `$T` and a few more characters after that. This is the signal that a trap has happened, and control should be passed to gdb. This module provides basic source code debugging of the firmware when used in conjunction with a version of gdb built for the lx106. If you enable this module, then fatal errors (like invalid memory reads) will trap into the gdbstub. This uses UART0 to talk to GDB. If this happens while the UART0 is connected to a terminal (or some IDE like ESPlorer) then you will see a string starting with `$T` and a few more characters after that. This is the signal that a trap has happened, and control should be passed to gdb.
`GDB` can then be started at connected to the NodeMCU platform. If this is connected to the host system via a serial port, then the following (or close variant) ought to work: `GDB` can then be started at connected to the NodeMCU platform. If this is connected to the host system via a serial port, then the following (or close variant) ought to work:
``` ```
gdb bin/firmwarefile.bin elf-gdb bin/firmwarefile.bin
target remote /dev/ttyUSB0 target remote /dev/ttyUSB0
``` ```
At this point, you can just poke around and see what happened, but you cannot continue execution. where `elf-gdb` is a symlink or alias pointing to the `gdb` image in your Xtensa toolchain; you cannot use the default native gdb build.
In order to do interactive debugging, add a call to `gdbstub.brk()` in your Lua code. This will trigger a break instruction and will trap into gdb as above. However, continuation is supported from a break instruction and so you can single step, set breakpoints, etc. Note that the lx106 processor as configured by Espressif only supports a single hardware breakpoint. This means that you can only put a single breakpoint in flash code. You can single step as much as you like. In order to do interactive debugging, add a call to `gdbstub.brk()` or `gdbstub.pbrk()` in your Lua code. This will trigger a break instruction and will trap into gdb as above. Limited continuation is supported from a break instruction and so you can single step, set breakpoints, etc.
Note that the lx106 processor as configured by Espressif only supports a single hardware breakpoint. This means that you can only put a single breakpoint in flash code. You can single step as much as you like.
## gdbstub.open() ## gdbstub.open()
Runs gdbstub initialization routine. It has to be run only once in code. Runs gdbstub initialization routine. Note that subsequent calls are ignored and the break functions will do this automatically if not already done so this is options
#### Syntax #### Syntax
`gdbstub.open()` `gdbstub.open()`
## gdbstub.brk() ## gdbstub.brk()
Enters gdb by executing a `break 0,0` instruction. Enters gdb by executing a `break 0,0` instruction, and if necessary first does initialisation.
#### Syntax #### Syntax
`gdbstub.brk()` `gdbstub.brk()`
## gdbstub.pbrk()
Enters gdb by executing a `break 0,0` instruction, and if necessary first does initialisation; It also set the `gdboutput` mode to 1 allowing the debug client to capture and echo UART output through the debug session.
#### Syntax
`gdbstub.pbrk()`
## gdbstub.gdboutput() ## gdbstub.gdboutput()
Controls whether system output is encapsulated in gdb remote debugging protocol. This turns out not to be as useful as you would hope - mostly because you can't send input to the NodeMCU board. Also because you really only should make this call *after* you get gdb running and connected to the NodeMCU. The example below first does the break and then switches to redirect the output. This works (but you are unable to send any more console input). Controls whether system output is encapsulated in gdb remote debugging protocol. This turns out not to be as useful as you would hope - mostly because you can't send input to the NodeMCU board. Also because you really only should make this call *after* you get gdb running and connected to the NodeMCU. The example below first does the break and then switches to redirect the output. This works (but you are unable to send any more console input).
...@@ -39,17 +47,27 @@ Controls whether system output is encapsulated in gdb remote debugging protocol. ...@@ -39,17 +47,27 @@ Controls whether system output is encapsulated in gdb remote debugging protocol.
#### Example #### Example
```lua ```Lua
function entergdb() -- Enter the debugger if your code throws an error
gdbstub.brk() xpcall(someTest, function(err) gdbstub.pbrk() end)
gdbstub.gdboutput(1) ```
print("Active")
end
gdbstub.open() ```Lua
entergdb() someprolog(); gdbstub.pbrk(); mylib.method(args)
``` ```
#### Notes #### Notes
Once you attach gdb to the NodeMCU, then any further output from the NodeMCU will be discarded (as it does not match the gdb remote debugging protocol). This may (or may not) be a problem. If you want to run under gdb and see the output from the NodeMCU, then call `gdbstub.gdboutput(1)` and then output will be wrapped in the gdb protocol and display on the gdb console. You don't want to do this until gdb is attached as each packet requires an explicit ack in order to continue. - This debug functionality is aimed at assisting C library developers, who are already familiar with use of `gdb` and with some knowledge of the internal Lua APIs. Lua developers (at least with Lua 5.3 builds) are better off using the standard Lua `debug` library.
- To get the best out of remote gdb, it helps to have reduced the error that you are investigating to a specific failing test case. This second example works because you can type in this line interactively and the Lua runtime will compile this then execute the compiled code, running the debug stub. `hb mylib_method` followed by `c` will allow the runtime to continue to the point where you enter your method under test.
- See the `.gdbinit` and `.gdbinitlua` examples of how to customise the environment.
- Once you attach gdb to the NodeMCU, then you can only continue to work within the current SDK task. The session does not support continuation through the SDK to other tasks. This means that you cannot use asynchronous services such as `net`. For this reason, the stub is really only useful for working through the forensics of why a specific bug is occurring.
- If you compile your build with `DEVELOPMENT_TOOLS` and `DEVELOPMENT_USE_GDB` enabled in your `app/include/user_config.h`, then any `lua_assert()` API will call the `lua_debugbreak()` wrapper which also call the stub.
- If `gdboutput()` has not been enabled then any further output from the NodeMCU will be discarded (as it does not match the gdb remote debugging protocol). This may (or may not) be a problem. If you want to run under gdb and see the output from the NodeMCU, then call `gdbstub.gdboutput(1)` or use `gdbstub.pbrk()`.
The main functional limitation of the environment is that the ESP8266 only supports a single hardware breakpoint at any time (the gdb `hb` and `wa` instruction) and you need to use hardware breakpoints for debugging firmware based code. This means that you cannot break on multiple code paths. On method of mitigating this is to make liberal use of `lua_assert()` statements in your code; these will enter into a debug session on failure. (They are optimised out on normal production builds.)
...@@ -297,7 +297,7 @@ If a `group` is given the return value will be a table containing the following ...@@ -297,7 +297,7 @@ If a `group` is given the return value will be a table containing the following
- for `group` = `"sw_version"` - for `group` = `"sw_version"`
- `git_branch` (string) - `git_branch` (string)
- `git_commit_id` (string) - `git_commit_id` (string)
- `git_release` (string) release name +additional commits e.g. "2.0.0-master_20170202 +403" - `git_release` (string) release name +additional commits e.g. "2.0.0-master_20170202 +403"
- `git_commit_dts` (string) commit timestamp in an ordering format. e.g. "201908111200" - `git_commit_dts` (string) commit timestamp in an ordering format. e.g. "201908111200"
- `node_version_major` (number) - `node_version_major` (number)
- `node_version_minor` (number) - `node_version_minor` (number)
...@@ -419,6 +419,7 @@ node.restore() ...@@ -419,6 +419,7 @@ node.restore()
node.restart() -- ensure the restored settings take effect node.restart() -- ensure the restored settings take effect
``` ```
## node.setcpufreq() ## node.setcpufreq()
Change the working CPU Frequency. Change the working CPU Frequency.
...@@ -536,6 +537,33 @@ Put NodeMCU in light sleep mode to reduce current consumption. ...@@ -536,6 +537,33 @@ Put NodeMCU in light sleep mode to reduce current consumption.
- [`wifi.resume()`](wifi.md#wifiresume) - [`wifi.resume()`](wifi.md#wifiresume)
- [`node.dsleep()`](#nodedsleep) - [`node.dsleep()`](#nodedsleep)
## node.startupcommand()
Overrides the default startup action on processor restart, preplacing the executing `init.lua` if it exists.
####Syntax
`node.startupcommand(string)`
#### Parameters
- `string` prefixed with either
- `@`, the remaining string is a filename to be executed.
- `=`, the remaining string is Lua chunk to be compiled and executed.
#### Returns
`status` this is `false` if write to the Reboot Config Record fails. Note that no attempt is made to parse or validate the string. If the command is invalid or the file missing then this will be reported on the next restart.
#### Example
```lua
node.startupcommand("@myappstart.lc") -- Execute the compiled file myappstart.lc on startup
```
```lua
-- Execute the LFS routine init() in preference to init.lua
node.startupcommand("=if LFS.init then LFS.init() else dofile('init.lua') end")
```
## node.stripdebug() ## node.stripdebug()
Controls the amount of debug information kept during [`node.compile()`](#nodecompile), and allows removal of debug information from already compiled Lua code. Controls the amount of debug information kept during [`node.compile()`](#nodecompile), and allows removal of debug information from already compiled Lua code.
......
...@@ -45,7 +45,7 @@ Currently only the "data" event is supported. ...@@ -45,7 +45,7 @@ Currently only the "data" event is supported.
- if n<255, the callback is called when n chars are received - if n<255, the callback is called when n chars are received
- if one char "c", the callback will be called when "c" is encountered, or max n=255 received - if one char "c", the callback will be called when "c" is encountered, or max n=255 received
- `function` callback function, event "data" has a callback like this: `function(data) end` - `function` callback function, event "data" has a callback like this: `function(data) end`
- `run_input` 0 or 1. If 0, input from UART will not go into Lua interpreter, can accept binary data. If 1, input from UART will go into Lua interpreter, and run. - `run_input` 0 or 1. If 0, input from UART will not go into Lua interpreter, and this can accept binary data. If 1, input from UART is treated as a text stream with the `DEL`, `BS`, `CR` and `LF` characters processed as normal. Completed lines will be passed to the Lua interpreter for execution. _Note that the interpreter only processes complete lines._
To unregister the callback, provide only the "data" parameter. To unregister the callback, provide only the "data" parameter.
......
...@@ -108,11 +108,14 @@ SECTIONS ...@@ -108,11 +108,14 @@ SECTIONS
* SDK libraries that used in bootup process, interruption handling * SDK libraries that used in bootup process, interruption handling
* and other ways where flash cache (iROM) is unavailable: * and other ways where flash cache (iROM) is unavailable:
*/ */
*libmain.a:*( .literal .literal.* .text .text.*) *libmain.a:*( .literal .literal.* .text .text.*)
*libphy.a:*( .literal .literal.* .text .text.*) *libphy.a:*( .literal .literal.* .text .text.*)
*libpp.a:*( .literal .literal.* .text .text.*) *libpp.a:*( .literal .literal.* .text .text.*)
*libgcc.a:*( .literal .literal.* .text .text.*) *libgcc.a:_ashrdi3.o( .literal .literal.* .text .text.*)
*libnet80211.a:*(.literal .text ) *libgcc.a:_divsf3.o( .literal .literal.* .text .text.*)
*libgcc.a:_fixsfsi.o( .literal .literal.* .text .text.*)
*libgcc.a:_modsi3.o( .literal .literal.* .text .text.*)
*libnet80211.a:*( .literal .text )
/* /*
* The following SDK libraries have .literal and .text sections, but are * The following SDK libraries have .literal and .text sections, but are
* either not used in NodeMCU or are safe to execute out of in iROM: * either not used in NodeMCU or are safe to execute out of in iROM:
...@@ -241,10 +244,12 @@ SECTIONS ...@@ -241,10 +244,12 @@ SECTIONS
*(.sdk.version) *(.sdk.version)
/* Link-time arrays containing the defs for the included modules */ /* Link-time arrays containing the defs for the included modules */
. = ALIGN(4); . = ALIGN(8);
lua_libs_base = ABSOLUTE(.); lua_libs_base = ABSOLUTE(.);
/* Allow either empty define or defined-to-1 to include the module */ /* Allow either empty define or defined-to-1 to include the module */
KEEP(*(.lua_libs)) KEEP(*(.lua_libs))
*liblua.a:linit.o(.lua_libs)
*(.lua_libs)
LONG(0) LONG(0) /* Null-terminate the array */ LONG(0) LONG(0) /* Null-terminate the array */
lua_rotable_base = ABSOLUTE(.); lua_rotable_base = ABSOLUTE(.);
KEEP(*(.lua_rotable)) KEEP(*(.lua_rotable))
......
#ifndef _SDK_OVERRIDE_ESPCONN_H_
#define _SDK_OVERRIDE_ESPCONN_H_
// Pull in the correct lwIP header
#include "../../app/include/lwip/app/espconn.h"
#endif
../../app/include/lwip/app/espconn.h
\ No newline at end of file
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
# define BUFSIZ 1024 # define BUFSIZ 1024
#endif #endif
extern void output_redirect(const char *str, size_t l);
#define puts(s) output_redirect((s), strlen(s))
#define printf(...) do { \ #define printf(...) do { \
unsigned char __printf_buf[BUFSIZ]; \ char __printf_buf[BUFSIZ]; \
sprintf(__printf_buf, __VA_ARGS__); \ sprintf(__printf_buf, __VA_ARGS__); \
puts(__printf_buf); \ puts(__printf_buf); \
} while(0) } while(0)
extern void output_redirect(const char *str);
#define puts output_redirect
#endif #endif
...@@ -126,7 +126,7 @@ def load_PT(data, args): ...@@ -126,7 +126,7 @@ def load_PT(data, args):
""" """
PTrec,recs = unpack_RCR(data) PTrec,recs = unpack_RCR(data)
flash_size = args.fs if args.fs is not None else DEFAULT_FLASH_SIZE flash_size = fs.args if args.fs is not None else DEFAULT_FLASH_SIZE
# The partition table format is a set of 3*uint32 fields (type, addr, size), # The partition table format is a set of 3*uint32 fields (type, addr, size),
# with the optional last slot being an end marker (0,size,0) where size is # with the optional last slot being an end marker (0,size,0) where size is
...@@ -308,7 +308,7 @@ def main(): ...@@ -308,7 +308,7 @@ def main():
raise FatalError("SPIFFS image %s does not exist" % arg.sf) raise FatalError("SPIFFS image %s does not exist" % arg.sf)
base = [] if arg.port is None else ['--port',arg.port] base = [] if arg.port is None else ['--port',arg.port]
if arg.baud is not None: base.extend(['--baud',arg.baud]) if arg.baud is not None: base.extend(['--baud',str(arg.baud)])
# ---------- Use esptool to read the PT ---------- # # ---------- Use esptool to read the PT ---------- #
...@@ -316,6 +316,7 @@ def main(): ...@@ -316,6 +316,7 @@ def main():
pt_file = tmpdir + '/pt.dmp' pt_file = tmpdir + '/pt.dmp'
espargs = base+['--after', 'no_reset', 'read_flash', '--no-progress', espargs = base+['--after', 'no_reset', 'read_flash', '--no-progress',
str(ROM0_Seg), str(FLASH_PAGESIZE), pt_file] str(ROM0_Seg), str(FLASH_PAGESIZE), pt_file]
esptool.main(espargs) esptool.main(espargs)
with open(pt_file,"rb") as f: with open(pt_file,"rb") as f:
......
File mode changed from 100644 to 100755
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment