Using snapshots

From SEGGER Wiki
Jump to: navigation, search


Overview

Ozone Debug Snapshots (snapshots for short) are a new feature of Ozone, introduced in version 2.63. Snapshots allow saving of the entire system state.

This includes:

  • RAM
  • Flash
  • CPU registers
  • Selected Peripherals
  • Timeline
  • Code Profile (Execution Counters)
  • Data Graphs
  • Power Graphs
  • Terminal Log
  • Console Log

After loading a snapshot, all debug windows show the same information they did (or would have, had they been visible) at the time the snapshot has been created. This includes the call stack, symbol, task, memory and register windows.

Advanced target state, such as clock, IRQ and peripheral configurations, can be precisely restored from a snapshot. This means that even complex multi-tasking programs and programs with peripheral IO can be resumed from the snapshot point.

Snapshots can be loaded and observed in target-offline mode. This means that no hardware is required to load a snapshot, not even a J-Link or J-Trace.

Use Cases

Typical use cases of snapshots are:

  • Snapshots allow customers to break away from a debug session with the ability to resume the session at a later point in time.
  • Snapshots allow easier reproduction and analysis of bugs, possibly by multiple parties on different Host-PCs.
  • Snapshots enhance Ozone's teaching and demonstration capabilities in training sessions and conferences.
  • Snapshots as an archiving media.

Supported Architectures

Snapshots are currently supported on the following architectures:

  • Cortex-M

Saving Snapshots

The snapshot dialog allows users to define what data will be saved to the snapshot. In particular, the dialog provides two sub-dialogs that allow to define what components of the system state, i.e. which memory regions, CPU, floating-point and peripheral registers, are to be saved. The dialog can be accessed from the debug menu or by executing command Debug.SaveSnapshot

SnapshotSave.png

The default configuration of the register selection dialog, and thus the default set of target registers stored to snapshots, are:

  • all basic CPU registers, including FP registers.

The default configuration of the memory selection dialog, and thus the default set of target memory regions stored to snapshots, are:

  • all FLASH and RAM region defined for the target within the MCU database of the J-Link API.
  • all ELF program data sections with the allocatable flag (A) set.

These default configurations can be restored by clicking on button Restore Defaults. Button Import allows to add memory regions from a SEGGER Embedded Studio memory map file. Button Save to Project makes the current configuration persistent by storing it to the user file of the project (jdebug.user). Snapshots are compressed using SEGGER's emCompress software library. The disk format is documented internally.

Loading Snapshots

The load snapshot dialog can be accessed from the debug menu or by executing command Debug.LoadSnapshot.

SnapshotLoad.png

When a snapshot is loaded, registers and memory regions are restored in the order they appear within the snapshot. This order is identical to the order displayed by the memory- and register selection dialogs. There is a peculiarity when loading snapshots in target-online mode: any non-basic CPU register is not immediately written to the target. Instead, the user must program the specific way in which system, peripheral and memory-mapped registers are to be applied to target, as explained below.

In order for the restored debug session to be in a consistent state, it is required that:

  • the target device of the snapshot matches the current target device.
  • the loaded program image binary-matches the program image at the time the snapshot was taken.
  • all system state configured by the debuggee, such as IRQs and timers, is memory-mapped and has been restored correctly from the snapshot.
  • the list of graphed expressions matches the list of expressions at the time the snapshot was taken.

A warnings dialog will be shown when any of the above conditions does not apply:

DebugSnapshotWarningsDialog.png

Restoring Advanced System State

In order to restore advanced system state, such as (clocked) peripherals from a snapshot, it is generally necessary for users to program the exact sequence of restore operations. To support this, Ozone provides the script functions OnSnapshotSave and OnSnapshotLoad and a command group Snapshot tailored to reading and writing to/from snapshot files.

The following script example restores the system state of an embOS blinky debuggee on a SEGGER Cortex-M trace reference board when the snapshot is loaded:

/*********************************************************************
*                                                                     
*       OnSnapshotSave                                                
*                                                                     
* Function description                                                
*   Optional event handler, called upon saving a snapshot.            
*                                                                     
* Additional information                                              
*    This function is usually used to save values of the target       
*    state which can either not be trivially read,                    
*    or need to be restored in a specific way or order.               
*    Typically use: Memory Mapped Registers,                          
*    such as PLL and GPIO configuration.                              
*                                                                     
**********************************************************************
*/ 
void OnSnapshotSave (void) {

  Util.Log("OnSnapshotSave: saving system state..."); 
  //
  // Save Cortex-M specific system state
  //
  Snapshot.SaveReg("CPU.Peripherals.SCB.VTOR");      // Vector table offset register
  Snapshot.SaveReg("CPU.Peripherals.DWT.DWT_CTRL");  // DWT unit status & control register (SYSTEMVIEW)
  Snapshot.SaveReg("CPU.Peripherals.SYSTICK");       // System timer configuration (SYSTICK)
  Snapshot.SaveReg("CPU.Peripherals.SCB.SHPR3");     // Cortex-M IRQ priorties 12-15 (SYSTICK)
  Snapshot.SaveReg("CPU.Peripherals.SCB.CPACR");     // FPU and coprocessor control register
  //
  // Save system clock configuration
  //
  Snapshot.SaveReg("Peripherals.RCC.CR");
  Snapshot.SaveReg("Peripherals.RCC.CFGR");
  Snapshot.SaveReg("Peripherals.RCC.PLLCFGR");
  //
  // Save FLASH configuration
  //
  Snapshot.SaveReg("Peripherals.FLASH.ACR");
  //
  // Save LED configuration
  //
  Snapshot.SaveReg("Peripherals.RCC.AHB1RSTR");     // LED port reset register
  Snapshot.SaveReg("Peripherals.RCC.AHB1ENR");      // LED port clock enable register
  Snapshot.SaveReg("Peripherals.GPIO.GPIOA.MODER"); // LED port mode register
  Snapshot.SaveReg("Peripherals.GPIO.GPIOA.ODR");   // LED port output data register
  //
  // Power configuration
  //
  Snapshot.SaveReg("Peripherals.PWR.CR");
  //
  // APB1 clock
  //
  Snapshot.SaveReg("Peripherals.RCC.APB1ENR"); 
  
  Util.Log("OnSnapshotSave: system state saved."); 
}
                                                              
/*********************************************************************
*                                                                     
*       OnSnapshotLoad                                                
*                                                                     
* Function description                                                
*   Optional event handler, called upon loading a snapshot.           
*                                                                     
* Additional information                                              
*   This function is used to restore the target state in cases        
*   where values cannot simply be written to the target.              
*   Typical use: GPIO clock needs to be enabled, before               
*   GPIO is configured.                                               
*                                                                     
**********************************************************************
*/                                                                     
void OnSnapshotLoad (void) {   

  Util.Log("OnSnapshotLoad: restoring system state...");
  
  if (SNAPSHOT_Restore_System_Generic() != 0) {
     Util.Log("OnSnapshotLoad : failed to restore generic system state");
     return 0;
  }
  if (SNAPSHOT_Restore_SysClock() != 0) {
     Util.Log("OnSnapshotLoad : failed to resore clock-specific system state");
     return 0;
  }
  if (SNAPSHOT_Restore_OS() != 0) {
     Util.Log("OnSnapshotLoad : failed to restore OS-specific system state");
     return 0;
  }
  if (SNAPSHOT_Restore_Board() != 0) {
     Util.Log("OnSnapshotLoad : failed to restore board-specific system state");
     return 0;
  }
  Util.Log("OnSnapshotLoad: system state restored.");
}
    
/*********************************************************************
*                                                                     
*       SNAPSHOT_Restore_System_Generic                     
*                                                                     
* Function description                                                
*   Loads and applies generic system state from a snapshot
*
* Return Value
*   0:  OK
*  -1:  error
*
* Notes
*    (1) User function
*                                                                     
**********************************************************************
*/                                                                    
int SNAPSHOT_Restore_System_Generic() {
   //
   // Restore CPACR
   //
   Snapshot.LoadReg("CPU.Peripherals.SCB.CPACR");
   //
   // Restore vector base address
   //
   Snapshot.LoadReg("CPU.Peripherals.SCB.VTOR");

   return 0;
}
    
/*********************************************************************
*                                                                     
*       SNAPSHOT_Restore_SysClock                        
*                                                                     
* Function description                                                
*   Loads and applies a HSE clock configuration from a snapshot
*
* Return Value
*   0:  OK
*  -1:  timeout while configuring PLL
*
* Notes
*    (1) User function
*                                                                     
**********************************************************************
*/                                                                    
int SNAPSHOT_Restore_SysClock(void) { 

   unsigned int  HSE_STARTUP_TIMEOUT;
   unsigned int  RCC_CR_HSEON;
   unsigned int  RCC_CR_HSERDY;
   unsigned int  RCC_CR_PLLON;
   unsigned int  RCC_CR_PLLRDY;
   unsigned int  RCC_CFGR_SW;
   unsigned int  RCC_CFGR_SW_PLL;
   unsigned int  RCC_CFGR_SWS;
   unsigned int  RCC_CFGR_SWS_HSE;
   unsigned int  RCC_CFGR_SWS_PLL;
   unsigned int  HSEStatus;
   unsigned int  Locked;
   unsigned int  StartUpCounter;
   
   HSE_STARTUP_TIMEOUT  =  500;
   RCC_CR_HSEON         =  0x00010000;
   RCC_CR_HSERDY        =  0x00020000;
   RCC_CR_PLLON         =  0x01000000;
   RCC_CR_PLLRDY        =  0x02000000;
   RCC_CFGR_SWS         =  0x0000000C;
   RCC_CFGR_SW_PLL      =  0x00000002;
   RCC_CFGR_SW          =  0x00000003;
   RCC_CFGR_SWS_HSE     =  0x00000004;
   RCC_CFGR_SWS_PLL     =  0x00000008;
   HSEStatus            =  0;
   StartUpCounter       =  0;
   Locked               =  0;
   //
   // Reset RCC clock configuration
   //
   SetRegBits     ("Peripherals.RCC.CR",      0x00000001); // Set HSION bit
   Target.SetReg  ("Peripherals.RCC.CFGR",    0x00000000); // Reset CFGR register
   ClearRegBits   ("Peripherals.RCC.CR",      0x01090000); // Reset HSEON, CSSON and PLLON bits
   Target.SetReg  ("Peripherals.RCC.PLLCFGR", 0x24003010); // Reset PLLCFGR register
   ClearRegBits   ("Peripherals.RCC.CR",      0x00040000); // Reset HSEBYP bit
   
   if ((Snapshot.ReadReg("Peripherals.RCC.CR") & 0x00010000) == 0) { // HSEON clear ?
     return 0; // snapshot session ran on reset clock (HSI)
   }
   //
   // Disable all interrupts
   //
   Target.SetReg("Peripherals.RCC.CIR", 0x24003010);
   //
   // Enable the HSE  
   //
   SetRegBits("Peripherals.RCC.CR", RCC_CR_HSEON);
   //
   // Wait till the HSE is ready
   //
   do {
      HSEStatus = (Target.GetReg("Peripherals.RCC.CR") & RCC_CR_HSERDY);
      StartUpCounter = StartUpCounter + 1;
   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
   //
   // Early out when timeout was reached
   //
   if ((Target.GetReg("Peripherals.RCC.CR") & RCC_CR_HSERDY) == 0) {return -1;}
   //
   // Restore peripheral clock enable
   //
   Snapshot.LoadReg("Peripherals.RCC.APB1ENR");
   //
   // Restore regulator voltage output mode
   //
   Snapshot.LoadReg("Peripherals.PWR.CR");
   //
   // Restore the clock dividers
   //
   SetRegBits("Peripherals.RCC.CFGR", Snapshot.ReadReg("Peripherals.RCC.CFGR") & 0xF0);
   //
   // Restore the PLL parameters
   //
   Snapshot.LoadReg("Peripherals.RCC.PLLCFGR");
   //
   // Enable the PLL
   //
   SetRegBits("Peripherals.RCC.CR", RCC_CR_PLLON);
   //
   // Wait till the PLL is ready
   //
   while((Target.GetReg("Peripherals.RCC.CR") & RCC_CR_PLLRDY) == 0) {}
   //
   // Restore Flash prefetch, Instruction cache, Data cache and wait state
   //
   Snapshot.LoadReg("Peripherals.FLASH.ACR");
   //
   // Select the PLL as system clock source
   //
   ClearRegBits ("Peripherals.RCC.CFGR", RCC_CFGR_SW);
   SetRegBits   ("Peripherals.RCC.CFGR", RCC_CFGR_SW_PLL);
   //
   // Wait till the PLL is used as system clock source */
   // 
   StartUpCounter = 0;
   do {
     Locked = ((Target.GetReg("Peripherals.RCC.CFGR") & RCC_CFGR_SWS) == RCC_CFGR_SWS_PLL);
     StartUpCounter = StartUpCounter + 1;
   } while ((Locked == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
   
   return 0;
}
    
/*********************************************************************
*                                                                     
*       SNAPSHOT_Restore_OS                         
*                                                                     
* Function description                                                
*   Loads and applies an RTOS system state from a snapshot
*
* Return Value
*   0:  OK
*  -1:  error
*
* Notes
*    (1) User function
*                                                                     
**********************************************************************
*/                                                                    
int SNAPSHOT_Restore_OS() {

   unsigned int  NOCYCCNT_BIT;
   unsigned int  RegVal;
   
   NOCYCCNT_BIT = (1 << 25);
   RegVal = 0;
   //
   // Restore system timer configuration
   //
   Snapshot.LoadReg("CPU.Peripherals.SYSTICK.SYST_RVR");  // Set reload register
   Snapshot.LoadReg("CPU.Peripherals.SCB.SHPR3");         // Set Priority for Systick Interrupt
   Snapshot.LoadReg("CPU.Peripherals.SYSTICK.SYST_CVR");  // Set the SysTick Counter Value
   Snapshot.LoadReg("CPU.Peripherals.SYSTICK.SYST_CSR");  // Enable SysTick IRQ and SysTick Timer 
   //
   //  Restore the cycle counter for SystemView functions
   //
   RegVal = Snapshot.ReadReg("CPU.Peripherals.DWT.DWT_CTRL");
  
   if ((RegVal & NOCYCCNT_BIT) == 0) { // Cycle counter supported?
     Target.SetReg("CPU.Peripherals.DWT.DWT_CTRL", RegVal);
   }
   return 0;
}
    
/*********************************************************************
*                                                                     
*       SNAPSHOT_Restore_Board                       
*                                                                     
* Function description                                                
*   Loads and applies a BSP state from a snapshot
*
* Return Value
*   0:  OK
*  -1:  error
*
* Notes
*    (1) User function
*                                                                     
**********************************************************************
*/                                                                    
int SNAPSHOT_Restore_Board() {
  
  unsigned int LEDPORT_RCC_BIT;
  
  LEDPORT_RCC_BIT = 0x00000001;
 
  ClearRegBits ("Peripherals.RCC.AHB1ENR",  LEDPORT_RCC_BIT);  // De-clock LED port
  ClearRegBits ("Peripherals.RCC.AHB1RSTR", LEDPORT_RCC_BIT);  // Reset LED port
  SetRegBits   ("Peripherals.RCC.AHB1ENR",  LEDPORT_RCC_BIT);  // Clock LED port
  //
  // Restore LED port state
  //
  Snapshot.LoadReg("Peripherals.GPIO.GPIOA.MODER"); // restore port modes
  Snapshot.LoadReg("Peripherals.GPIO.GPIOA.ODR");   // restore port states    
  
  return 0;
}
    
/*********************************************************************
*                                                                     
*       SetRegBits             
*                                                                     
* Function description                                                
*   Sets all masked bits to 1
*
* Notes
*    (1) User function
*                                                                     
**********************************************************************
*/                                                                    
void SetRegBits(const char* sReg, unsigned int Mask) {
  
  unsigned int Value;
  Value = Target.GetReg(sReg);
  Value |= Mask;
  Target.SetReg(sReg, Value);
}
    
/*********************************************************************
*                                                                     
*       ClearRegBits             
*                                                                     
* Function description                                                
*   Sets all masked bits to 0
*
* Notes
*    (1) User function
*                                                                     
**********************************************************************
*/                                                                    
void ClearRegBits(const char* sReg, unsigned int Mask) {
 
  unsigned int Value;
  Value = Target.GetReg(sReg);
  Value &= ~Mask;
  Target.SetReg(sReg, Value);
}

The snapshot scripting facility currently targets the system register state only. CPU registers and memory data is automatically written to target when a snapshot is loaded in online mode, irrespective of the presence of script functions OnSnapshotLoad and OnSnapshotSave.

Snapshot Debugger Commands

The following debugger commands can be employed within project script functions OnSnapshotLoad and OnSnapshotSave to access/restore snapshot file data. All of the below commands are also documented in the appendix of the Ozone user guide.

The following properties apply:

  • For register name arguments, any register displayed within the register window can be specified, using its qualified SVD tree path name, such as Core.CPU.SP or Peripherals.GPIO.GPIOA.MODER
  • When a register group was stored to the snapshot, each group register can be accessed individually.
  • When a register group is loaded to the target, registers are written piece-wise.
Command Description
Snapshot.SaveReg(const char* sReg) Saves a register (group) to a snapshot
Snapshot.SaveU32(U64 Addr, U32 Value) Saves a memory value to a snapshot
Snapshot.ReadReg(const char* sReg) Reads a register from a snapshot
Snapshot.ReadU32(U64 Addr) Reads a memory value from a snapshot
Snapshot.LoadReg(const char* sReg) Reads a register (group) from a snapshot and writes it to target
Snapshot.LoadU32(U64 Addr) Reads a memory value from a snapshot and writes it to target
Register.Addr(const char* sReg) Gets the memory address of a memory-mapped register
Target.WriteU32(U64 Addr, U32 Value) Writes a 32 bit value to target memory
Target.ReadU32(U64 Addr) Reads a 32 bit value from target memory
Target.SetReg(const char* sReg, U64 Value) Writes a CPU or system register
Target.GetReg(const char* sReg) Reads a CPU or system register

The Scope of Snapshots

Snapshot store binary debug session data which cannot be easily or efficiently stored in a user-readable format. Snapshots do not replace any of Ozone's existing textual configuration facilities. in particular, snapshots do not store nor replace:

  • Basic project settings such as Project.SetDevice
  • Any setting which can be specified using a debugger command, such as Target.PowerOn
  • Settings stored to Ozone user files, such as breakpoints and open documents.
  • User preferences and GUI settings.