简介

使用 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:\ncc = {_cc}\ncheckSum = {_chsum}\n{_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\n")
index = 0
while index < len(regSet):
addr = regSet[index].regAddr
val = regSet[index].regValue
fileObj.write("0x{_addr:08x} - 0x{_val:08x}\n".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

本博客的文章如无特殊说明,均为原创,转载请注明出处。如未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利

Keil debug command SAVE 命令保存文件的解析的更多相关文章

  1. Keil综合(03)_map文件全解析[转]

    推荐分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!http://www.captainbed.net/strongerhuang 我的网站:ht ...

  2. 在linux下通过hexdump生成一个十六进制的文本保存文件,解析此文件转变成正常源代码文件。

    举例说明: 此十六进制保存的文件为此源代码hexdump生成的: #include<stdio.h> #include<string.h> #include<stdlib ...

  3. 一个简单的wed服务器SHTTPD(1)————命令行和文件配置解析

    开始学习<LInux网络编程>中的综合案例,虽然代码书上有,还是自己打一下加深理解和印象. 主要有两个函数,完成命令行的解析,另一个实现配置文件的解析,注释还是比较丰富的哦. //star ...

  4. Vim保存文件命令 ":wq" 与 ":x" 的区别

    CSDN转载 [1] Vim是Unix/Linux系统最常用的编辑器之一,在保存文件时,我通常选择":wq",因为最开始学习vim的时候,就只记住了几个常用的命令:也没有细究命令的 ...

  5. [No0000192]Vim打开和保存文件-Vim使用技巧(7)

    使用Vim打开和保存文件是最常用的操作,介绍使用edit命令通过文件路径来打开文件,使用write命令保存文件,当文件路径不存在或用户权限不匹配时,使用write命令调用外部shell程序完成操作. ...

  6. linux:终端常用命令 + vi命令修改文件及保存 方法

    首先介绍一下Ubuntu下各个目录的一般作用: /  这就是根目录,一台电脑有且只有一个根目录,所有的文件都是从这里开始的.举个例子:当你在终端里输入“/home”,你其实是在告诉电脑,先从/(根目录 ...

  7. vi命令修改文件及保存的使用方法

    简单点:vi文件名,按"I"进入insert模式,可以正常文本编辑,编辑好之后按“esc”退出到“命令模式”,再按“shift+:”进入“底行模式”, 按“:wq”保存退出! 还一 ...

  8. linux下vi命令修改文件及保存的使用方法

    进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi n filename :打开文件,并将光标置于第n行首 vi filename :打开文件,并将光标置于一行首 v ...

  9. Docker commit 命令保存的镜像文件太大的问题

    基础镜像: centos7.5 进入容器后, 先后安装了 jdk1.8, maven3.6.0, git, rocketmq4.3.2 安装完成后使用 docker commit 命令保存为镜像 结果 ...

随机推荐

  1. 用python的curl和lxml来抓取和分析网页内容

    Curl是一个强大的URL语法的客户端,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, PO ...

  2. qlineedit设置背景颜色(使用QPalette的方法不行,必须使用QSS)

    使用QPalette的方法不行, ui->le_text->setAutoFillBackground(true);qDebug() << ui->le_text-> ...

  3. Visual C++ 异常(Exception)常见问题 (原文标题:A Visual C++ Exception FAQ)

    Visual C++ 异常(Exception)常见问题 版权:Doug Harrison 2001 – 2007 翻译:magictong(童磊) 2011年3月 原文地址:http://membe ...

  4. Qt - 设置程序界面风格(现成的QMacStyle等等)

    类的继承关系: QMotifStyle:OSF(开放基金协会)开发的一个工业标准的GUI(图形用户接口): QCDEStyle:公共桌面环境(Common Desktop Environment)的缩 ...

  5. NSTimer 的简易使用方法

      一.使用方式 1.声明NSTimer方法   static CGFloat sIntervalTime = 15.f; //定时刷新时间间隔 @property (nonatomic, stron ...

  6. C++中的new,operator new与placement new

    以下是C++中的new,operator new与placement new进行了详细的说明介绍,需要的朋友可以过来参考下     new operator/delete operator就是new和 ...

  7. 3021Java_数据类型

    1.分类 Java数据类型 基本数据类型 数值型 整数类型 浮点类型 字符型 布尔型 引用数据类型 类 接口 数组 2.基本数据类型 2.1 综述 java的8种基本数据类型(简单数据类型) bool ...

  8. vim 列编辑模式

    vim 列编辑模式 标签: vim 视窗模式 列编辑模式 vim 列编辑模式 例子:给列批量添加前缀.后缀.修改字段 vim 列编辑模式 vim 有三种编辑模式,命令模式.输入模式.视窗模式,我们常用 ...

  9. vue复选框获取值的补充

    要通过vue的v-model获取选中复选框的值,可以用遍历对象的方式获取,代码如下: <!DOCTYPE html> <html xmlns="http://www.w3. ...

  10. Application生命周期(一)

    1.Application是什么? Application和Activity,Service一样,是android框架的一个系统组件,当android程序启动时系统会创建一个 application对 ...