mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-25 14:00:20 +00:00
[FL-3299] furi_crash: added C2 status; added fw-version gdb command (#2638)
* furi_crash: added C2 status * debug: Added "fw-version" gdb command; vscode: updated configuration to use new command * debug: added fw-info command to debug_other session * Toolbox: versioned structure for Version * debug: fw-version: no longer needs an ELF file loaded * debug: flipperversion: removed unused variable * debug_other: print running fw version Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
parent
268b88be0d
commit
241b4ef6e4
12 changed files with 205 additions and 22 deletions
17
.vscode/example/launch.json
vendored
17
.vscode/example/launch.json
vendored
|
@ -36,6 +36,8 @@
|
|||
"./debug/stm32wbx.cfg",
|
||||
],
|
||||
"postAttachCommands": [
|
||||
"source debug/flipperversion.py",
|
||||
"fw-version",
|
||||
// "compare-sections",
|
||||
"source debug/flipperapps.py",
|
||||
"fap-set-debug-elf-root build/latest/.extapps",
|
||||
|
@ -59,6 +61,8 @@
|
|||
"attach 1",
|
||||
"set confirm off",
|
||||
"set mem inaccessible-by-default off",
|
||||
"source debug/flipperversion.py",
|
||||
"fw-version",
|
||||
"source debug/flipperapps.py",
|
||||
"fap-set-debug-elf-root build/latest/.extapps",
|
||||
// "compare-sections",
|
||||
|
@ -77,6 +81,8 @@
|
|||
"svdFile": "./debug/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"postAttachCommands": [
|
||||
"source debug/flipperversion.py",
|
||||
"fw-version",
|
||||
"source debug/flipperapps.py",
|
||||
"fap-set-debug-elf-root build/latest/.extapps",
|
||||
]
|
||||
|
@ -97,20 +103,13 @@
|
|||
"./debug/stm32wbx.cfg",
|
||||
],
|
||||
"postAttachCommands": [
|
||||
"source debug/flipperversion.py",
|
||||
"fw-version",
|
||||
"source debug/flipperapps.py",
|
||||
"fap-set-debug-elf-root build/latest/.extapps",
|
||||
],
|
||||
// "showDevDebugOutput": "raw",
|
||||
},
|
||||
{
|
||||
"name": "fbt debug",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "./lib/scons/scripts/scons.py",
|
||||
"args": [
|
||||
"plugin_dist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "python debug",
|
||||
"type": "python",
|
||||
|
|
16
SConstruct
16
SConstruct
|
@ -239,19 +239,31 @@ distenv.PhonyTarget(
|
|||
)
|
||||
|
||||
# Debug alien elf
|
||||
debug_other_opts = [
|
||||
"-ex",
|
||||
"source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py",
|
||||
# "-ex",
|
||||
# "source ${FBT_DEBUG_DIR}/FreeRTOS/FreeRTOS.py",
|
||||
"-ex",
|
||||
"source ${FBT_DEBUG_DIR}/flipperversion.py",
|
||||
"-ex",
|
||||
"fw-version",
|
||||
]
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"debug_other",
|
||||
"${GDBPYCOM}",
|
||||
GDBOPTS="${GDBOPTS_BASE}",
|
||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||
GDBPYOPTS='-ex "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py" ',
|
||||
GDBPYOPTS=debug_other_opts,
|
||||
)
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"debug_other_blackmagic",
|
||||
"${GDBPYCOM}",
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBREMOTE="$${BLACKMAGIC_ADDR}",
|
||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||
GDBPYOPTS=debug_other_opts,
|
||||
)
|
||||
|
||||
|
||||
|
|
109
debug/flipperversion.py
Normal file
109
debug/flipperversion.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
from dataclasses import dataclass, field
|
||||
from typing import Dict, Optional
|
||||
|
||||
import gdb
|
||||
|
||||
|
||||
# Must match FuriHalRtcRegisterVersion index in FuriHalRtcRegister enum
|
||||
RTC_BACKUP_VERSION_REGISTER_IDX = 0x2
|
||||
|
||||
RTC_BASE = 0x40002800
|
||||
RTC_BACKUP_BASE = RTC_BASE + 0x50
|
||||
|
||||
VERSION_REGISTER_ADDRESS = RTC_BACKUP_BASE + RTC_BACKUP_VERSION_REGISTER_IDX * 4
|
||||
|
||||
VERSION_STRUCT_MAGIC = 0xBE40
|
||||
|
||||
|
||||
@dataclass
|
||||
class VersionData:
|
||||
git_hash: str
|
||||
git_branch: str
|
||||
build_date: str
|
||||
version: str
|
||||
target: int
|
||||
build_is_dirty: bool
|
||||
extra: Optional[Dict[str, str]] = field(default_factory=dict)
|
||||
|
||||
|
||||
class VersionLoader:
|
||||
def __init__(self, version_ptr):
|
||||
self.version_ptr = version_ptr
|
||||
self._cstr_type = gdb.lookup_type("char").pointer()
|
||||
self._uint_type = gdb.lookup_type("unsigned int")
|
||||
|
||||
version_signature = version_ptr.dereference().cast(self._uint_type)
|
||||
is_versioned = (version_signature & (0xFFFF)) == VERSION_STRUCT_MAGIC
|
||||
if is_versioned:
|
||||
self._version_data = self.load_versioned(
|
||||
major=version_signature >> 16 & 0xFF,
|
||||
minor=version_signature >> 24 & 0xFF,
|
||||
)
|
||||
else:
|
||||
self._version_data = self.load_unversioned()
|
||||
|
||||
@property
|
||||
def version(self) -> VersionData:
|
||||
return self._version_data
|
||||
|
||||
def load_versioned(self, major, minor):
|
||||
if major != 1:
|
||||
raise ValueError("Unsupported version struct major version")
|
||||
|
||||
# Struct version 1.0
|
||||
extra_data = int(self.version_ptr[5].cast(self._uint_type))
|
||||
return VersionData(
|
||||
git_hash=self.version_ptr[1].cast(self._cstr_type).string(),
|
||||
git_branch=self.version_ptr[2].cast(self._cstr_type).string(),
|
||||
build_date=self.version_ptr[3].cast(self._cstr_type).string(),
|
||||
version=self.version_ptr[4].cast(self._cstr_type).string(),
|
||||
target=extra_data & 0xF,
|
||||
build_is_dirty=bool((extra_data >> 8) & 0xF),
|
||||
)
|
||||
|
||||
def load_unversioned(self):
|
||||
"""Parse an early version of the version struct."""
|
||||
extra_data = int(self.version_ptr[5].cast(self._uint_type))
|
||||
return VersionData(
|
||||
git_hash=self.version_ptr[0].cast(self._cstr_type).string(),
|
||||
git_branch=self.version_ptr[1].cast(self._cstr_type).string(),
|
||||
# branch number is #2, but we don't care about it
|
||||
build_date=self.version_ptr[3].cast(self._cstr_type).string(),
|
||||
version=self.version_ptr[4].cast(self._cstr_type).string(),
|
||||
target=extra_data & 0xF,
|
||||
build_is_dirty=bool((extra_data >> 8) & 0xF),
|
||||
)
|
||||
|
||||
|
||||
class FlipperFwVersion(gdb.Command):
|
||||
"""Print the version of Flipper's firmware."""
|
||||
|
||||
def __init__(self):
|
||||
super(FlipperFwVersion, self).__init__("fw-version", gdb.COMMAND_USER)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
void_ptr_type = gdb.lookup_type("void").pointer().pointer()
|
||||
version_ptr_ptr = gdb.Value(VERSION_REGISTER_ADDRESS).cast(void_ptr_type)
|
||||
|
||||
if not version_ptr_ptr:
|
||||
print("RTC version register is NULL")
|
||||
return
|
||||
|
||||
version_ptr = version_ptr_ptr.dereference()
|
||||
if not version_ptr:
|
||||
print("Pointer to version struct is NULL")
|
||||
return
|
||||
|
||||
version_struct = version_ptr.cast(void_ptr_type)
|
||||
|
||||
v = VersionLoader(version_struct)
|
||||
print("Firmware version on attached Flipper:")
|
||||
print(f"\tVersion: {v.version.version}")
|
||||
print(f"\tBuilt on: {v.version.build_date}")
|
||||
print(f"\tGit branch: {v.version.git_branch}")
|
||||
print(f"\tGit commit: {v.version.git_hash}")
|
||||
print(f"\tDirty: {v.version.build_is_dirty}")
|
||||
print(f"\tHW Target: {v.version.target}")
|
||||
|
||||
|
||||
FlipperFwVersion()
|
|
@ -1,5 +1,5 @@
|
|||
entry,status,name,type,params
|
||||
Version,+,26.0,,
|
||||
Version,+,26.1,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
|
@ -823,6 +823,7 @@ Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, voi
|
|||
Function,+,furi_hal_bt_clear_white_list,_Bool,
|
||||
Function,+,furi_hal_bt_dump_state,void,FuriString*
|
||||
Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode
|
||||
Function,-,furi_hal_bt_get_hardfault_info,const FuriHalBtHardfaultInfo*,
|
||||
Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*"
|
||||
Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack,
|
||||
Function,+,furi_hal_bt_get_rssi,float,
|
||||
|
|
|
|
@ -1,5 +1,5 @@
|
|||
entry,status,name,type,params
|
||||
Version,+,26.0,,
|
||||
Version,+,26.1,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
|
@ -1004,6 +1004,7 @@ Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, voi
|
|||
Function,+,furi_hal_bt_clear_white_list,_Bool,
|
||||
Function,+,furi_hal_bt_dump_state,void,FuriString*
|
||||
Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode
|
||||
Function,-,furi_hal_bt_get_hardfault_info,const FuriHalBtHardfaultInfo*,
|
||||
Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*"
|
||||
Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack,
|
||||
Function,+,furi_hal_bt_get_rssi,float,
|
||||
|
|
|
|
@ -19,6 +19,8 @@
|
|||
/* Time, in ms, to wait for mode transition before crashing */
|
||||
#define C2_MODE_SWITCH_TIMEOUT 10000
|
||||
|
||||
#define FURI_HAL_BT_HARDFAULT_INFO_MAGIC 0x1170FD0F
|
||||
|
||||
FuriMutex* furi_hal_bt_core2_mtx = NULL;
|
||||
static FuriHalBtStack furi_hal_bt_stack = FuriHalBtStackUnknown;
|
||||
|
||||
|
@ -440,3 +442,12 @@ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode) {
|
|||
FURI_LOG_E(TAG, "Failed to switch C2 mode: %d", fw_start_res);
|
||||
return false;
|
||||
}
|
||||
|
||||
const FuriHalBtHardfaultInfo* furi_hal_bt_get_hardfault_info() {
|
||||
/* AN5289, 4.8.2 */
|
||||
const FuriHalBtHardfaultInfo* info = (FuriHalBtHardfaultInfo*)(SRAM2A_BASE);
|
||||
if(info->magic != FURI_HAL_BT_HARDFAULT_INFO_MAGIC) {
|
||||
return NULL;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
|
|
@ -224,6 +224,19 @@ uint32_t furi_hal_bt_get_transmitted_packets();
|
|||
*/
|
||||
bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode);
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t source_pc;
|
||||
uint32_t source_lr;
|
||||
uint32_t source_sp;
|
||||
} FuriHalBtHardfaultInfo;
|
||||
|
||||
/** Get hardfault info
|
||||
*
|
||||
* @return hardfault info. NULL if no hardfault
|
||||
*/
|
||||
const FuriHalBtHardfaultInfo* furi_hal_bt_get_hardfault_info();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_debug.h>
|
||||
#include <furi_hal_bt.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
|
@ -87,6 +88,20 @@ static void __furi_print_stack_info() {
|
|||
__furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4);
|
||||
}
|
||||
|
||||
static void __furi_print_bt_stack_info() {
|
||||
const FuriHalBtHardfaultInfo* fault_info = furi_hal_bt_get_hardfault_info();
|
||||
if(fault_info == NULL) {
|
||||
furi_hal_console_puts("\r\n\tcore2: not faulted");
|
||||
} else {
|
||||
furi_hal_console_puts("\r\n\tcore2: hardfaulted.\r\n\tPC: ");
|
||||
__furi_put_uint32_as_hex(fault_info->source_pc);
|
||||
furi_hal_console_puts("\r\n\tLR: ");
|
||||
__furi_put_uint32_as_hex(fault_info->source_lr);
|
||||
furi_hal_console_puts("\r\n\tSP: ");
|
||||
__furi_put_uint32_as_hex(fault_info->source_sp);
|
||||
}
|
||||
}
|
||||
|
||||
static void __furi_print_heap_info() {
|
||||
furi_hal_console_puts("\r\n\t heap total: ");
|
||||
__furi_put_uint32_as_text(xPortGetTotalHeapSize());
|
||||
|
@ -136,6 +151,7 @@ FURI_NORETURN void __furi_crash() {
|
|||
__furi_print_stack_info();
|
||||
}
|
||||
__furi_print_heap_info();
|
||||
__furi_print_bt_stack_info();
|
||||
|
||||
#ifndef FURI_DEBUG
|
||||
// Check if debug enabled by DAP
|
||||
|
|
|
@ -1,23 +1,34 @@
|
|||
#include "version.h"
|
||||
|
||||
#include <furi.h>
|
||||
/* This header is autogenerated by build system */
|
||||
#include "version.inc.h"
|
||||
|
||||
#define VERSION_MAGIC (0xBE40u)
|
||||
#define VERSION_MAJOR (0x1u)
|
||||
#define VERSION_MINOR (0x0u)
|
||||
|
||||
struct Version {
|
||||
// Header
|
||||
const uint16_t magic;
|
||||
const uint8_t major;
|
||||
const uint8_t minor;
|
||||
// Payload
|
||||
const char* git_hash;
|
||||
const char* git_branch;
|
||||
const char* git_branch_num;
|
||||
const char* build_date;
|
||||
const char* version;
|
||||
// Payload bits and pieces
|
||||
const uint8_t target;
|
||||
const bool build_is_dirty;
|
||||
};
|
||||
|
||||
/* version of current running firmware (bootloader/flipper) */
|
||||
static const Version version = {
|
||||
.magic = VERSION_MAGIC,
|
||||
.major = VERSION_MAJOR,
|
||||
.minor = VERSION_MINOR,
|
||||
.git_hash = GIT_COMMIT,
|
||||
.git_branch = GIT_BRANCH,
|
||||
.git_branch_num = GIT_BRANCH_NUM,
|
||||
.build_date = BUILD_DATE,
|
||||
.version = VERSION
|
||||
#ifdef FURI_RAM_EXEC
|
||||
|
@ -41,7 +52,8 @@ const char* version_get_gitbranch(const Version* v) {
|
|||
}
|
||||
|
||||
const char* version_get_gitbranchnum(const Version* v) {
|
||||
return v ? v->git_branch_num : version.git_branch_num;
|
||||
UNUSED(v);
|
||||
return "0";
|
||||
}
|
||||
|
||||
const char* version_get_builddate(const Version* v) {
|
||||
|
|
|
@ -39,10 +39,10 @@ def generate(env, **kw):
|
|||
"|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
||||
],
|
||||
GDBOPTS_BASE=[
|
||||
"-ex",
|
||||
"target extended-remote ${GDBREMOTE}",
|
||||
"-ex",
|
||||
"source ${FBT_DEBUG_DIR}/gdbinit",
|
||||
"-ex",
|
||||
"target extended-remote ${GDBREMOTE}",
|
||||
],
|
||||
GDBOPTS_BLACKMAGIC=[
|
||||
"-q",
|
||||
|
@ -61,6 +61,8 @@ def generate(env, **kw):
|
|||
"-ex",
|
||||
"source ${FBT_DEBUG_DIR}/flipperapps.py",
|
||||
"-ex",
|
||||
"source ${FBT_DEBUG_DIR}/flipperversion.py",
|
||||
"-ex",
|
||||
"fap-set-debug-elf-root ${FBT_FAP_DEBUG_ELF_ROOT}",
|
||||
"-ex",
|
||||
"source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py",
|
||||
|
@ -68,6 +70,8 @@ def generate(env, **kw):
|
|||
"svd_load ${SVD_FILE}",
|
||||
"-ex",
|
||||
"compare-sections",
|
||||
"-ex",
|
||||
"fw-version",
|
||||
],
|
||||
JFLASHPROJECT="${FBT_DEBUG_DIR}/fw.jflash",
|
||||
)
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
"@UFBT_DEBUG_DIR@/stm32wbx.cfg"
|
||||
],
|
||||
"postAttachCommands": [
|
||||
"source @UFBT_DEBUG_DIR@/flipperversion.py",
|
||||
"fw-version",
|
||||
"source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
"fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
],
|
||||
|
@ -49,6 +51,8 @@
|
|||
"@UFBT_DEBUG_DIR@/stm32wbx.cfg"
|
||||
],
|
||||
"postAttachCommands": [
|
||||
"source @UFBT_DEBUG_DIR@/flipperversion.py",
|
||||
"fw-version",
|
||||
"source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
"fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
],
|
||||
|
@ -69,6 +73,8 @@
|
|||
"attach 1",
|
||||
"set confirm off",
|
||||
"set mem inaccessible-by-default off",
|
||||
"source @UFBT_DEBUG_DIR@/flipperversion.py",
|
||||
"fw-version",
|
||||
"source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
"fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
]
|
||||
|
@ -86,6 +92,8 @@
|
|||
"svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"postAttachCommands": [
|
||||
"source @UFBT_DEBUG_DIR@/flipperversion.py",
|
||||
"fw-version",
|
||||
"source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
"fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
]
|
||||
|
|
|
@ -35,8 +35,6 @@ class GitVersion:
|
|||
or "unknown"
|
||||
)
|
||||
|
||||
branch_num = self._exec_git("rev-list --count HEAD") or "n/a"
|
||||
|
||||
try:
|
||||
version = self._exec_git("describe --tags --abbrev=0 --exact-match")
|
||||
except subprocess.CalledProcessError:
|
||||
|
@ -45,7 +43,6 @@ class GitVersion:
|
|||
return {
|
||||
"GIT_COMMIT": commit,
|
||||
"GIT_BRANCH": branch,
|
||||
"GIT_BRANCH_NUM": branch_num,
|
||||
"VERSION": version,
|
||||
"BUILD_DIRTY": dirty and 1 or 0,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue