Vxworks中的tt命令源代码分析
吴学军
目录
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
* 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
* 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返回调用参数的个数