Vxworks中的tt命令源代碼分析
吳學軍
<[email protected]>
目錄
tt實現的函數說明
具體實現分析
trcStack函數分析
trcStackLvl分析
tt實現的函數說明
* tt - display a stack trace of a task
*
* This routine displays a list of the nested routine calls that the specified
* task is in. Each routine call and its parameters are shown.
*
* If <taskNameOrId> is not specified or zero, the last task referenced is
* assumed. The tt() routine can only trace the stack of a task other than
* itself. For instance, when tt() is called from the shell, it cannot trace
* the shell's stack.
*
* EXAMPLE
* .CS
* -> tt "logTask"
* 3ab92 _vxTaskEntry +10 : _logTask (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
* ee6e _logTask +12 : _read (5, 3f8a10, 20)
* d460 _read +10 : _iosRead (5, 3f8a10, 20)
* e234 _iosRead +9c : _pipeRead (3fce1c, 3f8a10, 20)
* 23978 _pipeRead +24 : _semTake (3f8b78)
* value = 0 = 0x0
* .CE
* This indicates that logTask() is currently in semTake() (with
* one parameter) and was called by pipeRead() (with three parameters),
* which was called by iosRead() (with three parameters), and so on.
*
* INTERNAL
* This higher-level symbolic stack trace is built on top of the
* lower-level routines provided by trcLib.
*
* CAVEAT
* In order to do the trace, some assumptions are made. In general, the
* trace will work for all C language routines and for assembly language
* routines that start with a LINK instruction. Some C compilers require
* specific flags to generate the LINK first. Most VxWorks assembly language
* routines include LINK instructions for this reason. The trace facility
* may produce inaccurate results or fail completely if the routine is
* written in a language other than C, the routine's entry point is
* non-standard, or the task's stack is corrupted. Also, all parameters are
* assumed to be 32-bit quantities, so structures passed as parameters will
* be displayed as f2longfP integers.
*
* RETURNS:
* OK, or ERROR if the task does not exist.
通過以上可以首先學習到
tt不能顯示其自身任務的調用棧
tt的調用基於trcLib實現
tt的實現基於一些假設:
所tt的routines必須由C或者由LINK指令開始的彙編語言實現,則tt執行的結果會不準確或失敗,同時,如果函數的入口點不標準或任務棧已經被破壞的情況下也會出現同樣結果;(破壞了當然看不了了,~~~)
所有參數假定爲32位的
具體實現分析
STATUS tt(int taskNameOrId )
{
REG_SET regSet;
BOOL resumeIt = FALSE;
int tid = taskIdFigure (taskNameOrId);
{
ULONG sr;
INSTR *pc;
_RType lo;
_RType hi;
_RType gpreg[32];
ULONG cause;
ULONG fpcsr;
} REG_SET;
x86架構的寄存器組具體實現如下:
typedef struct
{
ULONG edi;
ULONG esi;
ULONG ebp;
ULONG esp;
ULONG ebx;
ULONG edx;
ULONG ecx;
ULONG eax;
ULONG eflags;
INSTR *pc;
ULONG intLockKey;
CONTEXT windowsContext;
} REG_SET;
函數taskIdFigure的作用是 translate a task name or ID to a task ID在t21mips的 target/src/usr/usrlib.c中實現;
if (tid == ERROR)
{
printErr (DBG_TASK_NOT_FOUND);
return (ERROR);
}
tid = taskIdDefault (tid);
)
{
static int defaultTaskId;
if (tid != 0)
defaultTaskId = tid;
return (defaultTaskId);
}
*/
if (tid == taskIdSelf () || tid == 0)
{
printErr ("Sorry, traces of my own stack begin at tt ().n");
return (ERROR);
}
if (taskIdVerify (tid) != OK)
{
printErr ("Can't trace task %#x: invalid task id.n", tid);
return (ERROR);
}
if (!taskIsSuspended (tid))
{
resumeIt = TRUE;
taskSuspend (tid);
}
taskRegsGet (tid, ®Set);
trcStack (®Set, (FUNCPTR) dbgPrintCall, tid);
if (resumeIt)
taskResume (tid);
return (OK);
}
trcStack函數分析
int funcAdrs,
int nargs,
UINT32 * args
)
繼續
* If <printRtn> is NULL, a default routine will be used that prints out just
* the call address, the function address, and the arguments as hexadecimal
* values.
*
* CAVEAT
* In order to do the trace, a number of assumptions are made. In general,
* the trace will work for all C language routines and for assembly language
* routines that start with an PUSH %EBP MOV %ESP %EBP instruction. Most
* VxWorks assembly language routines include PUSH %EBP MOV %ESP %EBP
* instructions for exactly this reason.
* However, routines written in other languages, strange entries into
* routines, or tasks with corrupted stacks can confuse the trace. Also,
* all parameters are assumed to be 32-bit quantities, therefore structures
* passed as parameters will be displayed as a number of long integers.
*
* EXAMPLE
* The following sequence can be used
* to trace a VxWorks task given a pointer to the task's TCB:
* .CS
* REG_SET regSet; /@ task's data registers @/
*
* taskRegsGet (taskId, ®Set);
* trcStack (®Set, (FUNCPTR)printRtn, tid);
* .CE
*
* SEE ALSO: tt()
*
* NOMANUAL
*/
*/
int val;
SYM_TYPE type;
INSTR * addr;
int stackSave;
char * pName = NULL;
INSTR * pc = pRegSet->pc;
int * fp = (int *)pRegSet->fpReg;
int * sp = (int *)pRegSet->spReg;
if (printRtn == NULL)
printRtn = (FUNCPTR)trcDefaultPrint;
addr = trcFollowJmp (pc);
if ((DSM(addr, PUSH_EBP, PUSH_EBP_MASK) &&
DSM(addr+1, MOV_ESP0, MOV_ESP0_MASK) &&
DSM(addr+2, MOV_ESP1, MOV_ESP1_MASK)) ||
(DSM(addr, ENTER, ENTER_MASK)) ||
(DSM(addr, RET, RET_MASK)) ||
(DSM(addr, RETADD, RETADD_MASK)) ||
((sysSymTbl != NULL) &&
(symByValueFind (sysSymTbl, (UINT) pc, &pName, &val, &type) == OK) &&
(val == (int) pc)))
{
stackSave = *(sp - 1);
*(sp - 1) = (int)fp;
fp = sp - 1;
trcStackLvl (fp, pc, 0, printRtn);
*(sp - 1) = stackSave;
}
else if ((DSM(addr-1, PUSH_EBP, PUSH_EBP_MASK) &&
DSM(addr, MOV_ESP0, MOV_ESP0_MASK) &&
DSM(addr+1, MOV_ESP1, MOV_ESP1_MASK)))
{
fp = sp;
trcStackLvl (fp, pc, 0, printRtn);
}
else
{
trcStackLvl (fp, pc, 0, printRtn);
}
if (pName != NULL)
{
free (pName);
}
trcStackLvl分析
該函數是一個遞歸函數,被每一級嵌套函數調用所調用來打印任務堆棧;最大嵌套深度爲40,首次調用從0開始(第三個參數),具體實現如下:
if (fp == NULL)
return;
returnAdrs = (INSTR *) *(fp + 1);
if (((void *)*fp != NULL) && (depth < MAX_TRACE_DEPTH))
{
trcStackLvl ((int *) *fp, returnAdrs, depth + 1, printRtn);
}
(* printRtn) (trcFindCall (returnAdrs), trcFindFuncStart (fp, pc),
trcCountArgs (returnAdrs), fp + 2);
其中
函數trcFindCall返回當前子函數被調用的地址(尋找CALL指令)
函數trcFindFuncStart尋找函數開始的地址並返回
函數trcCountArgs返回調用參數的個數