Foreword

最近又遇到了一些奇怪的bug,意外发现调试手段上还是有所欠缺,而SES的js脚本可以做更多自定义的工具,可以进一步改造方便疑难杂症使用

Threads Script

需要注意Threads Script用的是Java Script,而不是Jlink Script(前面查了半天发现不对),虽然都简称成了js,但是Jlink Script应该只有Jlink的一些批处理程序才会使用这种方式写脚本

之前有说过SES的RTOS Awareness好像有点问题,老是显示不全,不如Ozone的

貌似这个问题在我提给官方以后修复了

之前有提到显示操作系统线程情况的脚本,这里发现其实这个东西可以自定义的程度还是蛮高的

/*********************************************************************
*               SEGGER MICROCONTROLLER GmbH                          *
*       Solutions for real time microcontroller applications         *
**********************************************************************
*                                                                    *
*       (c) 1995 - 2019  SEGGER Microcontroller GmbH                 *
*                                                                    *
*       www.segger.com     Support: support@segger.com               *
*                                                                    *
**********************************************************************
*                                                                    *
*       Please note:                                                 *
*                                                                    *
*       Knowledge of this file may under no circumstances            *
*       be used to write a similar product                           *
*                                                                    *
*       Thank you for your fairness !                                *
*                                                                    *
**********************************************************************
*                                                                    *
*       Current version number will be inserted here                 *
*       when shipment is built.                                      *
*                                                                    *
**********************************************************************

----------------------------------------------------------------------
File        : FreeRTOSPlugin_CM7.js
Purpose     : Ozone FreeRTOS-awareness JavaScript Plugin for Cortex-M7
---------------------------END-OF-HEADER------------------------------
*/

/*********************************************************************
*
*       Local Functions
*
**********************************************************************
*/

/*********************************************************************
*
*       GetTaskStackGrowDir
*  
* Function description
*   Indicates if the task stack grows in positive (1) or negative (-1) memory direction
*
* Notes
*   (1) The stack grow direction depends on the FreeRTOS-port.
*       Currently, a positive grow direction is only used on the PIC architecture.
*/
function GetTaskStackGrowDir() {    
  return -1;
}

/*********************************************************************
*
*       GetTaskPrioName
*  
* Function description
*   Returns the display text of a task priority
*
* Parameters
*   Priority: task priority (integer)
*/
function GetTaskPrioName(Priority) {
    
  var sName;
  
  if (Priority == 0) {
    sName = "Idle"
  } else if (Priority == 1) {
    sName = "Low"
  } else if (Priority == 2) {
    sName = "Normal";
  } else if (Priority == 3) {
    sName = "High";
  } else if (Priority == 4) {
    sName = "Highest";
  } else {
    return Priority.toString();
  } 
  sName = sName + " (" + Priority + ")";
  return sName;
}

/*********************************************************************
*
*       GetTaskName
*  
* Function description
*   Returns the display text of a task name
*
* Parameters
*   tcb:   task control block (type tskTCB)
*   Addr:  control block memory location
*/
function GetTaskName(tcb, Addr) {
    
   var sTaskName;
   
   sTaskName = Debug.evaluate("(char*)(*(tskTCB*)" + Addr + ").pcTaskName");
   if (sTaskName == undefined) {
     sTaskName = Debug.evaluate("(char*)(*(TCB_t*)" + Addr + ").pcTaskName");
   }
   
   if (tcb.uxTCBNumber != undefined) {
     sTaskName = "#" + tcb.uxTCBNumber + " \"" + sTaskName + "\"";
   }
   return sTaskName;
}

/*********************************************************************
*
*       GetTaskID
*  
* Function description
*   Returns the display text of a task ID
*
* Parameters
*   tcb:   task control block (type tskTCB)
*   Addr:  control block memory location
*/
function GetTaskID(tcb, Addr) { 
   return  "0x" + (tcb.uxTCBNumber == undefined ? Addr.toString(16) : tcb.uxTCBNumber.toString(16));
}

/*********************************************************************
*
*       GetTCB
*  
* Function description
*   Returns the task control block of a task
*
* Parameters
*   Addr: control block memory location
*/
function GetTCB(Addr) { 
  var tcb;
  tcb = Debug.evaluate("*(tskTCB*)" + Addr);
  if (tcb == undefined) {
    tcb = Debug.evaluate("*(TCB_t*)" + Addr);
  }
  return tcb;
}

/*********************************************************************
*
*       GetTaskNotifyStateStr
*  
* Function description
*   Returns the display string of a task notify state
*
* Parameters
*   tcb: task control block (type tskTCB)
*/
function GetTaskNotifyStateStr(tcb) {

   if (tcb.ucNotifyState == undefined) {
     return tcb.eNotifyState == undefined ? "N/A" : tcb.eNotifyState.toString();
   } else {
     return tcb.ucNotifyState.toString()
   }
}

/*********************************************************************
*
*       GetTaskStackInfoStr
*  
* Function description
*   Returns a display text of the format "<free space> / <stack size>"
*
* Parameters
*   tcb: task control block (type tskTCB)
*
* Notes
*   (1) pxEndOfStack is only available when FreeRTOS was compiled with 
*       configRECORD_STACK_HIGH_ADDRESS == 1
*/
function GetTaskStackInfoStr(tcb) {
  var FreeSpace;
  var UsedSpace;
  var Size;
  //                                GrowDir == 0     GrowDir == 1
  //
  // pxStack       |  Low Addr   |  Stack Top     |  Stack Base    |
  //               |             |                |                |
  // pxTopOfStack  |             |  Stack Pointer |  Stack Pointer |       
  //               |             |                |                |
  // pxEndOfStack  |  High Addr  |  Stack Base    |  Stack Top     |
  // 
  if (GetTaskStackGrowDir() == 1) { // stack grows in positive address direction
  
    if (tcb.pxEndOfStack == undefined) {
      UsedSpace  =  tcb.pxTopOfStack - tcb.pxStack;
      FreeSpace  =  undefined;
      Size       =  undefined;  
    } else {
      FreeSpace  =  tcb.pxEndOfStack - tcb.pxTopOfStack;
      UsedSpace  =  tcb.pxTopOfStack - tcb.pxStack;
      Size       =  FreeSpace + UsedSpace;  
    }
  } else {    // stack grows in negative address direction
  
    if (tcb.pxEndOfStack == undefined) {
      FreeSpace  =  tcb.pxTopOfStack - tcb.pxStack;     
      UsedSpace  =  undefined;      
      Size       =  undefined;
    } else {
      FreeSpace  =  tcb.pxTopOfStack - tcb.pxStack;     
      UsedSpace  =  tcb.pxEndOfStack - tcb.pxTopOfStack;      
      Size       =  FreeSpace + UsedSpace;
    }   
  }   
  return FreeSpace + " / " + (Size == undefined ? "N/A" : Size);   
}

function GetLabel1(tcb) {
  var FreeSpace;
  var UsedSpace;
  var Size;
  //                                GrowDir == 0     GrowDir == 1
  //
  // pxStack       |  Low Addr   |  Stack Top     |  Stack Base    |
  //               |             |                |                |
  // pxTopOfStack  |             |  Stack Pointer |  Stack Pointer |       
  //               |             |                |                |
  // pxEndOfStack  |  High Addr  |  Stack Base    |  Stack Top     |
  // 
  if (GetTaskStackGrowDir() == 1) { // stack grows in positive address direction
  
    if (tcb.pxEndOfStack == undefined) {
      UsedSpace  =  tcb.pxTopOfStack - tcb.pxStack;
      FreeSpace  =  undefined;
      Size       =  undefined;  
    } else {
      FreeSpace  =  tcb.pxEndOfStack - tcb.pxTopOfStack;
      UsedSpace  =  tcb.pxTopOfStack - tcb.pxStack;
      Size       =  FreeSpace + UsedSpace;  
    }
  } else {    // stack grows in negative address direction
    // FreeRTOS -1 ,go on here
    if (tcb.pxEndOfStack == undefined) {
      FreeSpace  =  tcb.pxTopOfStack - tcb.pxStack;     
      UsedSpace  =  undefined;      
      Size       =  undefined;
    } else {
      FreeSpace  =  tcb.pxTopOfStack - tcb.pxStack;     
      UsedSpace  =  tcb.pxEndOfStack - tcb.pxTopOfStack;      
      Size       =  FreeSpace + UsedSpace;
    }   
  }   
  return "0x"+tcb.pxTopOfStack.toString(16) + " / " + "0x"+tcb.pxStack.toString(16);   
}

function GetLabel2(addr) {
  return addr.toString(16);   
}

function GetLabel3(param) {
  return param.toString(16);   
}

/*********************************************************************
*
*       AddTask
*  
* Function description
*   Adds a task to the task window
*
* Parameters
*   Addr:            memory location of the task's control block (TCB)
*   CurrTaskAddr:    memory location of the executing task's control block (TCB)
*   sState:          state of the task (e.g. "executing")
*/
function AddTask(Addr, CurrTaskAddr, sState) {
  var tcb;
  var sTaskName; 
  var sPriority;
  var sRunCnt;
  var sMutexCnt;
  var sTimeout;
  var sStackInfo;
  var sID;
  var sNotifiedValue;
  var sNotifyState; 
  var Lable1
  var Lable2
  var Lable3

  tcb            = GetTCB(Addr);
  sTaskName      = GetTaskName(tcb, Addr);
  sID            = GetTaskID(tcb, Addr);
  sStackInfo     = GetTaskStackInfoStr(tcb);
  sPriority      = GetTaskPrioName(tcb.uxPriority);
  sNotifyState   = GetTaskNotifyStateStr(tcb);
  sTimeout       = (tcb.Timeout          == undefined ? "N/A" : tcb.Timeout.toString());
  sRunCnt        = (tcb.ulRunTimeCounter == undefined ? "N/A" : tcb.ulRunTimeCounter.toString());
  sNotifiedValue = (tcb.ulNotifiedValue  == undefined ? "N/A" : tcb.ulNotifiedValue.toString());
  sMutexCnt      = (tcb.uxMutexesHeld    == undefined ? "N/A" : tcb.uxMutexesHeld.toString());

  // custom labels
  Lable1  = GetLabel1(tcb);
  Lable2  = GetLabel2(Addr);
  Lable3  = GetLabel3(0);
 
  if (Addr == CurrTaskAddr) {
    sState = "executing";
  } 
  Threads.add(sTaskName, sRunCnt, sPriority, sState, sTimeout, sStackInfo, sID, sMutexCnt, sNotifiedValue, sNotifyState, Lable1,Lable2,Lable3,(Addr == CurrTaskAddr) ? undefined : Addr);
}

/*********************************************************************
*
*       AddList
*  
* Function description
*   Adds all tasks of a task list to the task window
*
* Parameters
*   List:            task list (type xLIST)
*   CurrTaskAddr:    memory location of the executing task's control block (TCB)
*   sState:          common state of all tasks within 'list'
*/
function AddList(List, CurrTaskAddr, sState) {
  var i;
  var Index;
  var Item;
  var TaskAddr;

  if ((List != undefined) && (List.uxNumberOfItems > 0)) {
      
    Index = List.xListEnd.pxNext;
    
    for (i = 0; i < List.uxNumberOfItems; i++) {
        
      Item = Debug.evaluate("*(xLIST_ITEM*)" + Index);

      TaskAddr = Item != 0 ? Item.pvOwner : 0;

      if (TaskAddr != 0) {
        AddTask(TaskAddr, CurrTaskAddr, sState);
      }
      Index = Item.pxNext;

      if (i > 1000) { // infinite loop guard
        break;
      }
    }
  }
}

/*********************************************************************
*
*       API Functions
*
**********************************************************************
*/

/*********************************************************************
*
*       init
*  
* Function description
*   Initializes the task window
*/
function init() {
    
  Threads.clear();
  Threads.newqueue("Task List");
  Threads.setColumns("Name", "Run Count", "Priority", "Status", "Timeout", "Stack Info", "ID", "Mutex Count", "Notified Value", "Notify State","Lable1","Lable2","Lable3");
  Threads.setColor("Status", "ready", "executing", "blocked");
}

/*********************************************************************
*
*       update
*  
* Function description
*   Updates the task window
*/
function update() {
  var i;
  var pList;
  var List;
  var MaxPriority;
  var CurrTaskAddr;

  Threads.clear();

  if((Debug.evaluate("pxCurrentTCB") == 0) || (Debug.evaluate("pxCurrentTCB") == undefined)) {
    return;
  }
  MaxPriority  = Debug.evaluate("uxTopReadyPriority");  
  CurrTaskAddr = Debug.evaluate("pxCurrentTCB");

  for (i = MaxPriority; i >= 0; i--) {
    List = Debug.evaluate("pxReadyTasksLists[" + i + "]");
    AddList(List, CurrTaskAddr, "ready");
  }

  pList = Debug.evaluate("pxDelayedTaskList");
  if (pList != 0) {
    List = Debug.evaluate("*(xLIST*)" + pList);
    AddList(List, CurrTaskAddr, "blocked");
  }

  pList = Debug.evaluate("pxOverflowDelayedTaskList");
  if (pList != 0) {
    List = Debug.evaluate("*(xLIST*)" + pList);
    AddList(List, CurrTaskAddr, "blocked");
  }

  List = Debug.evaluate("xSuspendedTaskList");
  if (List != 0) {
    AddList(List, CurrTaskAddr, "suspended");
  } 
}

/*********************************************************************
*
*       getregs
*
* Function description
*   Returns the register set of a task.
*   For ARM cores, this function is expected to return the values
*   of registers R0 to R15 and PSR.
*
* Parameters
*   hTask: integer number identifiying the task.
*   Identical to the last parameter supplied to method Threads.add.
*   For convenience, this should be the address of the TCB.
*
* Return Values
*   An array of unsigned integers containing the tasks register values.
*   The array must be sorted according to the logical indexes of the regs.
*   The logical register indexing scheme is defined by the ELF-DWARF ABI.
*
**********************************************************************
*/
function getregs(hTask) { 
  var i;
  var SP;
  var LR;
  var Addr;
  var tcb;
  var aRegs = new Array(17);

  tcb  =  GetTCB(hTask);
  SP   =  tcb.pxTopOfStack;
  Addr =  SP;
  
  /* the following registers are pushed by the FreeRTOS-scheduler */
  //
  // R4...R11
  //
  for (i = 4; i < 12; i++) {
    aRegs[i] = TargetInterface.peekWord(Addr); 
    Addr += 4;
  }
  //
  // EXEC_RET
  //
  LR = TargetInterface.peekWord(Addr);
  Addr += 4;
  //
  // S16...S31
  //
  if ((LR & 0x10) != 0x10) { // FP context has been saved?
    Addr += 4*16; // skip S16..S31
  }
  /* the following registers are pushed by the ARM core */
  //
  // R0...R3
  //
  for (i = 0; i < 4; i++) {
    aRegs[i] = TargetInterface.peekWord(Addr);  
    Addr += 4;
  }
  //
  // R12, LR, PC, PSR
  //
  aRegs[12] = TargetInterface.peekWord(Addr); 
  Addr += 4;
  aRegs[14] = TargetInterface.peekWord(Addr);  
  Addr += 4;
  aRegs[15] = TargetInterface.peekWord(Addr); 
  Addr += 4;
  aRegs[16] = TargetInterface.peekWord(Addr); 
  Addr += 4;
  //
  // S0..S15
  //
  if ((LR & 0x10) != 0x10) { // FP context has been saved?
    Addr += 4*18; // skip S0...S15
  }
  if (aRegs[16] & (1<<9)) { // Stack has been 8-byte aligned
    Addr += 4;
  }
  //
  // SP
  //
  aRegs[13] = Addr;
  
  return aRegs;
}

/*********************************************************************
*
*       getContextSwitchAddrs
*
*  Functions description
*    Returns an unsigned integer array containing the base addresses 
*    of all functions that complete a task switch when executed.
*/
function getContextSwitchAddrs() {
  
  var aAddrs;
  var Addr;
  
  Addr = Debug.evaluate("&vTaskSwitchContext");
  
  if (Addr != undefined) {
    aAddrs = new Array(1);
    aAddrs[0] = Addr;
    return aAddrs;
  } 
  return [];
}

/*********************************************************************
*
*       getOSName()
*
*  Functions description:
*    Returns the name of the RTOS this script supplies support for
*/
function getOSName() {
  return "FreeRTOS";
}

这里主要是增加了三个标签的显示

可以显示栈的起始指针和当前指针位置、TCB指针位置,还多了一个标签待定,随便定义显示什么

整个脚本里主要显示的表格是Threads,只要在它里面去加内容就行了

function init() {
    
  Threads.clear();
  Threads.newqueue("Task List");
  Threads.setColumns("Name", "Run Count", "Priority", "Status", "Timeout", "Stack Info", "ID", "Mutex Count", "Notified Value", "Notify State","Lable1","Lable2","Lable3");
  Threads.setColor("Status", "ready", "executing", "blocked");
}

剩下显示具体变量也好,还是什么其他东西也好,都可以使用这个函数来完成

Debug.evaluate("pxCurrentTCB")

他会把对应的变量转成实际的内容返回

如果要调试某个函数,还可以通过这种方式来获取到具体的函数名称

Debug.getfunction(address)

如果相加额外的表格列,对应加上一个数字即可

function init()
{
  ...
  Threads.setColumns2("Timers", "Id(Timers)", "Name", "Hook", "Timeout", "Period", "Active");
function update()
{
  ...
  Threads.add2("Timers", "0x1FF0A30", "MyTimer", "0x46C8 (Timer50)", "50(550)", "50", "1");

每次更新脚本以后只需要Reload一下,就可以直接加载允许了,不需要断开jlink重连什么的,还是非常方便的

特别是如果遇到踩内存或者需要遍历各个队列什么的,就可以用js脚本直接写一个然后输出到外部框里就行了

其他

虽然官方文档里有Echo,类似console.log,但是试了一下在js这里写这个内容是完全无效的,可以正常执行,但是结果不知道输出到哪里去了

WScript.Echo(s) 

这个小插件的报错有点不友好,很容易看不出来具体错误是什么,要怎么改

而又缺少对这个小插件调试的手段,只能一遍遍试着跑,有点蛋疼

Summary

好用的脚本还是得多积累积累,下次遇到问题才能派上用场

Quote

https://studio.segger.com/index.htm?https://studio.segger.com/ide_debug_expressions.htm