Commit 5e1d6cfb authored by Jeffrey Lee's avatar Jeffrey Lee
Browse files

Add exception dump generation and processing facilities

Detail:
  This set of changes adds support for the following features:
  * A new code system variable, Debugger$DumpOptions, to control whether exception/crash dumps are collected from SeriousErrorV and where they should be output
  * Dump output can be in raw (binary) or annotated (text) form.
  * Annotated form provides detailed annotation of the stack(s), detecting certain constructs such as SWI invocations, IRQsema frames, CMHG veneers, APCS stack frame chains, and most forms of assembler function calls. The output isn't as easy to understand as a proper stack backtrace would be, but the low-level nature allows it to cope with corrupt or partially-overwritten stack frames, and avoids making invasive changes to components in order to make them backtrace-friendly
  * Stack annotation is able to make use of embedded ROM debug symbols (to be supported by romlinker 0.06) and Norcroft-style embedded function names in order to provide function-level location information for most ROM components and applications
  * System variables Debugger$RawFile and Debugger$AnnotatedFile to specify where to save raw and annotated exception dumps (preliminary, approach may change in future)
  * As well as supporting saving to file, the exception dumps can also be sent to the HAL via HAL_DebugTX, or if a program is driving SeriousErrorV directly it can use SeriousErrorV_CustomReport to have it fed to a custom callback function
  The code is structured in such a way that the core dump annotation code can potentially be built into a standalone application to allow offline processing of dumps (offline application not part of this checkin)
  File changes:
  c/exc, h/exc - Core code for producing the annotated exception dumps
  hdr/ExcDump - Header detailing the format of the binary dump
  s/ExceptionDump - Code variable and SeriousErrorV handling. Several support calls (used by c/exc) are also implemented here, in order to separate the dump processing from any interrogation of the originating machine
  Makefile - Updated for c/exc inclusion, and C header generation from hdr/ExcDump
  Resources/UK/Messages, Resources/Germany/Messages - New messages used by exception dump code
  c/support - Add a strcmp implementation, and extend vsprintf to be vsnprintf. Add support for string width format specifier.
  s/Debugger - Workspace definitions and init/shutdown hooks for exception dump code. Refactor *Where so that the locate logic is separate from the message output logic, to allow the locate logic to be used by the exception dump code.
Admin:
  Tested on Raspberry Pi
  German messages in need of translation


Version 1.92. Tagged as 'Debugger-1_92'
parent 7d3b9924
......@@ -31,7 +31,7 @@ HELPSRC = HelpSrc
TOKENSOURCE = TokHelpSrc
TOKHELPSRC = ${TOKENSOURCE}
ASMHDRS = Debugger
OBJS = Debugger util dis2_vfp support
OBJS = Debugger util dis2_vfp support exc
HDRS =
CMHGFILE =
......@@ -116,9 +116,15 @@ dis2_vfp.o: dis2_vfp.c
dis2_vfp.oz: dis2_vfp.c
${CC} ${CFLAGS} ${C_MODULE} -o $@ dis2_vfp.c
excdump.h: hdr.ExcDump
${HDR2H} hdr.ExcDump $@
exc.c: excdump.h
clean::
${RM} c.dis2_vfp
${RM} c.dis2_arm
${RM} h.excdump
${RM} ${TOKENSOURCE}
# Stuff from AAsmModule that's missing from CModule
......
No preview for this file type
No preview for this file type
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "1.91"
Module_Version SETA 191
Module_MajorVersion SETS "1.92"
Module_Version SETA 192
Module_MinorVersion SETS ""
Module_Date SETS "03 Mar 2016"
Module_ApplicationDate SETS "03-Mar-16"
Module_Date SETS "05 Apr 2016"
Module_ApplicationDate SETS "05-Apr-16"
Module_ComponentName SETS "Debugger"
Module_ComponentPath SETS "castle/RiscOS/Sources/Programmer/Debugger"
Module_FullVersion SETS "1.91"
Module_HelpVersion SETS "1.91 (03 Mar 2016)"
Module_FullVersion SETS "1.92"
Module_HelpVersion SETS "1.92 (05 Apr 2016)"
END
/* (1.91)
/* (1.92)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 1.91
#define Module_MajorVersion_CMHG 1.92
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 03 Mar 2016
#define Module_Date_CMHG 05 Apr 2016
#define Module_MajorVersion "1.91"
#define Module_Version 191
#define Module_MajorVersion "1.92"
#define Module_Version 192
#define Module_MinorVersion ""
#define Module_Date "03 Mar 2016"
#define Module_Date "05 Apr 2016"
#define Module_ApplicationDate "03-Mar-16"
#define Module_ApplicationDate "05-Apr-16"
#define Module_ComponentName "Debugger"
#define Module_ComponentPath "castle/RiscOS/Sources/Programmer/Debugger"
#define Module_FullVersion "1.91"
#define Module_HelpVersion "1.91 (03 Mar 2016)"
#define Module_LibraryVersionInfo "1:91"
#define Module_FullVersion "1.92"
#define Module_HelpVersion "1.92 (05 Apr 2016)"
#define Module_LibraryVersionInfo "1:92"
This diff is collapsed.
......@@ -33,6 +33,18 @@ char *strcat(char *str1,const char *str2)
return ret;
}
int strcmp(const char *str1, const char *str2)
{
char c;
int diff;
do
{
c = *str1++;
diff = c - *str2++;
} while (c && !diff);
return diff;
}
void *memcpy(void *ptr1,const void *ptr2,size_t n)
{
while(n--)
......@@ -46,7 +58,7 @@ int sprintf(char *out,const char *format,...)
{
va_list a;
va_start(a,format);
int ret = vsprintf(out,format,a);
int ret = vsnprintf(out,SIZE_MAX,format,a);
va_end(a);
return ret;
}
......@@ -57,21 +69,49 @@ int _sprintf(char *out,const char *format,...)
{
va_list a;
va_start(a,format);
int ret = vsprintf(out,format,a);
int ret = vsnprintf(out,SIZE_MAX,format,a);
va_end(a);
return ret;
}
int snprintf(char *out,size_t max,const char *format,...)
{
va_list a;
va_start(a,format);
int ret = vsnprintf(out,max,format,a);
va_end(a);
return ret;
}
extern int _snprintf(char *out,size_t max,const char *format,...);
int _snprintf(char *out,size_t max,const char *format,...)
{
va_list a;
va_start(a,format);
int ret = vsnprintf(out,max,format,a);
va_end(a);
return ret;
}
int vsprintf(char *out,const char *format,va_list a)
{
int count=0;
return vsnprintf(out,SIZE_MAX,format,a);
}
#define OUTC(C) do { char chr = C; if (count < usable_max) out[count] = chr; count++; } while(0)
int vsnprintf(char *out,size_t max,const char *format,va_list a)
{
size_t count=0;
int c;
size_t usable_max = (out ? max : 0);
while((c = *format++) != 0)
{
if(c == '%')
{
/* We'll only deal with the following format specifiers:
%s (control-terminated - to cope with messages)
%[-<width>]s (control-terminated - to cope with messages)
%c
%<width>[ll]X
%<width>[ll]x
......@@ -81,6 +121,8 @@ int vsprintf(char *out,const char *format,va_list a)
int width=0;
bool islong=false;
c = *format++;
if (c == '-')
c = *format++;
while((c >= '0') && (c <= '9'))
{
width = width*10 + c - '0';
......@@ -91,12 +133,27 @@ int vsprintf(char *out,const char *format,va_list a)
case 's':
{
const char *s = va_arg(a,const char *);
while(*s >= ' ')
out[count++] = *s++;
if(width)
{
/* Assume left-justified */
do
{
OUTC(((*s >= ' ') ? *s++ : ' '));
}
while(--width);
}
else
{
while(*s >= ' ')
{
OUTC(*s++);
width--;
}
}
}
break;
case 'c':
out[count++] = va_arg(a,int);
OUTC(va_arg(a,int));
break;
case 'l':
islong = true;
......@@ -116,16 +173,18 @@ int vsprintf(char *out,const char *format,va_list a)
width = 1;
do
{
unsigned int n = h>>60;
unsigned int n = (unsigned int) (h>>60);
if(n || (i<width))
{
width = 16;
char c2;
if(n <= 9)
out[count++] = n+'0';
c2 = n+'0';
else if(c == 'X')
out[count++] = n+'A'-10;
c2 = n+'A'-10;
else
out[count++] = n+'a'-10;
c2 = n+'a'-10;
OUTC(c2);
}
h=h<<4;
} while(--i >= 0);
......@@ -138,7 +197,7 @@ int vsprintf(char *out,const char *format,va_list a)
if((i & 0x80000000) && (c == 'd'))
{
i = -i;
out[count++] = '-';
OUTC('-');
}
while(i)
{
......@@ -151,7 +210,7 @@ int vsprintf(char *out,const char *format,va_list a)
}
while(width > k)
{
out[count++] = '0';
OUTC('0');
width--;
}
c = '0';
......@@ -160,25 +219,24 @@ int vsprintf(char *out,const char *format,va_list a)
i -= j;
c++;
}
out[count++] = c;
OUTC(c);
width = k-1;
}
while(width-- >= 0)
out[count++] = '0';
OUTC('0');
}
break;
}
}
else if(c == '\\')
{
out[count++] = *format++;
}
else
{
out[count++] = c;
OUTC(c);
}
}
out[count] = 0;
if (out && max)
{
out[(count < max) ? count : (max-1)] = 0;
}
return count;
}
......
/* Copyright 2016 Castle Technology Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EXC_H
#define EXC_H
#include <stdint.h>
#include <stdbool.h>
#include "dis2.h"
/* To avoid dynamic memory allocation we use a line buffer to collect annotations before they are output
The buffer acts as a sliding window, storing the annotations for a contiguous range of memory
The buffer is flushed in a lazy manner; we only emit entries once we need to add an annotation for an address which is outside the current window
This allows us to go back and add annotations up to LINEBUFFER_SIZE lines in the past (required for e.g. STM decoding) */
#define LINEBUFFER_SIZE 32 /* 16 in an APCS frame plus 10 for a _kernel_swi_regs. But round up to power of 2 for simplicity. N.B. 32 is max due to use of bitflags */
#define LINEBUFFER_COLUMNS 4 /* If we find some overlapping stack frames (e.g. from stale data on the stack) we output them in separate columns */
#define LINEBUFFER_COLWIDTH 40
typedef struct {
uint32_t val;
bool ok;
} excresult;
typedef enum {
/* Messages used in annotations */
EXC_MSG_NONE = 0,
EXC_MSG_SWI,
EXC_MSG_MAYBEPSR,
EXC_MSG_R14_DESC,
EXC_MSG_REGNO,
EXC_MSG_IRQSEMA,
EXC_MSG_PSR,
EXC_MSG_ASMCALL,
EXC_MSG_RETURN_2DESC,
EXC_MSG_APCS,
EXC_MSG_CMHG_R0,
EXC_MSG_CMHG_RN,
EXC_MSG_CMHG_R9,
EXC_MSG_RETURN_1DESC,
EXC_MSG_APCS_BROKEN,
/* Other messages */
EXC_MSG_UNKNOWN,
EXC_MSG_OUT_OF_ANNOT,
EXC_MSG_DUMP_CORRUPT,
EXC_MSG_BLOCK_MEM,
EXC_MSG_BLOCK_OSRSI6,
EXC_MSG_BLOCK_ERROR,
EXC_MSG_BLOCK_OSMEM16,
EXC_MSG_IRQ_STACK,
EXC_MSG_SVC_STACK,
EXC_MSG_USR_STACK,
EXC_MSG_END,
EXC_MSG_CALLTO,
} exc_msg;
/* This represents a single annotation block/column (e.g. decoded stack frame) */
typedef struct exc_annotation_block {
uint8_t msgs[LINEBUFFER_SIZE]; /* Message type/number to display for the line */
uint32_t addrs[LINEBUFFER_SIZE][2]; /* Two addresses (or other values, e.g. SWI numbers) to display for the line */
uint32_t next_fp; /* Next FP value in an APCS stack frame chain - allows all frames within a chain to use the same column */
uint32_t min,max; /* Min/max address range of current (or last) block */
uint32_t lineflags; /* Each bit corresponds to a line in the buffer; bit is set if it's the middle of an annotation, clear if it's the start */
} exc_annotation_block_t;
typedef struct exc_context {
uint32_t lineaddr; /* The address of the first line in the buffer */
uint8_t line; /* The index of the first line in the buffer (it's a circular buffer) */
exc_annotation_block_t annotations[LINEBUFFER_COLUMNS];
const uint32_t *buffer; /* The buffer containing the dump blocks */
size_t bufferlen;
#ifndef MODULE
const uint32_t *rom;
size_t romlen;
#endif
void (*print)(void *param, const char *str);
void *print_param;
} exc_context_t;
typedef struct {
const uint32_t *symbols;
uint32_t romaddr;
} romsymtable;
extern __value_in_regs excresult ExcPeekMem2(exc_context_t *ctx, uint32_t addr);
extern const char *ExcGetMsg(exc_context_t *ctx, exc_msg msg);
extern void ExcDescribeAddr(exc_context_t *ctx, uint32_t addr, char *buf, size_t len);
extern __value_in_regs romsymtable ExcGetROMSymbols(void);
#endif
; Copyright 2016 Castle Technology Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; Dump block format:
; word 0: block length (including header)
; word 1: block type
; 0 -> memory dump
; word 2: base addr
; word 3+: data
; 1 -> OSRSI6 item(s)
; word 2: base index
; word 3+: data
; 2 -> register dump
; word 2+: data
; 3 -> error block
; word 2+: data
; 4 -> OS_Memory 16 items
; word 2: base item number
; word 3+: details of each item
; base of area (R1)
; address space allocated (R2)
; actual memory used (R3)
^ 0
ExcDump_Chunk_Memory # 1
ExcDump_Chunk_OSRSI6 # 1
ExcDump_Chunk_Regs # 1
ExcDump_Chunk_Error # 1
ExcDump_Chunk_OSMem16 # 1
^ 0
ExcDump_Reg_R0 # 1
ExcDump_Reg_R1 # 1
ExcDump_Reg_R2 # 1
ExcDump_Reg_R3 # 1
ExcDump_Reg_R4 # 1
ExcDump_Reg_R5 # 1
ExcDump_Reg_R6 # 1
ExcDump_Reg_R7 # 1
ExcDump_Reg_R8 # 1
ExcDump_Reg_R9 # 1
ExcDump_Reg_R10 # 1
ExcDump_Reg_R11 # 1
ExcDump_Reg_R12 # 1
ExcDump_Reg_R13 # 1
ExcDump_Reg_R14 # 1
ExcDump_Reg_R15 # 1
ExcDump_Reg_CPSR # 1
ExcDump_Reg_R13_usr # 1
ExcDump_Reg_R14_usr # 1
ExcDump_Reg_R13_svc # 1
ExcDump_Reg_R14_svc # 1
ExcDump_Reg_SPSR_svc # 1
ExcDump_Reg_R13_irq # 1
ExcDump_Reg_R14_irq # 1
ExcDump_Reg_SPSR_irq # 1
ExcDump_Reg_R13_abt # 1
ExcDump_Reg_R14_abt # 1
ExcDump_Reg_SPSR_abt # 1
ExcDump_Reg_R13_und # 1
ExcDump_Reg_R14_und # 1
ExcDump_Reg_SPSR_und # 1
ExcDump_Reg_Count # 0
ExcAnnotateAll_DescribeBlocks * 1
END
......@@ -247,8 +247,13 @@
GET Hdr:CPU.Arch
GET Hdr:OSRSI6
GET Hdr:VFPSupport
GET Hdr:HighFSI
GET Hdr:FileTypes
GET Hdr:OSMisc
GET Hdr:HALEntries
GET Hdr:Debugger
GET hdr.ExcDump
GET VersionASM
......@@ -382,6 +387,23 @@ DisReg_C # 1 ; Prefix char for Co-pro registers
CRelocOffset # 4 ; Relocation offset used by C code
]
DumpBuffer # 4
DumpBufferLen # 4
ExceptionBusy # 4 ; Tracks state of exception dump code to avoid re-entry:
; 0 -> idle
; 1 -> stage 1 busy
; 2 -> stage 2 busy
ROMDebugSymbols # 4
ROMBaseAddr # 4
DumpOptions # 4
DumpOption_HAL_Raw * 1
DumpOption_HAL_Annotated * 2
DumpOption_File_Raw * 4
DumpOption_File_Annotated * 8
DumpOption_Collect * 16 ; Collect but don't report
DumpOptions_Default * 0 ; Default options to use on module init
DumpOptionsStr # 44 ; Big enough for longest string
StringBuffer # 160 ; Temp string buffer. Big enough to
; hold a disassembled instruction
; and a full register set + three instrs
......@@ -620,6 +642,8 @@ Debug_Init Entry
MOV r3, #17
MOV r14, #0
STR r14, MessageFile_Open
STR r14, ROMDebugSymbols
STR r14, ROMBaseAddr
20 STR r14, [r1], #4
SUBS r3, r3, #1
BNE %BT20
......@@ -709,6 +733,31 @@ Debug_Init Entry
;
40
; Find ROM
MOV r0, #ModHandReason_LookupName
ADRL r1, Where_UMod
SWI XOS_Module
BVS %FT42
MOV r4, r3, LSR #20
MOV r4, r4, LSL #20
STR r4, ROMBaseAddr
; Find ROM debug symbols
MOV r0, #15
MOV r1, #0
41
SWI XOS_ReadSysInfo
MOVVS r1, #0
CMP r1, #0
BEQ %FT42
CMP r2, #ExtROMFooter_DebugSymbols
CMPEQ r3, #4
BNE %BT41
LDW r0, r1, r2, r3
ADD r0, r0, r4
STR r0, ROMDebugSymbols
42
; SAR
MOV R3, #0
STR R3, DisOpts
......@@ -719,6 +768,13 @@ Debug_Init Entry
BLVC declareresourcefsfiles
]
MOV R3, #DumpOptions_Default
STR R3, DumpOptions
BLVC ExcDump_CodeVar_Init
[ DumpOptions_Default <> 0
BLVC ExcDump_Init
]
EXIT
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......@@ -776,6 +832,8 @@ Debug_Die Entry
LDR wp, [r12]
BL ExcDump_CodeVar_Shutdown
BL SwapAllBreakpoints ; Be nice
MOV r0, #ExceptionDumpArea ; Restore old exception dump area
......@@ -2273,6 +2331,7 @@ BxTAB DCB "BX", 0
BxjTAB DCB "BXJ",0
ALIGN
AdrTAB DCB "ADR",0
BkptTAB DCB "BKPT",0
ALIGN
......@@ -2570,7 +2629,6 @@ Mul16 ROUT
B InstructionEnd
AdrTAB DCB "ADR",0
MrsTAB DCB "MRS",0
MsrTAB DCB "MSR",0
BlxTAB DCB "BLX",0
......@@ -6370,7 +6428,6 @@ Where_Code Entry "r6-r11"
LDREQB r0, SysIs32bit
TEQEQ r0, #0
BICEQ r7, r7, #ARM_CC_Mask
MOV r8, #0 ; No details
BL message_writes
DCB "M15", 0 ; "Address &"
......@@ -6381,6 +6438,50 @@ Where_Code Entry "r6-r11"
SWIVC XOS_WriteI+space
EXIT VS
BL Where_Util
EXIT VS
CMP r7, #-1
BNE %FT85
; Say "is <somewhere vague>"
BL message_write0
B %FT88
85
; Say "is at offset &xx in <some area> 'detail'"
; => r0 -> area name token
; r7 = offset
; r8 -> detail string
BL message_writes
DCB "M21", 0
ALIGN
MOVVC r10, r7
BLVC DisplayHexWord
SWIVC OS_WriteI+space
BLVC message_write0
TEQ r8, #0 ; NULL details? V preserved
BEQ %FT88
SWIVC OS_WriteI+space
SWIVC OS_WriteI+"'"
MOVVC r0, r8
SWIVC OS_Write0
SWIVC OS_WriteI+"'"
88
SWIVC OS_NewLine
EXIT
; In:
; r7 = address
; Out:
; r0 -> area name token
; r7 = offset
; r8 -> detail string
; offset is -1 if unsure of location
Where_Util ROUT
Entry "r1-r6,r9-r11"
MOV r8, #0 ; No details
; Applications sometimes go pop
MOV r0, #-1
SWI XOS_ReadDynamicArea
......@@ -6467,43 +6568,44 @@ Where_Code Entry "r6-r11"
ADRCS r0, Where_NotMapped ; C set, is not RAM
ADRCC r0, Where_Unknown ; Somewhere, but not sure where
80
; Say "is <somewhere vague>"
BL message_write0
B %FT88
MOV r7, #-1
MOV r8, #0
85
; Say "is at offset &xx in <some area> 'detail'"
; => r0 -> area name token
; r7 = offset
; r8 -> detail string
BL message_writes
DCB "M21", 0
ALIGN
MOVVC r10, r7
BLVC DisplayHexWord
SWIVC OS_WriteI+space
BLVC message_write0
TEQ r8, #0 ; NULL details? V preserved
BEQ %FT88
SWIVC OS_WriteI+space
SWIVC OS_WriteI+"'"
MOVVC r0, r8
SWIVC OS_Write0
SWIVC OS_WriteI+"'"
88
SWIVC OS_NewLine
EXIT
Where_Unknown DCB "M28", 0
Where_NotMapped DCB "M30", 0
Where_ROM DCB "M34", 0
Where_Module DCB "M47", 0
Where_AppSlot DCB "M88", 0
Where_DynArea DCB "M89", 0
Where_Kernel DCB "M95", 0
Where_SysWksp DCB "M96", 0
Where_Unknown DCB "M28", 0 ; vague
Where_NotMapped DCB "M30", 0 ; vague
Where_ROM DCB "M34", 0 ; offset
Where_Module DCB "M47", 0 ; offset+detail
Where_AppSlot DCB "M88", 0 ; offset
Where_DynArea DCB "M89", 0 ; offset+detail
Where_Kernel DCB "M95", 0 ; offset
Where_SysWksp DCB "M96", 0 ; vague
ALIGN
; In:
; r0 = address
; r1 -> result buffer (area name, offset, detail string)
EXPORT Where_Util_FromC
Where_Util_FromC ROUT
Entry "r1,r7,r8,r10"
SUB r12, sl, #:INDEX:CRelocOffset
MOV r7, r0
BL Where_Util
ADDVS r0, r0, #4
MOVVS r7, #-1
MOVVS r8, #0
FRAMLDR r1
BVS %FT50
MOVS r10, r0
BEQ %FT50
BL lookup_r10
ADDVS r10, r0, #4
MOV r0, r10
50
STMIA r1, {r0,r7,r8}
EXIT
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......@@ -6534,5 +6636,6 @@ declareresourcefsfiles
]
GET Thumb.s
GET CodeVar.s
GET ExceptionDump.s
END
This diff is collapsed.
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