[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:
hedger 2023-05-09 01:31:39 +03:00 committed by GitHub
parent 268b88be0d
commit 241b4ef6e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 205 additions and 22 deletions

View file

@ -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",

View file

@ -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
View 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()

View file

@ -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 entry status name type params
2 Version + 26.0 26.1
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
823 Function + furi_hal_bt_clear_white_list _Bool
824 Function + furi_hal_bt_dump_state void FuriString*
825 Function + furi_hal_bt_ensure_c2_mode _Bool BleGlueC2Mode
826 Function - furi_hal_bt_get_hardfault_info const FuriHalBtHardfaultInfo*
827 Function + furi_hal_bt_get_key_storage_buff void uint8_t**, uint16_t*
828 Function + furi_hal_bt_get_radio_stack FuriHalBtStack
829 Function + furi_hal_bt_get_rssi float

View file

@ -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,

1 entry status name type params
2 Version + 26.0 26.1
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1004 Function + furi_hal_bt_clear_white_list _Bool
1005 Function + furi_hal_bt_dump_state void FuriString*
1006 Function + furi_hal_bt_ensure_c2_mode _Bool BleGlueC2Mode
1007 Function - furi_hal_bt_get_hardfault_info const FuriHalBtHardfaultInfo*
1008 Function + furi_hal_bt_get_key_storage_buff void uint8_t**, uint16_t*
1009 Function + furi_hal_bt_get_radio_stack FuriHalBtStack
1010 Function + furi_hal_bt_get_rssi float

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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",
)

View file

@ -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@"
]

View file

@ -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,
}