为了方便调试 C6000 DSP,我需要获取 DSP 内部所有变量的地址和大小。TI 的 cg_xml 工具包没有提供变量大小的信息,所以我写了这个 Python 脚本,从 .out 文件中提取变量信息并导出为 .csv 文件。

说明

这个脚本包括:

首先,用 ofd6x 把 .out 文件的信息导出为 xml 信息。

然后,用 ElementTree 处理 xml。

最后,生成 csv 文件。

<elf32_sym> 标签包含符号的信息,这些标签位于路径 object_file/elf/section_table/section/symbol_table/ 下。 <elf32_sym> 的内容类似这样:

<elf32_sym>
    <index>0x11cf</index>
    <st_name>0xce40</st_name>
    <st_name_string>VariableName</st_name_string>
    <st_value>0x82825c</st_value>
    <st_size>0x2</st_size>
    <st_bind>STB_GLOBAL</st_bind>
    <st_type>STT_OBJECT</st_type>
    <st_visibility>STV_HIDDEN</st_visibility>
    <st_shndx>0x7</st_shndx>
    <st_shndx_string>.bss</st_shndx_string>
</elf32_sym>

这个链接详细介绍了符号表节(Symbol Table Section)。注意,STT_OBJECT 对应数据对象,如变量、数组等。STT_COMMON 表示一个未初始化的公共块,其处理方式与 STT_OBJECT 完全相同。

若 .out 文件中包含非 ASCII 字符的路径,ofd6x 生成的 xml 可能会含有一些无效字符。下面这句代码用于删除这些无效字符:

output.decode('utf-8','ignore').encode('utf-8')

Python 脚本

import xml.etree.ElementTree as ET
import csv
import subprocess
import sys
import os

if len(sys.argv) != 2:
    sys.exit()

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

filename = sys.argv[1]

output = subprocess.Popen([resource_path("ofd6x.exe"), "-xg", filename], stdout=subprocess.PIPE).communicate()[0]

root = ET.fromstring(output.decode('utf-8','ignore').encode('utf-8'))

def get_name(sym):
    return sym.find('st_name_string').text
def get_type(sym):
    return sym.find('st_type').text
def get_addr(sym):
    return sym.find('st_value').text
def get_size(sym):
    return sym.find('st_size').text
def get_bind(sym):
    return sym.find('st_bind').text
def get_visibility(sym):
    return sym.find('st_visibility').text
def get_shndx(sym):
    return sym.find('st_shndx_string').text

with open(filename+'_syms.csv', 'w', newline='') as csvfile:
    fieldnames = ['name', 'addr', 'addr10', 'size', 'section','bind', 'technblogy.com']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()

    for sym in root.findall('object_file/elf/section_table/section/symbol_table/elf32_sym'):
        if (get_type(sym)=='STT_OBJECT' or get_type(sym)=='STT_COMMON') and get_name(sym)[0]!='$':
            c = {}
            c['name']    = get_name(sym)
            c['addr']    = get_addr(sym)
            c['addr10']  = int(get_addr(sym),16)
            c['size']    = int(get_size(sym),16)
            c['section'] = get_shndx(sym)
            c['bind']    = get_bind(sym)

            writer.writerow(c)

参考

Software Development Organization (SDO) Applications Packages

Symbol Table Section – Linker and Libraries Guide

python – ElementTree and unicode – Stack Overflow

python – Bundling data files with PyInstaller (–onefile) – Stack Overflow

Reading and Writing CSV Files in Python – Real Python


0 条评论

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注