通过Python+CRemoteAPI控制Trace32进行调试
关键词:Python、C Remote API、Trace32等等。
当需要对Trace32调试进行自动化,或者提高效率时,可以通过Remote Control API进行。
基本的调试流程如下:
Python、C等语言可以通过调用C Remote API库文件,和Trace32 PowerView基于Socket通信,进行Trace32调试工作。模拟了Trace32 PowerView下的操作。
1 配置Trace32支持Socket Remote Control
1. 修改C:\T32\config.t32文件,增加两个空白行。
2. 在Trace32 Start中找到一个连接,选择PowerView Instance->Advanced Settings->Interfaces->API Port->Use Port选择Yes。
3. 在T32的temp指定目录里,查看T32_xxxxxx.t32,出现了API访问相关配置:
参考《API for Remote Control and JTAG Access》的Preparing Trace32 Software。
2 Remote Control API
2.1 API内容
API包含两个C文件,一个头文件:
- hlinknet.c-处理跟Trace32调试软件的Socket接口工作。
- hremote.c-API接口函数的实现。
- t32.h-API文件件。
2.2 编写基于Remote Control API接口的C程序
包含头文件t32.h,将库连接到可执行文件中即可。
如果需要记录API函数调用轨迹,在编译时需要打开ENABLE_APILOG,增加
-DENABLE_APILOG
在运行时,增加环境变量:
set T32APILOGFILE=C:\temp\t32apilog.txt
则会将调用函数轨迹输出到log文件中。
更多参考:C:\T32\demo\api\capi\test。
2.3 API列表
t32.h中包含了所有API函数:
T32EXTERN int T32_Errno; T32EXTERN int T32_Config(const char *String1, const char *String2); T32EXTERN int T32_Init(void); T32EXTERN int T32_Attach(int DeviceSpecifier); T32EXTERN int T32_Terminate(int ShellReturnValue); T32EXTERN int T32_Exit(void); T32EXTERN int T32_Ping(void); T32EXTERN int T32_Nop(void); T32EXTERN int T32_NopEx(int length, int options); T32EXTERN int T32_NopFail(void); T32EXTERN int T32_Cmd(const char *Command); T32EXTERN int T32_Cmd_f(const char *command, ...) ATTRIBUTE_PRINTF(1, 2); T32EXTERN int T32_CmdWin(uint32_t WindowHandle, const char *Command); T32EXTERN int T32_Printf(const char *str, ...) ATTRIBUTE_PRINTF(1, 2); T32EXTERN int T32_Stop(void); T32EXTERN int T32_GetPracticeState(int *pPracticeState); T32EXTERN int T32_EvalGet(uint32_t *pEvaluationResult); T32EXTERN int T32_EvalGetString(char *EvaluationString); T32EXTERN int T32_GetMessage(char *AreaMessage, uint16_t *pMessageType); T32EXTERN int T32_GetTriggerMessage(char *TriggerMessage); T32EXTERN int T32_GetChannelSize(void); T32EXTERN void T32_GetChannelDefaults(void *ParametersOut); T32EXTERN void T32_SetChannel(void *ParametersIn); T32EXTERN int T32_APILock(int nTimeoutMS); /* preliminary*/ T32EXTERN int T32_APIUnlock(void); T32EXTERN int T32_GetApiRevision(uint32_t* pRevNum); T32EXTERN void T32_GetSocketHandle(int *t32soc); T32EXTERN int T32_Go(void); T32EXTERN int T32_Break(void); T32EXTERN int T32_Step(void); T32EXTERN int T32_StepMode(int Mode); T32EXTERN int T32_ResetCPU(void); T32EXTERN int T32_SetMode(int Mode); T32EXTERN int T32_GetCpuInfo(char **pCPUString, uint16_t *pFPUType, uint16_t *pEndianess, uint16_t *pReserved); T32EXTERN int T32_GetState(int *pSystemState); T32EXTERN int T32_ReadMemory (uint32_t Address, int Access, uint8_t *pBuffer, int Size); T32EXTERN int T32_WriteMemory (uint32_t Address, int Access, const uint8_t *pBuffer, int Size); T32EXTERN int T32_WriteMemoryPipe(uint32_t Address, int Access, const uint8_t *pBuffer, int Size); T32EXTERN int T32_ReadMemoryEx (uint32_t Address, int Segment, int Access, int Attribute, uint8_t *pBuffer, int Size); /*undocumented*/ T32EXTERN int T32_WriteMemoryEx (uint32_t Address, int Segment, int Access, int Attribute, uint8_t *pBuffer, int Size); /*undocumented*/ T32EXTERN int T32_SetMemoryAccessClass(const char* Access); T32EXTERN int T32_GetRam(uint32_t *pStartAddress, uint32_t *pEndAddress, uint16_t *pAccess); T32EXTERN int T32_GetSource(uint32_t Address, char *SourceFile, uint32_t *pSourceLine); T32EXTERN int T32_GetSelectedSource( char *SourceFile, uint32_t *pSourceLine); T32EXTERN int T32_GetSymbol(const char *SymbolName, uint32_t *pAddress, uint32_t *pSize, uint32_t *pAccess); T32EXTERN int T32_GetSymbolFromAddress (char* SymbolName, uint32_t Address, int StringLength); T32EXTERN int T32_ReadVariableString(const char *VariableName, char *StringFromNumeric, int StringLength); T32EXTERN int T32_ReadVariableValue (const char *VariableName, uint32_t *pValueLower32Bit, uint32_t *pValueUpper32Bit); T32EXTERN int T32_WriteVariableValue (const char *VariableName, uint32_t ValueLower32Bit, uint32_t ValueUpper32Bit); T32EXTERN int T32_GetWindowContent(const char *command, char * buffer, uint32_t requested, uint32_t offset, uint32_t print_code); T32EXTERN int T32_ReadRegisterByName (const char *RegisterName, uint32_t *pValueLower32Bit, uint32_t *pValueUpper32Bit); T32EXTERN int T32_WriteRegisterByName(const char *RegisterName, uint32_t ValueLower32Bit, uint32_t ValueUpper32Bit); T32EXTERN int T32_ReadPP(uint32_t *pProgramCounter); T32EXTERN int T32_ReadRegister (uint32_t MaskLower32Bit, uint32_t MaskUpper32Bit, uint32_t *pBuffer); T32EXTERN int T32_WriteRegister(uint32_t MaskLower32Bit, uint32_t MaskUpper32Bit, uint32_t *pBuffer); T32EXTERN int T32_ReadBreakpoint (uint32_t Address, int Access, uint16_t *pBPConfiguration, int Size); T32EXTERN int T32_WriteBreakpoint(uint32_t Address, int Access, int BPConfiguration, int Size); T32EXTERN int T32_GetBreakpointList(int *pNumberFetched, T32_Breakpoint *pBPSettings, int FetchLimit); T32EXTERN int T32_GetTraceState(int TraceType, int *pTraceState, int32_t *pTraceTotalRecords, int32_t *pCurrentRecordMin, int32_t *pCurrentRecordMax); T32EXTERN int T32_ReadTrace (int TraceType, int32_t StartRecord, int NumberOfRecords, uint32_t Mask, uint8_t *pBuffer); T32EXTERN int T32_GetLastErrorMessage(char *ErrorMessage, uint32_t* pLastError, uint32_t* pInternal); # ifdef ENABLE_NOTIFICATION typedef void (*T32_NotificationCallback_t)(); T32EXTERN int T32_NotifyStateEnable(int EventNumber, T32_NotificationCallback_t pFunction); T32EXTERN int T32_NotifyEventEnable(const char* event, T32_NotificationCallback_t pFunction); T32EXTERN int T32_CheckStateNotify(unsigned ParameterOfCallbackFunction);
参考:API Functions,包括错误码、每个函数描述以及和多个Trace32联调。
3 Python+t32api.so/t32api.dll进行调试
在C:\T32\demo\api\python中提供了Python所需要使用的库,以及Python脚本。
其中库:
- t32api.dll - 32/64位Windows适用。
- t32api64.dll - 64位Windows适用。
- t32api.so - 32/64位Linux适用。
- t32api64.so - 64位Linux使用。
Python脚本:
- t32api.py - 简单的使用Remote Control演示。
- t32apicmd.py - 使用T32_Cmd()和T32_GetMessage()执行命令获取结果。
- t32remotedo.py - 执行一个PRACTICE脚本。
- t32apimenu.py - 较丰富的Remote Control API演示。
以最简单的t32api.py为例:
#!/usr/bin/python # -*- coding: latin-1 -*- import platform--获取操作系统细信息。 import ctypes--提供了与C语言兼容的数据类型,允许调用DLL/SO共享库中的函数。 # auto-detect the correct library if (platform.system()=='Windows') or (platform.system()[0:6]=='CYGWIN') :--获取操作系统类型,根据操作系统类型加载不同的C Remote Control库。 if ctypes.sizeof(ctypes.c_voidp)==4: # WINDOWS 32bit t32api = ctypes.CDLL("./t32api.dll") # alternative using windows DLL search order: # t32api = ctypes.cdll.t32api else: # WINDOWS 64bit t32api = ctypes.CDLL("./t32api64.dll") # alternative using windows DLL search order: # t32api = ctypes.cdll.t32api64 elif platform.system()=='Darwin' : # Mac OS X t32api = ctypes.CDLL("./t32api.dylib") else : if ctypes.sizeof(ctypes.c_voidp)==4: # Linux 32bit t32api = ctypes.CDLL("./t32api.so") else: # Linux 64bit t32api = ctypes.CDLL("./t32api64.so") t32api.T32_Config(b"NODE=",b"localhost")--调用C库中T32_Config对连接进行配置。 t32api.T32_Config(b"PORT=",b"20000") t32api.T32_Config(b"PACKLEN=",b"1024") t32api.T32_Init()--初始化,并建立和Trace32 PowerView的Socket连接。 t32api.T32_Attach(1)--附着到Trace32,一般选择T32_DEC_ICD支持的命令更丰富。 t32api.T32_Ping()--测试和Trace32的连通。 t32api.T32_Cmd(b"AREA")--执行一个Trace32命令。 t32api.T32_Exit()--断开和Trace32的连接。
4 连接多个Trace32 PowerView
API没有Socket通信通道的参数,这里提供了几个函数用于切换到不同的Socket:
- T32_GetChannelSize():获取一个Channel结构体大小,用于后续创建Channel。
- T32_GetChannelDefaults():获取默认Channel参数。
- T32_SetChannel():设置活跃Channel。
首先T32_GetChannelSize()获取Channel结构体大小,分配内存;然后T32_GetChannelDefaults()填充默认Channel参数;T32_SetChannel()设置活跃参数,之后调用API建立Socket连接,发送命令进行处理。
示例:
void* channel_1 = malloc (T32_GetChannelSize()); void* channel_2 = malloc (T32_GetChannelSize()); T32_GetChannelDefaults (channel_1); T32_GetChannelDefaults (channel_2); T32_SetChannel (channel_1); T32_Config ("PORT=", "20000");--设置channel_1对应的Socket连接。此后发送的命令都会通过端口20000发送。
T32_Init ();
T32_Attach (T32_DEV_ICE);
T32_SetChannel (channel_2);
T32_Config ("PORT=", "20002");--设置channel_2对应的Socket连接。此后发送的命令都会通过端口20002发送。
T32_Init ();
T32_Attach (T32_DEV_ICE);