简介

使用 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. windows下进程间通信的(13种方法)

    转自:http://blog.csdn.NET/shiqz/article/details/5862936 摘 要 随着人们对应用程序的要求越来越高,单进程应用在许多场合已不能满足人们的要求.编写多进 ...

  2. 初次比较正式的IT职场面试后几点对自己web开发的思考

    昨天晚上参加一个web开发面试,对于还没有真正毕业的自己来说,web开发的面试不是第一次,暑假就面试几家公司,前几次的面试并没有发现自己对自己学习的专业知识有什么学习态度的问题,因为前几次的面试官都是 ...

  3. C语言实现常用排序算法——基数排序

    #include<stdio.h> #include<math.h> #define SIZE 10 #define C_SIZE 20 /*行数稳定=10,切记!列数务必搞的 ...

  4. spark streaming 接收kafka消息之一 -- 两种接收方式

    源码分析的spark版本是1.6. 首先,先看一下 org.apache.spark.streaming.dstream.InputDStream 的 类说明: This is the abstrac ...

  5. Python自学day-11

    一.RabbitMQ概述 RabbitMQ是一种消息队列,是一个公共的消息中间件,用于不同进程之间的通讯. 除了RabbitMQ以外,还有ZeroMQ.ActiveMQ等等. 前面学习了两种队列: 线 ...

  6. [Qt]自定义表头实现过滤功能

    1. 写在前面 过滤功能源自项目上交互优化用户体验,在表头添加过滤符号实现过滤,替换以往在表格上方占用一行过滤项进行过滤. 2. 过滤提示 过滤提示就是三态图标(normal,hover,press) ...

  7. scrapy基础知识之将item 通过pipeline保存数据到mysql mongoDB:

    pipelines.py class xxPipeline(object): def process_item(self, item, spider): con=pymysql.connect(hos ...

  8. VMware下的Centos7实践Kvm虚拟化(通俗易懂)

    虽然网上已经有很多关于kvm安装的教程了,但我还是看得头晕,有的教程里安装的包很多,有的很少,也没说明那些安装包的作用是干嘛的,用的命令也不一样,也没解释命令的意思是什么. 我重新写一个教程,尽量通俗 ...

  9. kuangbin专题 专题一 简单搜索 Fliptile POJ - 3279

    题目链接:https://vjudge.net/problem/POJ-3279 题意:格子有两面,1表示黑色格子,0表示白色格子,奶牛每次可以踩一个格子,踩到的格子和它周围的上下左右格子都会翻面,也 ...

  10. flink window实例分析

    window是处理数据的核心.按需选择你需要的窗口类型后,它会将传入的原始数据流切分成多个buckets,所有计算都在window中进行. flink本身提供的实例程序TopSpeedWindowin ...