• Keil debug command SAVE 命令保存文件的解析


    简介

    使用 Keil debug 很方便,把内存中的一段区域 dump 出来也很方便,例如使用命令 SAVE filepath startAddr, endAddr, typeCode 。但是要查看 dump 出来的内容却很不方便。因为 dump 出来的格式是 INTEL hex386 格式的,这个格式是给机器读的而不是给人读的。

    例如下面是一个完成的 INTEL HEX386 格式的文件,你能看懂是什么意思吗?

    :10001300AC12AD13AE10AF1112002F8E0E8F0F2244
    :10000300E50B250DF509E50A350CF5081200132259
    :03000000020023D8
    :0C002300787FE4F6D8FD7581130200031D
    :10002F00EFF88DF0A4FFEDC5F0CEA42EFEEC88F016
    :04003F00A42EFE22CB
    :00000001FF
    

    把 hex386 格式的文件翻译成人能看到的格式是很有必要的,我参考 keil 官方资料 编写了一个 Python 脚本,输入的文件必须是 SAVE filepath startAddr, endAddr, 0x04 产生出来的文件,其中的 typeCode=0x04 表示目标地址时 32bit 对齐的。

    脚本所做的事情就是读取输入文件(例如 abc.hex)处理之后把寄存器的地址-值对写到输出文件(和输入文件名相同,后缀名为 txt)。

    Python 脚本

    脚本内容如下:

    # -*- coding: utf-8 -*-
    """
    Created on Thu Jul 18 09:46:05 2019
    
    @author: LinTeX9527
    
    @version: v0.1-20190718
    
    @desc: convert HEX386 file to txt file.
    """
    
    import os.path
    
    class RegAddrCls:
        """
        an entity represents register addr-value pair.
        """
        def __init__(self, addr, value):
            #super(RegAddrCls, self).__init()
            # default value
            self.__addr = 0
            self.__value = 0
            self.__valid = False
            
            self.regAddr = addr
            self.regValue = value
         
       
        @property
        def regAddr(self):
            return self.__addr
        
        @regAddr.setter
        def regAddr(self, addr):
            if isinstance(addr, int):
                self.__addr = addr
            else:
                raise TypeError("@addr must be a number")
                 
        @property
        def regValue(self):
            return self.__value
        
        @regValue.setter
        def regValue(self, value):
            if isinstance(value, int):
                self.__value = value
                self.isValid = True
            else:
                 raise TypeError("@value must be a number")
        
        @property
        def isValid(self):
            return self.__valid
    
        @isValid.setter
        def isValid(self, valid):
            if isinstance(valid, bool):
                self.__valid = valid
            else:
                raise TypeError("@valid must be True or False")
    
    
    def dumpRegArray(regArray):
        if isinstance(regArray, list):
            index = 0
            while index < len(regArray):
                item = regArray[index]
                if isinstance(item, RegAddrCls):
                    if item.isValid:
                        print("0x{_addr:08x} - 0x{_value:08x}".format(_addr=item.regAddr, _value=item.regValue))
                index += 1
        else:
            print("@regArray is not list type.")
                
    
    # tt for HEX data types.
    TT_00_DATA_RECORD = 0x00
    TT_01_EOF = 0x01
    TT_02_EX_SEG_ADDR_RECORD = 0x02
    TT_04_EX_LINEAR_ADDR_RECORD = 0x04
    TT_05_START_LINEAR_ADDR_RECORD = 0x05
    
    gBaseRegAddr = 0
    
    
    def processLine(lineData):
        
        global gBaseRegAddr
        
        # return this array when data contains valid register addr-value pairs.
        regArray = []
        
        # number of data bytes in the record
        ll = 0
        # starting address
        aaaa = 0
        # HEX record type.
        tt = 00
        # data bytes
        dd = []
        # @cc is the checksum read from the file;
        # @checksum is checksum we calibrate the record
        cc = 0
        checkSum = 0
    
        #print(lineData)
        #print(lineData[2:6])
        
        ll = int(lineData[0:2], base=16)
        #print("ll = 0x{_ll:x}".format(_ll=ll))
    
        aaaa = int(lineData[2:6], base=16)
        aaaa_a = int(lineData[2:4], base=16)
        aaaa_b = int(lineData[4:6], base=16)
        #print("aaaa = 0x{_aaaa:x}".format(_aaaa=aaaa))
    
        tt = int(lineData[6:8], base=16)   
        #print("tt = 0x{_tt:x}".format(_tt=tt))
    
        index = 0
        while (index < ll*2):
            item = int(lineData[8+index:(8+index+2)], base=16)
            dd.append(item)
            index += 2
        #print("dataBytes: {_dd}".format(_dd=dd))
        
        cc = int(lineData[8+index:(8+index+2)], base=16)
        #print("cc = {_cc:x}".format(_cc=cc))
        
        #                          ll + aaaa + tt ++ all_data
        checkSum = 0x01 + 0xFF - ( (ll + (aaaa_a + aaaa_b) + tt + sum(dd)) & 0xFF )
        # checkSum should only be 0~255.
        checkSum = checkSum % 256
        #print("checkSum = {_csum:X}".format(_csum=checkSum))
        
        if cc != checkSum:
            print("CC error for this line data:
    cc = {_cc}
    checkSum = {_chsum}
    {_dd}".format(_cc=cc, _chsum=checkSum, _dd=lineData))
            return None
        
        ###########################  check tt  ####################################
        if tt == TT_01_EOF:
            #print("EOF, no data available.")
            return None
        elif tt == TT_00_DATA_RECORD:
            #print("TT_00_DATA_RECORD")
            index = 0
            
            # register is 4 bytes aligned.
            regNum = int(ll / 4) * 4
            
            while index < regNum:
                #print("index = {_index}".format(_index = index))
                # calculate register address.
                itemAddr = gBaseRegAddr + aaaa + index
                # get register value.
                itemValue = dd[index] + (dd[index+1] << 8)+ (dd[index+2] << 16) + (dd[index+3] << 24)
                
                #regObj = RegAddrCls()
                #regObj.regAddr = itemAddr
                #regObj.regValue = itemValue
                
                regArray.append(RegAddrCls(itemAddr, itemValue))
                index += 4
            
            #dumpRegArray(regArray)
            return regArray
            
        elif tt == TT_02_EX_SEG_ADDR_RECORD:
            #print("TT_02_EX_SEG_ADDR_RECORD")
            
            segAddr = (dd[0] << 12) + (dd[1] << 4)
            print("segAddr = 0x{_seg:08x}".format(_seg=segAddr))
            
            gBaseRegAddr += segAddr
            print("gBaseRegAddr = 0x{_g:x}".format(_g=gBaseRegAddr))
            return None
        elif tt == TT_04_EX_LINEAR_ADDR_RECORD:
            #print("TT_04_EX_LINEAR_ADDR_RECORD")
            if ll != 2:
                print("it must contain 2 data bytes for upper 16 bits address.")
                return None
            
            # update global register base address.
            upAddr = (dd[0] << 8) + dd[1];
            gBaseRegAddr = (upAddr << 16) + aaaa;
            #print("gBaseRegAddr = 0x{_g:x}".format(_g=gBaseRegAddr))
        elif tt == TT_05_START_LINEAR_ADDR_RECORD:
            print("TT_05_START_LINEAR_ADDR_RECORD")
            if ll != 4:
                print("it must contain 4 data bytes for start address of the application.")
                return None
            # TODO: do nothing, we just ignore this type.
            return None
        else:
            #print("TT--Unkown")
            return None
    
    
    def fileHex2Txt(filepath):
        """
        @filepath input file must be HEX format, which is generated from Keil debug
                  command: "SAVE filepath start_addr, end_addr, 0x4"
        """
        if not isinstance(filepath, str):
            print("@filepath must be subclass of str.")
            return
    
        regSet = []
    
        with open(filepath, 'rt') as fileObj:
            while True:
                line = fileObj.readline()
                if len(line):
                    # remove ':'
                    line = line.replace(':', '').strip()
                    tempSet = processLine(line)
                    if tempSet != None:
                        regSet += tempSet
                else:
                    break
        
        inputAbsPath = os.path.abspath(filepath)
        outputFilepath = inputAbsPath.split('.')[0] + '.txt'
        print(" input filepath = {_in}".format(_in=inputAbsPath))
        print("output filepath = {_out}".format(_out=outputFilepath))
            
        #dumpRegArray(regSet)
        
        with open(outputFilepath, 'wt') as fileObj:
            fileObj.write("  address ---  value
    ")
            index = 0
            while index < len(regSet):
                addr = regSet[index].regAddr
                val = regSet[index].regValue
                fileObj.write("0x{_addr:08x} - 0x{_val:08x}
    ".format(_addr=addr, _val=val))
                index += 1    
    
    
    def convertHex386ToTxt(filepath):
        
        # check file suffix
        suffix = os.path.basename(filepath).split('.')[1]
        if suffix != 'hex':
            print("file must have 'hex' suffix")
            return
        
        # check if file exists.
        hex_file_path = os.path.abspath(filepath)
        if os.path.exists(hex_file_path):
            fileHex2Txt(hex_file_path)
        else:
            print("file does NOT exist: {_f}".format(_f=hex_file_path))
        
    
    def main():
        print("------  main()  start  ------")
        
        convertHex386ToTxt("demo.hex")
        
        print("------  main()   over  ------")
    
    
    if __name__ == "__main__":
        main()
        
    

    参考资料

    keil 官方资料

    声明

    欢迎转载,请注明出处和作者,同时保留声明。
    作者:LinTeX9527
    出处:https://www.cnblogs.com/LinTeX9527/p/11233421.html
    本博客的文章如无特殊说明,均为原创,转载请注明出处。如未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利

  • 相关阅读:
    设计模式整理_单例设计模式
    设计模式整理_工厂模式
    设计模式整理_装饰者模式
    设计模式整理_观察者模式
    设计模式整理_策略模式
    JavaSE复习_7 异常
    JavaSE复习_6 枚举类
    JavaSE复习_5 Eclipse的常见操作
    pta编程题19 Saving James Bond 2
    ImportError: No module named PIL
  • 原文地址:https://www.cnblogs.com/LinTeX9527/p/11233421.html
Copyright © 2020-2023  润新知