Tools: Refine GNUARM support and data output
The result collect from GNUARM need to be refined and made more
accurate. The two different compliers work differently and the
results are required to be transformed in different formats.
Signed-off-by: Jianliang Shen <jianliang.shen@arm.com>
Change-Id: Ia3ec3e0157adb0bd68e557422fcf6928e4eb5259
diff --git a/code-size-analyze-tool/src/sq.py b/code-size-analyze-tool/src/sq.py
new file mode 100644
index 0000000..11f620a
--- /dev/null
+++ b/code-size-analyze-tool/src/sq.py
@@ -0,0 +1,612 @@
+# ------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# ------------------------------------------------------------------------------
+
+import sqlite3
+import os
+import glob
+from xlsxwriter.workbook import Workbook
+
+class SQ(object):
+ """
+ Class SQ is used to create a new sqlite3 database and search the information
+ of functions, data, sections, libraries, object files from map file. Then
+ store the result into the database for further usage.
+
+ - Methods:
+ - SQ().update() - Create and update the database.
+
+ - Variables:
+ - SQ().armcc - ARMCLANG option.
+ - SQ().gnuarm - GNUARM option.
+ - SQ().file_path - The map file path which detail information comes from.
+ """
+ def __init__(self):
+ """
+ Initialize variables.
+ """
+ self.gnuarm = False
+ self.armcc = False
+ self.file_path = ""
+
+ self.__gnuarm_info = []
+ self.__sec_dict = {}
+ self.__delete()
+ self.__con = sqlite3.connect("data.db")
+ self.__cur = self.__con.cursor()
+
+ def __delete(self):
+ """
+ Search and delete the previous database file and excel file.
+ """
+ for infile in glob.glob(os.path.join(os.getcwd(), '*.db')):
+ os.remove(infile)
+ for infile in glob.glob(os.path.join(os.getcwd(), '*.xlsx')):
+ os.remove(infile)
+
+ def __new(self):
+ """
+ Create tables in a new empty database.
+ """
+ self.__cur.execute('''create table Summary
+ (Code INT NOT NULL,
+ RO_data INT NOT NULL,
+ RW_data INT NOT NULL,
+ ZI_data INT NOT NULL,
+ EXTRA_FLASH INT NOT NULL,
+ EXTRA_RAM INT NOT NULL,
+ Flash INT NOT NULL,
+ RAM INT NOT NULL);''')
+ self.__cur.execute('''create table Section
+ (name TEXT NOT NULL,
+ size INT NOT NULL,
+ address TEXT NOT NULL,
+ pad_size INT NOT NULL);''')
+ self.__cur.execute('''create table Function
+ (name TEXT NOT NULL,
+ section TEXT NOT NULL,
+ size INT NOT NULL,
+ base_addr TEXT NOT NULL,
+ obj_file TEXT NOT_NULL,
+ lib_file TEXT NOT_NULL);''')
+ self.__cur.execute('''create table Data
+ (name TEXT NOT NULL,
+ section TEXT NOT NULL,
+ size INT NOT NULL,
+ base_addr TEXT NOT NULL,
+ type TEXT NOT NULL,
+ obj_file TEXT NOT_NULL,
+ lib_file TEXT NOT_NULL);''')
+ self.__cur.execute('''create table Library
+ (name TEXT NOT NULL,
+ flashsize INT NOT NULL,
+ ramsize INT NOT NULL,
+ code INT NOT NULL,
+ rodata INT NOT NULL,
+ rwdata INT NOT NULL,
+ zidata INT NOT NULL,
+ incdata INT NOT_NULL,
+ Debug INT NOT NULL);''')
+ self.__cur.execute('''create table Object
+ (name TEXT NOT NULL,
+ library TEXT NOT NULL,
+ flashsize INT NOT NULL,
+ ramsize INT NOT NULL,
+ code INT NOT NULL,
+ rodata INT NOT NULL,
+ rwdata INT NOT NULL,
+ zidata INT NOT NULL,
+ incdata INT NOT_NULL,
+ Debug INT NOT NULL);''')
+ if self.gnuarm:
+ self.__cur.execute('''create table Unknown
+ (name TEXT NOT NULL,
+ section TEXT NOT NULL,
+ size INT NOT NULL,
+ base_addr TEXT NOT NULL,
+ type TEXT NOT NULL,
+ obj_file TEXT NOT_NULL,
+ lib_file TEXT NOT_NULL);''')
+
+ def __collect_summary(self):
+ code_size = ro_data = rw_data = zi_data = flash_size = ram_size = extra_ram = extra_flash = 0
+ if self.gnuarm:
+ max_ram_addr = max_flash_addr = max_addr_ram_sym_size = max_addr_flash_sym_size = 0
+ flash_start_addr, x, ram_start_addr, y = self.__get_ram_and_flash_start_addr()
+ for s in self.__gnuarm_info:
+ if s[3] == "text":
+ code_size += s[1]
+ if s[3] == "rodata":
+ ro_data += s[1]
+ if s[3] == "data":
+ rw_data += s[1]
+ if s[3] == "bss":
+ zi_data += s[1]
+ if s[3] == "unknown_ram":
+ extra_ram += s[1]
+ if s[3] == "unknown_flash":
+ extra_flash += s[1]
+
+ for s in self.__sec_dict.keys():
+ if self.__sec_dict[s]['type'] == 'ram':
+ max_ram_addr = max(max_ram_addr, int(self.__sec_dict[s]['addr'], 16))
+ max_addr_ram_sym_size = self.__sec_dict[s]['size']
+ ram_size = max_ram_addr - ram_start_addr + max_addr_ram_sym_size
+
+ """
+ Some special sections like 'psp_stack' or 'heap' are pre-allocated,
+ and filled with zero. They are belonging to bss/ZI part.
+ """
+ if self.__sec_dict[s]['size'] == self.__sec_dict[s]['fill']:
+ zi_data += self.__sec_dict[s]['size']
+ if self.__sec_dict[s]['type'] == 'flash':
+ max_flash_addr = max(max_flash_addr, int(self.__sec_dict[s]['addr'], 16))
+ max_addr_flash_sym_size = self.__sec_dict[s]['size']
+ flash_size = max_flash_addr - flash_start_addr + max_addr_flash_sym_size
+
+ """
+ For Secure image, the TFM_DATA part is loaded from Flash.
+ """
+ for line in open(self.file_path, "r"):
+ if line.find("load address") >= 0:
+ extra_flash_addr = int(line.split()[-1] ,16)
+ extra_flash_data = int(line.split()[-4], 16)
+ if extra_flash_addr == max_flash_addr + max_addr_flash_sym_size:
+ flash_size += extra_flash_data
+
+ elif self.armcc:
+ for line in open(self.file_path, "r"):
+ if line.find("gram Size: Code=") > 0:
+ content = line.split()
+ code_size = int(content[2].split('=')[1])
+ ro_data = int(content[3].split('=')[1])
+ rw_data = int(content[4].split('=')[1])
+ zi_data = int(content[5].split('=')[1])
+ flash_size = code_size + ro_data + rw_data
+ ram_size = rw_data + zi_data
+
+ self.__cur.execute("insert into Summary values (?,?,?,?,?,?,?,?)",
+ (code_size,
+ ro_data,
+ rw_data,
+ zi_data,
+ extra_flash,
+ extra_ram,
+ flash_size,
+ ram_size))
+
+ def __collect_section(self):
+ if self.gnuarm:
+ for s in self.__gnuarm_info:
+ if s[3] == "text":
+ self.__cur.execute("insert into Function values (?,?,?,?,?,?)",
+ (s[0], s[6], s[1], s[2], s[4], s[5]))
+ elif s[3] == "rodata":
+ self.__cur.execute("insert into Data values (?,?,?,?,?,?,?)",
+ (s[0], s[6], s[1], s[2], "RO", s[4], s[5]))
+ elif s[3] == "data":
+ self.__cur.execute("insert into Data values (?,?,?,?,?,?,?)",
+ (s[0], s[6], s[1], s[2], "RW", s[4], s[5]))
+ elif s[3] == "bss":
+ self.__cur.execute("insert into Data values (?,?,?,?,?,?,?)",
+ (s[0], s[6], s[1], s[2], "ZI", s[4], s[5]))
+ else:
+ self.__cur.execute("insert into Unknown values (?,?,?,?,?,?,?)",
+ (s[0], s[6], s[1], s[2], s[3], s[4], s[5]))
+ for s in self.__sec_dict.keys():
+ self.__cur.execute("insert into Section values (?,?,?,?)",
+ (self.__sec_dict[s]['name'],
+ self.__sec_dict[s]['size'],
+ self.__sec_dict[s]['addr'],
+ self.__sec_dict[s]['fill']))
+ elif self.armcc:
+ line_idx, line_start = 0, 0
+ section_name = ""
+ section_addr = ""
+ section_size = 0
+ section_pad_size = 0
+ for line in open(self.file_path, "r"):
+ line_idx += 1
+
+ if line.find("Execution Region") > 0:
+ if len(section_name) > 0:
+ self.__cur.execute("insert into Section values (?,?,?,?)",
+ (section_name,
+ section_size,
+ section_addr,
+ section_pad_size))
+ line_start = line_idx + 1
+
+ content = line.split()
+ if len(content) >= 10:
+ section_name = content[2]
+ section_addr = content[4][:-1]
+ section_size = int(content[6][:-1], 16)
+ section_pad_size = 0
+ if line.find("PAD\n") > 0 and line_idx > line_start and line_start > 0:
+ section_pad_size += int(line.split()[1], 16)
+ if line.find(" Code ") > 0:
+ content = line.split()
+ if len(content) >= 7:
+ if line.find(" * ") > 0:
+ content.remove("*")
+ func_name = content[5].strip().split('.')[-1]
+ if content[6].find('(') > 0:
+ object_file = content[6][content[6].find('(') + 1: -1]
+ lib_file = content[6][:content[6].find('(')]
+ else:
+ object_file = lib_file = content[6]
+ self.__cur.execute("insert into Function values (?,?,?,?,?,?)",
+ (func_name,
+ section_name,
+ int(content[1].strip(), 16),
+ content[0].strip(),
+ object_file,
+ lib_file))
+ if line.find(" Data ") > 0 or line.find(" Zero ") > 0:
+ content = line.split()
+ if len(content) == 7:
+ if content[2] == "Zero":
+ data_type = "ZI"
+ else:
+ data_type = content[3]
+ data_name = content[5].strip()
+ if content[6].find('(') > 0:
+ object_file = content[6][content[6].find('(') + 1: -1]
+ lib_file = content[6][:content[6].find('(')]
+ else:
+ object_file = lib_file = content[6]
+ self.__cur.execute("insert into Data values (?,?,?,?,?,?,?)",
+ (data_name,
+ section_name,
+ int(content[1].strip(), 16),
+ content[0].strip(),
+ data_type,
+ object_file,
+ lib_file))
+
+ def __collect_library(self):
+ if self.gnuarm:
+ lib_detail_list = self.__collect_set(5)
+ for s in lib_detail_list:
+ self.__cur.execute("insert into Library values (?,?,?,?,?,?,?,?,?)",
+ (s['name'],
+ s['Code']+ s['RO'] + s['RW'],
+ s['RW'] + s['ZI'],
+ s['Code'],
+ s['RO'],
+ s['RW'],
+ s['ZI'],
+ 0, 0))
+
+ elif self.armcc:
+ line_idx, line_start = 0, 0
+ for line in open(self.file_path, "r"):
+ line_idx += 1
+ if line.find("Code (inc. data) RO Data RW Data ZI Data Debug Library Name") > 0:
+ line_start = line_idx + 1
+ if line_idx > line_start and line_start > 0:
+ content = line.split()
+ if len(content) == 7:
+ self.__cur.execute("insert into Library values (?,?,?,?,?,?,?,?,?)",
+ (content[6],
+ int(content[0]) + int(content[2]) + int(content[3]),
+ int(content[3]) + int(content[4]),
+ content[0],
+ content[2],
+ content[3],
+ content[4],
+ content[1],
+ content[5]))
+ else:
+ break
+
+ def __collect_obj(self):
+ if self.gnuarm:
+ obj_lib = ""
+ obj_detail_list = self.__collect_set(4)
+ for s in obj_detail_list:
+ for t in self.__gnuarm_info:
+ if t[4] == s['name']:
+ obj_lib = t[5]
+ break
+ self.__cur.execute("insert into Object values (?,?,?,?,?,?,?,?,?,?)",
+ (s['name'],
+ obj_lib,
+ s['Code']+ s['RO'] + s['RW'],
+ s['RW'] + s['ZI'],
+ s['Code'],
+ s['RO'],
+ s['RW'],
+ s['ZI'],
+ 0, 0))
+ elif self.armcc:
+ line_idx, line_start = 0, 0
+ for line in open(self.file_path, "r"):
+ line_idx += 1
+ if line.find("Code (inc. data) RO Data RW Data ZI Data Debug Object Name") > 0:
+ line_start = line_idx + 1
+ if line_idx > line_start and line_start > 0:
+ content = line.split()
+ if len(content) == 7:
+ self.__cur.execute("insert into Object values (?,?,?,?,?,?,?,?,?,?)",
+ (content[6],
+ "no library",
+ int(content[0]) + int(content[2]) + int(content[3]),
+ int(content[3]) + int(content[4]),
+ content[0],
+ content[2],
+ content[3],
+ content[4],
+ content[1],
+ content[5]))
+ else:
+ break
+ line_idx, line_start = 0, 0
+ for line in open(self.file_path, "r"):
+ line_idx += 1
+ if line.find("Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name") > 0:
+ line_start = line_idx + 1
+ if line_idx > line_start and line_start > 0:
+ content = line.split()
+ if len(content) == 7:
+ obj_name = content[6]
+ library_file = ""
+ for line in open(self.file_path, "r"):
+ if line.find(obj_name) > 0:
+ ch_r = line[line.find(obj_name) + len(obj_name)]
+ ch_l = line[line.find(obj_name) - 1]
+ if ch_l == '(' and ch_r == ')':
+ library_file = line.split()[6][:line.split()[6].find('(')]
+ if len(library_file) == 0:
+ library_file = "no library"
+ self.__cur.execute("insert into Object values (?,?,?,?,?,?,?,?,?,?)",
+ (content[6],
+ library_file,
+ int(content[0]) + int(content[2]) + int(content[3]),
+ int(content[3]) + int(content[4]),
+ content[0],
+ content[2],
+ content[3],
+ content[4],
+ content[1],
+ content[5]))
+ else:
+ break
+
+ def __get_ram_and_flash_start_addr(self):
+ start = False
+ for line in open(self.file_path, "r"):
+ if line.find('Memory Configuration') >= 0:
+ start = True
+ if line.find('Linker script and memory map') == 0:
+ break
+ if start:
+ if line.find('FLASH') >= 0:
+ flash_start_addr = int(line.split()[1].strip(), 16)
+ flash_end_addr = int(line.split()[1].strip(), 16) + int(line.split()[2].strip(), 16)
+ if line.find('RAM') >= 0:
+ ram_start_addr = int(line.split()[1].strip(), 16)
+ ram_end_addr = int(line.split()[1].strip(), 16) + int(line.split()[2].strip(), 16)
+ return flash_start_addr, flash_end_addr, ram_start_addr, ram_end_addr
+
+ def __get_info_from_gnuarm_map(self):
+ def get_key_content():
+ start, end, real_start = False, False, False
+ content = ""
+ for line in open(self.file_path, "r"):
+ if line.find('Linker script and memory map') >= 0:
+ start = True
+ if line.find('OUTPUT(') == 0:
+ end = True
+ if start and not real_start:
+ if(line[0] == '.'):
+ real_start = True
+ if real_start and not end:
+ content += line
+ return content.split('\n')[:-2]
+
+ def output_to_gnuarm_info():
+ type_founded = False
+ info = [cur_sym_name, cur_sym_size, cur_sym_addr, "type", obj, lib, cur_sec_name]
+ for type in ["text", "data", "bss", "rodata"]:
+ info[3] = type
+ if cur_sym_name.find('.' + type) == 0:
+ if cur_sym_name.find('.' + type + '.') == 0:
+ info[0] = cur_sym_name[len(type)+2:]
+ self.__gnuarm_info.append(info)
+ type_founded = True
+ break
+ self.__gnuarm_info.append(info)
+ type_founded = True
+ if not type_founded:
+ if int(cur_sym_addr,16) >= flash_start_addr and int(cur_sym_addr,16) <= flash_end_addr:
+ info[3] = "unknown_flash"
+ self.__gnuarm_info.append(info)
+ if int(cur_sym_addr,16) >= ram_start_addr and int(cur_sym_addr,16) <= ram_end_addr:
+ info[3] = "unknown_ram"
+ self.__gnuarm_info.append(info)
+
+ def get_obj_and_lib(line):
+ lib = line[line.rfind('/') + 1:line.rfind('.o') + 2]
+ obj = lib[lib.find("(") + 1:lib.rfind('.o')] + '.o'
+ if lib.find('(') > 0:
+ lib = lib[:lib.find("(")]
+ else:
+ lib = "no library"
+ return lib, obj
+
+ def get_part_list(idx):
+ ret = []
+ while len(lines[idx]) > 0 and lines[idx].split()[0].find('0x0000') >= 0:
+ if len(lines[idx].split()) == 2:
+ cur_addr = lines[idx].split()[0].strip()
+ cur_name = lines[idx].split()[1].strip()
+ if cur_sym_name.find(cur_name) >= 0:
+ break
+ else:
+ delta = -1
+ cur_idx = idx + 1
+ next_addr = ''
+ while len(lines[cur_idx]) >= 0:
+ if lines[cur_idx].find('0x0000') >= 0:
+ for s in lines[cur_idx].split():
+ if s.find('0x0000') >= 0:
+ next_addr = s.strip()
+ delta = int(next_addr, 16) - int(cur_addr, 16)
+ if delta >= 0:
+ break
+ cur_idx += 1
+ ret.append(['0x' + cur_addr[-8:], cur_sym_name+'.'+cur_name, delta])
+ else:
+ break
+ idx += 1
+ return ret
+
+ lines = get_key_content()
+ i_max = len(lines)
+ part_list = []
+ cur_sym_name, cur_sym_addr, cur_sym_size, lib, obj = "", "", "", "", ""
+ flash_start_addr , flash_end_addr , ram_start_addr , ram_end_addr = self.__get_ram_and_flash_start_addr()
+ for i in range(i_max):
+ lib, obj = "no_library", "no_object"
+ if len(lines[i]) > 0 and lines[i][0] == '.':
+ cur_sec_name = lines[i].split()[0][1:]
+ if len(lines[i].split()) > 1:
+ cur_sec_addr = lines[i].split()[1]
+ cur_sec_size = lines[i].split()[2]
+ else:
+ cur_sec_addr = lines[i+1].split()[0]
+ cur_sec_size = lines[i+1].split()[1]
+ if cur_sec_addr.find('0x00') < 0:
+ continue
+ if int(cur_sec_addr,16) >= flash_start_addr and int(cur_sec_addr,16) <= flash_end_addr:
+ self.__sec_dict[cur_sec_name] = {'name': cur_sec_name,
+ 'addr': '0x' + cur_sec_addr[-8:],
+ 'fill': 0,
+ 'size': int(cur_sec_size, 16),
+ 'type': 'flash'}
+ if int(cur_sec_addr,16) >= ram_start_addr and int(cur_sec_addr,16) <= ram_end_addr:
+ self.__sec_dict[cur_sec_name] = {'name': cur_sec_name,
+ 'addr': '0x' + cur_sec_addr[-8:],
+ 'fill': 0,
+ 'size': int(cur_sec_size, 16),
+ 'type': 'ram'}
+
+ if len(lines[i]) > 0 and lines[i][0] == ' ' and lines[i][1] != ' ':
+ cur_sym_name = lines[i].split()[0].strip()
+ if len(lines[i].split()) > 2:
+ cur_sym_addr = lines[i].split()[1].strip()
+ cur_sym_size = lines[i].split()[2].strip()
+ if cur_sym_addr.find('0x00') == 0 and cur_sym_size.find('0x') == 0:
+ cur_sym_addr = '0x' + cur_sym_addr[-8:]
+ cur_sym_size = int(cur_sym_size, 16)
+ if lines[i].find('/') > 0:
+ lib, obj = get_obj_and_lib(lines[i])
+ part_list = get_part_list(i+1)
+ else:
+ continue
+
+ elif len(lines[i+1]) > 0 and lines[i+1].split()[0].find('0x00') >= 0:
+ cur_sym_addr = lines[i+1].split()[0].strip()
+ cur_sym_size = lines[i+1].split()[1].strip()
+ if cur_sym_addr.find('0x00') == 0 and cur_sym_size.find('0x') == 0:
+ cur_sym_addr = '0x' + cur_sym_addr[-8:]
+ cur_sym_size = int(cur_sym_size, 16)
+ if lines[i+1].find('/') > 0:
+ lib, obj = get_obj_and_lib(lines[i+1])
+ part_list = get_part_list(i+2)
+ else:
+ continue
+ else:
+ continue
+
+ if cur_sym_name.find("*fill*") >= 0:
+ self.__sec_dict[cur_sec_name]['fill'] += cur_sym_size
+ continue
+
+ if len(part_list) > 0:
+ for s in part_list:
+ cur_sym_addr = s[0]
+ cur_sym_name = s[1]
+ cur_sym_size = s[2]
+ output_to_gnuarm_info()
+ else:
+ output_to_gnuarm_info()
+
+ def __output_to_excel(self):
+ def transform_db_2_excel(table_name):
+ worksheet = workbook.add_worksheet(name=table_name)
+ cursor = self.__cur.execute('select * from {}'.format(table_name))
+ names = list(map(lambda x: x[0], cursor.description))
+ len_list = []
+ for s in names:
+ len_list.append(max(15, len(s)))
+ for i in range(len(names)):
+ worksheet.write(0, i, names[i], title_m)
+
+ mysel = self.__cur.execute('select * from {}'.format(table_name))
+ for i, row in enumerate(mysel):
+ for j, value in enumerate(row):
+ len_list[j] = max(len_list[j], len(str(value)))
+ worksheet.write(i + 1, j, value, page_m)
+ worksheet.set_column(j, j, width=len_list[j])
+
+ table_list = ["Summary", "Section", "Library", "Object", "Function", "Data"]
+ if self.gnuarm:
+ table_list.append("Unknown")
+ workbook = Workbook('data.xlsx')
+ title_m = workbook.add_format({'bold': True,
+ 'align': 'left',
+ 'font_size': 12})
+ page_m = workbook.add_format({'align': 'left',
+ 'font_size': 10})
+ for table in table_list:
+ transform_db_2_excel(table)
+ workbook.close()
+
+ def __collect_set(self, index):
+ name_list = []
+ detail_list = []
+ for s in self.__gnuarm_info:
+ if s[index] not in name_list:
+ name_list.append(s[index])
+ if s[3] == "text":
+ detail_list.append({'name': s[index], 'Code':s[1],'ZI':0, 'RO':0,'RW':0})
+ if s[3] == "rodata":
+ detail_list.append({'name': s[index], 'Code':0,'ZI':0, 'RO':s[1],'RW':0})
+ if s[3] == "data":
+ detail_list.append({'name': s[index], 'Code':0,'ZI':0, 'RO':0,'RW':s[1]})
+ if s[3] == "bss":
+ detail_list.append({'name': s[index], 'Code':0,'ZI':s[1], 'RO':0,'RW':0})
+ else:
+ for t in detail_list:
+ if t['name'] == s[index]:
+ if s[3] == "text":
+ t['Code'] += s[1]
+ if s[3] == "rodata":
+ t['RO'] += s[1]
+ if s[3] == "data":
+ t['RW'] += s[1]
+ if s[3] == "bss":
+ t['ZI'] += s[1]
+ return detail_list
+
+ def update(self):
+ """
+ Create the database and collect information from map file, then store
+ it into the database, and write to excel file for further usage.
+ """
+ self.__new()
+ if self.gnuarm:
+ self.__get_info_from_gnuarm_map()
+ self.__collect_summary()
+ self.__collect_section()
+ self.__collect_library()
+ self.__collect_obj()
+ self.__con.commit()
+ self.__output_to_excel()
+ self.__con.close()
diff --git a/code-size-analyze-tool/src/ui.py b/code-size-analyze-tool/src/ui.py
new file mode 100644
index 0000000..e555e59
--- /dev/null
+++ b/code-size-analyze-tool/src/ui.py
@@ -0,0 +1,958 @@
+# ------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# ------------------------------------------------------------------------------
+
+import sqlite3
+import curses
+import curses.textpad
+
+class UI(object):
+ """
+ Class UI is used to show the data in the terminal with library curses. It
+ contains two main diffrent functions, one is to control the UI and show the
+ message in the terminal, the other is to search the information and then
+ transform it into a string varible called items[]. This can be showed or
+ exported as a plaintext. These functions to fill items[] are PUBLIC.
+
+ - Methods:
+ - UI().run() - Run the UI in terminal.
+ - UI.draw_<symbol>_page() - Get the information of specific symbol
+
+ - Variables:
+ - UI().items - The result searched from database.
+ - UI().armcc - ARMCLANG option.
+ - UI().gnuarm - GNUARM option.
+ - UI().con - Database handler.
+ - UI().function_name - Specific function name.
+ - UI().data_name - Specific data name.
+ - UI().section_name - Specific section name.
+ - UI().library_name - Specific library name.
+ - UI().obj_file - Specific object file name.
+ """
+
+ def __init__(self):
+ """
+ Initialize variables.
+ """
+ self.function_name = ""
+ self.data_name = ""
+ self.section_name = ""
+ self.library_name = ""
+ self.obj_file = ""
+ self.gnuarm = False
+ self.armcc = False
+ self.items = []
+ self.con = sqlite3.connect("data.db")
+
+ self.__cur = self.con.cursor()
+ self.__window = None
+ self.__width = 0
+ self.__height = 0
+ self.__menu_depth = 0
+ self.__detail = 0
+ self.__section_detail = 0
+ self.__UP = -1
+ self.__DOWN = 1
+ self.__line1 = "─" * 128
+ self.__line2 = "-" * 128
+ self.__cmd_file="Enter the file name:"
+ self.__cmd_func="Enter the function name:"
+ self.__cmd_data="Enter the data name:"
+
+ def __init_curses(self):
+ """
+ Setup the curses
+ """
+ self.__window = curses.initscr()
+ self.__window.keypad(True)
+
+ curses.noecho()
+ curses.cbreak()
+ curses.curs_set(False)
+
+ curses.start_color()
+ curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
+ curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_WHITE)
+
+ self.__current = curses.color_pair(2)
+ self.__height, self.__width = self.__window.getmaxyx()
+
+ self.__max_lines = curses.LINES - 1
+ self.__top = 0
+
+ self.__bottom = len(self.items)
+ self.__current = 0
+ self.__current_x = 0
+
+ def __input_stream(self):
+ """
+ Waiting an input and run a proper method according to type of input
+ """
+ while True:
+ self.__display()
+
+ ch = self.__window.getch()
+ if ch == curses.KEY_UP:
+ self.__scroll(self.__UP)
+ elif ch == curses.KEY_DOWN:
+ self.__scroll(self.__DOWN)
+ elif ch == curses.KEY_LEFT:
+ self.__current_x = max(self.__current_x - 1, 0)
+ elif ch == curses.KEY_RIGHT:
+ self.__current_x = self.__current_x + 1
+ elif ch == ord('q') or ch == ord('Q'):
+ """
+ If press 'q' or 'Q', escape this page
+ """
+ if self.__menu_depth == 0:
+ break
+ self.__menu_depth = max(self.__menu_depth - 1, 0)
+ self.__draw_page()
+ elif ch == 10:
+ """
+ If press ENTER, get into next page if it exists
+ """
+ self.__get_menu_choose()
+ self.__menu_depth = self.__menu_depth + 1
+ self.__draw_page()
+ elif ch == 58:
+ """
+ If press ':', get target name form input line to search
+ functions or data
+ """
+ if self.__menu_depth == 1:
+ if self.__detail == 3:
+ self.draw_function_page(self.__get_input_line_msg(self.__cmd_func))
+ if self.__detail == 4:
+ self.draw_data_page(self.__get_input_line_msg(self.__cmd_data))
+ elif ch == ord('s') or ch == ord('S'):
+ """
+ If press 's' or 'S', save to file
+ """
+ self.__save_file(self.__get_input_line_msg(self.__cmd_file))
+
+ def __get_input_line_msg(self, cmd):
+ """
+ Get message from input line.
+ """
+ self.__window.addstr(self.__height - 1, 0, cmd, curses.color_pair(2))
+ self.input_line = curses.newwin(1, curses.COLS - 2 - len(cmd), curses.LINES-1, len(cmd) + 1)
+ self.input_box = curses.textpad.Textbox(self.input_line)
+ self.__window.refresh()
+ self.input_box.edit()
+ ret = self.input_box.gather()[:len(self.input_box.gather())-1]
+ self.__display()
+ self.input_line.clear()
+ return ret
+
+ def __save_file(self, output_file_name):
+ """
+ Save to files
+ """
+ fo = open(output_file_name + '.txt', "w")
+ for s in self.items:
+ fo.write(s + '\n')
+ fo.close()
+
+ def __scroll(self, direction):
+ """
+ Scrolling the window when pressing up/down arrow keys
+ """
+ next_line = self.__current + direction
+ if (direction == self.__UP) and (self.__top > 0 and self.__current == 0):
+ self.__top += direction
+ return
+ if (direction == self.__DOWN) and (next_line == self.__max_lines) and \
+ (self.__top + self.__max_lines < self.__bottom):
+ self.__top += direction
+ return
+ if (direction == self.__UP) and (self.__top > 0 or self.__current > 0):
+ self.__current = next_line
+ return
+ if (direction == self.__DOWN) and (next_line < self.__max_lines) and \
+ (self.__top + next_line < self.__bottom):
+ self.__current = next_line
+ return
+
+ def __display(self):
+ """
+ Display the items on window
+ """
+ self.__window.erase()
+ for idx, item in enumerate(self.items[self.__top:self.__top + self.__max_lines]):
+ if idx == self.__current:
+ self.__window.addstr(idx, 0, item[self.__current_x:self.__current_x + self.__width], curses.color_pair(2))
+ else:
+ self.__window.addstr(idx, 0, item[self.__current_x:self.__current_x + self.__width], curses.color_pair(1))
+ self.__window.refresh()
+
+ def __draw_page(self):
+ """
+ Draw different page with menu_depth, detail and section_detail.
+ """
+ if self.__menu_depth == 0:
+ self.__draw_welcome_page()
+ elif self.__menu_depth == 1:
+ if self.__detail == 1:
+ self.draw_summary_page()
+ if self.__detail == 2:
+ self.draw_section_page()
+ if self.__detail == 3:
+ self.draw_function_page("")
+ if self.__detail == 4:
+ self.draw_data_page("")
+ if self.__detail == 5:
+ self.draw_library_page()
+ if self.__detail == 6:
+ self.draw_obj_page()
+ elif self.__menu_depth == 2:
+ if self.__detail == 2:
+ self.draw_section_detail_page()
+ if self.__detail == 3:
+ self.draw_function_detail_page()
+ if self.__detail == 4:
+ self.draw_data_detail_page()
+ if self.__detail == 5:
+ self.draw_library_detail_page()
+ if self.__detail == 6:
+ self.draw_obj_detail_page()
+ elif self.__menu_depth == 3 and self.__detail == 2:
+ """
+ Draw section detail menu, here self.__detail is 2
+ """
+ if self.__section_detail == 1:
+ self.draw_section_lib()
+ if self.__section_detail == 2:
+ self.draw_section_func()
+ if self.__section_detail == 3:
+ self.draw_section_data()
+ elif self.__menu_depth == 4:
+ """
+ Only section detail menu can move to menu depth 5, here function
+ detail and data detail are also supported.
+ """
+ if self.__section_detail == 2:
+ self.draw_function_detail_page()
+ if self.__section_detail == 3:
+ self.draw_data_detail_page()
+
+ self.__bottom = len(self.items)
+ self.__current = 0
+ self.__current_x = 0
+ self.__top = 0
+
+ def __get_menu_choose(self):
+ """
+ Get options from menus or specific objects like function, data, library
+ or object files.
+ """
+
+ """
+ First page, menu_depth = 1
+ =============================
+ Current file: tfm_s.axf
+ 1. Summary Info -->
+ 2. Section Module -->
+ 3. Function detail -->
+ 4. Data detail -->
+ 5. Library Summary -->
+ 6. Object files Summary -->
+ =============================
+ It will change the self.__detail's value in range 1 - 6
+ """
+ if self.__menu_depth == 0:
+ if self.__current + self.__top > 0:
+ self.__detail = self.__current
+ else:
+ """
+ Except first line
+ """
+ self.__menu_depth = self.__menu_depth - 1
+ if self.__menu_depth == 1:
+ if self.__current + self.__top > 0:
+ if self.__detail == 2:
+ """
+ Get section name which will be used to draw its detail page
+ in __draw_page() function.
+ """
+ self.section_name = self.items[self.__top + self.__current].split()[0]
+ elif self.__detail == 3:
+ """
+ Get function name and its object file to avoid same name
+ situation. Function name will be used to draw its detail
+ page in __draw_page() function.
+ """
+ self.function_name = self.items[self.__top + self.__current].split()[0]
+ self.obj_file = self.items[self.__top + self.__current].split()[4]
+ elif self.__detail == 4:
+ """
+ Get data name and its object file name to avoid same name
+ situation. Data name will be used to draw its detail page in
+ __draw_page() function.
+ """
+ self.data_name = self.items[self.__top + self.__current].split()[0]
+ self.obj_file = self.items[self.__top + self.__current].split()[5]
+ elif self.__detail == 5:
+ """
+ Get library name which will be used to draw its detail page
+ in __draw_page() function.
+ """
+ self.library_name = self.items[self.__top + self.__current].split()[0]
+ elif self.__detail == 6:
+ """
+ Get object file name which will be used to draw its detail
+ page in __draw_page() function.
+ """
+ self.obj_file = self.items[self.__top + self.__current].split()[0]
+ else:
+ """
+ Other invalid choose will not change menu depth.
+ """
+ self.__menu_depth = self.__menu_depth - 1
+ else:
+ """
+ Except first line
+ """
+ self.__menu_depth = self.__menu_depth - 1
+ """
+ Section detail page, menu_depth = 1
+ =============================
+ Name :TFM_UNPRIV_CODE Size :155544
+ 1. Summary -->
+ 2. Function -->
+ 3. Data -->
+ =============================
+ It will change the self.__section_detail's value in range 1 - 3
+ """
+ if self.__menu_depth == 2:
+ if self.__current + self.__top > 0:
+ if self.__detail == 2:
+ self.__section_detail = self.__current
+ else:
+ self.__menu_depth = self.__menu_depth - 1
+ else:
+ self.__menu_depth = self.__menu_depth - 1
+ if self.__menu_depth == 3:
+ if self.__current + self.__top > 0:
+ if self.__section_detail == 2:
+ self.function_name = self.items[self.__top + self.__current].split()[0]
+ self.obj_file = self.items[self.__top + self.__current].split()[4]
+ elif self.__section_detail == 3:
+ self.data_name = self.items[self.__top + self.__current].split()[0]
+ self.obj_file = self.items[self.__top + self.__current].split()[5]
+ else:
+ self.__menu_depth = self.__menu_depth - 1
+ else:
+ self.__menu_depth = self.__menu_depth - 1
+ if self.__menu_depth == 4:
+ self.__menu_depth = self.__menu_depth - 1
+
+ def __draw_welcome_page(self):
+ self.items = ["Code Size Analysis Tool for Map File",
+ "1. Summary Info -->",
+ "2. Section Module -->",
+ "3. Function detail -->",
+ "4. Data detail -->",
+ "5. Library Summary -->",
+ "6. Object files Summary -->"]
+
+ def draw_summary_page(self):
+ """
+ Get summary info from database and save into self.items.
+ """
+ cursor = self.__cur.execute("select * from Summary")
+ if self.gnuarm:
+ for row in cursor:
+ self.items = [self.__line1,
+ "Total usage(include all symbols and \"fill or pad\"):",
+ "Flash size\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[6], row[6]/1024),
+ "RAM size\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[7], row[7]/1024),
+ self.__line2,
+ "These data are collected from functions, stacks or arrays sizes without \"fill or pad\" part!",
+ "Text size\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[0], row[0]/1024),
+ "Read-only data\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[1], row[1]/1024),
+ "Read-write data\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[2], row[2]/1024),
+ "BSS data\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[3], row[3]/1024),
+ self.__line2,
+ "Some other unknown type symbols locate in flash or ram:",
+ "Total unknown type symbols in flash: {:<8}\t{:<4.2f}\tKB".
+ format(row[4], row[4]/1024),
+ "Total unknown type symbols in RAM : {:<8}\t{:<4.2f}\tKB".
+ format(row[5], row[5]/1024),
+ self.__line1]
+ break
+ if self.armcc:
+ for row in cursor:
+ self.items = ["Code size\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[0], row[0]/1024),
+ "RO data\t\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[1], row[1]/1024),
+ "RW data\t\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[2], row[2]/1024),
+ "ZI data\t\t: {:<8}\t{:<4.2f}\tKB".
+ format(row[3], row[3]/1024),
+ "Flash size\t: {:<8}\t{:<4.2f}\tKB = Code + RO + RW".
+ format(row[6], row[6]/1024),
+ "RAM size\t: {:<8}\t{:<4.2f}\tKB = RW + ZI".
+ format(row[7], row[7]/1024)]
+ break
+
+ def draw_section_page(self):
+ """
+ Get section info from database and save into self.items.
+ """
+ self.items = ["{:<50}{:<16}{:<16}{:<16}".
+ format("Name", "Size", "Address", "PAD size")]
+
+ cursor = self.__cur.execute("select * from Section ORDER BY size DESC")
+ for row in cursor:
+ self.items.append("{:<50}{:<16}{:<16}{:<16}".
+ format(row[0], row[1], row[2], row[3]))
+
+ def draw_section_detail_page(self):
+ """
+ Section detail page with a menu.
+ """
+ cursor = self.__cur.execute("select * from Section WHERE name = '{}'".
+ format(self.section_name))
+ for row in cursor:
+ self.items = ["Name :{}\t\tSize :{}".
+ format(self.section_name, row[1]),
+ "1. Summary -->",
+ "2. Function -->",
+ "3. Data -->"]
+ break
+
+ def draw_section_lib(self):
+ lib_dict, obj_dict = {}, {}
+ lib_list, obj_list = [], []
+ exsit_no_lib_obj = False
+ tmp_list = []
+ colums_name = "{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".format(
+ "Name", "Flash", "RAM", "Code", "RO data", "RW data", "ZI data", "Total")
+ count = 0
+
+ """
+ Get detail information with functions and data from tables in database
+ with a dictionary in python.
+ """
+ cursor = self.__cur.execute("select * from Function WHERE section = '{}' ORDER BY lib_file DESC".
+ format(self.section_name))
+ for row in cursor:
+ lib_name = row[5]
+ if lib_name in lib_dict.keys():
+ lib_dict[lib_name]['Code'] += row[2]
+ else:
+ lib_dict[lib_name] = {'RO': 0, 'RW': 0,
+ 'Code': row[2], 'ZI': 0}
+
+ obj_name = row[4]
+ if obj_name in obj_dict.keys():
+ obj_dict[obj_name]['Code'] += row[2]
+ else:
+ obj_dict[obj_name] = {'RO': 0, 'RW': 0,
+ 'Code': row[2], 'Lib': lib_name, 'ZI': 0}
+
+ cursor = self.__cur.execute("select * from Data WHERE section = '{}' ORDER BY lib_file DESC".
+ format(self.section_name))
+ for row in cursor:
+ lib_name = row[6]
+ if lib_name in lib_dict.keys():
+ lib_dict[lib_name][row[4]] += row[2]
+ else:
+ lib_dict[lib_name] = {'RO': 0, 'RW': 0, 'Code': 0, 'ZI': 0}
+ lib_dict[lib_name][row[4]] = row[2]
+
+ obj_name = row[5]
+ if obj_name in obj_dict.keys():
+ obj_dict[obj_name][row[4]] += row[2]
+ else:
+ obj_dict[obj_name] = {'RO': 0, 'RW': 0,
+ 'Code': 0, 'Lib': lib_name, 'ZI': 0}
+ obj_dict[obj_name][row[4]] = row[2]
+
+ """
+ Transform the dictionary to a dictionary list in python and sort the
+ elements with total size.
+ """
+ for s in lib_dict.keys():
+ lib_list.append({'Name': s,
+ 'RO': lib_dict[s]['RO'],
+ 'RW': lib_dict[s]['RW'],
+ 'Code': lib_dict[s]['Code'],
+ 'ZI': lib_dict[s]['ZI']})
+ lib_list = sorted(lib_list,
+ key=lambda i: i['RO'] + i['Code'] + i['RW'] + i['ZI'],
+ reverse=True)
+ for s in obj_dict.keys():
+ obj_list.append({'Name': s,
+ 'RO': obj_dict[s]['RO'],
+ 'RW': obj_dict[s]['RW'],
+ 'Code': obj_dict[s]['Code'],
+ 'Lib': obj_dict[s]['Lib'],
+ 'ZI': obj_dict[s]['ZI']})
+ obj_list = sorted(obj_list,
+ key=lambda i: i['RO'] + i['Code'] + i['RW'] + i['ZI'],
+ reverse=True)
+
+ def sum_data(data_list):
+ """
+ Calculate the sum of libraries or object files, and implement total
+ data line. It will be added into self.items.
+ """
+ ret = {'RO': 0, 'RW': 0, 'Code': 0, 'ZI': 0,
+ 'Flash': 0, 'Ram': 0, 'Total': 0}
+ if len(data_list) > 0:
+ for s in data_list:
+ ret['Code'] += s['Code']
+ ret['RO'] += s['RO']
+ ret['RW'] += s['RW']
+ ret['ZI'] += s['ZI']
+ ret['Flash'] += s['Code'] + s['RO'] + s['RW']
+ ret['Ram'] += s['RW'] + s['ZI']
+ ret['Total'] = ret['Flash'] + ret['ZI']
+ self.items.append(self.__line2)
+ self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format("Summary",
+ ret['Flash'],
+ ret['Ram'],
+ ret['Code'],
+ ret['RO'],
+ ret['RW'],
+ ret['ZI'],
+ ret['Total']))
+ self.items.append(self.__line1)
+ return ret
+
+ def insert_column_line(title):
+ """
+ Quickly insert column line.
+ """
+ self.items.append(title)
+ self.items.append(self.__line2)
+ self.items.append(colums_name)
+ self.items.append(self.__line2)
+
+ def quick_insert_data_line(s):
+ """
+ Quickly insert a single data line.
+ """
+ self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format(s['Name'],
+ s['Code'] + s['RO'] + s['RW'],
+ s['RW'] + s['ZI'],
+ s['Code'],
+ s['RO'],
+ s['RW'],
+ s['ZI'],
+ s['Code'] + s['RO'] + s['RW'] + s['ZI']))
+ """
+ Dump library information.
+ """
+ self.items = [self.__line1]
+ insert_column_line("\t\t\t\t\t\t\tSection libraries")
+ for s in lib_list:
+ if s['Name'].find(".o") > 0:
+ exsit_no_lib_obj = True
+ else:
+ tmp_list.append(s)
+ quick_insert_data_line(s)
+ sum_data(tmp_list)
+
+ """
+ Dump object file information.
+ """
+ insert_column_line("\t\t\t\t\t\t\tSection object files")
+ for s in obj_list:
+ quick_insert_data_line(s)
+ ret = sum_data(obj_list)
+ total_flash_size, total_ram_size = ret['Flash'], ret['Ram']
+
+ """
+ Dump NOT-IN-LIBRARY object file information.
+ """
+ if exsit_no_lib_obj:
+ insert_column_line(
+ "\t\t\t\t\t\t\tSection NOT-IN-LIBRARY object files")
+ tmp_list = []
+ for s in lib_list:
+ if s['Name'].find(".o") > 0:
+ tmp_list.append(s)
+ quick_insert_data_line(s)
+ sum_data(tmp_list)
+
+ """
+ Insert the summary information at the top of this page.
+ """
+ cursor = self.__cur.execute(
+ "select * from Section WHERE name = '{}'".format(self.section_name))
+ for row in cursor:
+ self.items.insert(0, "Section Name :{}\tTotal Size :{}\tFlash : {}\tRAM : {:<6}\tPad size = {}".
+ format(self.section_name, row[1], total_flash_size, total_ram_size, row[3]))
+ break
+ self.items.insert(0, self.__line2)
+ self.items.insert(0, "\t\t\t\t\t\t\tSection information")
+ self.items.insert(0, self.__line1)
+
+ """
+ Dump detail information of the section.
+ """
+ index = 4 * ' '
+ self.items.append("\t\t\t\t\t\t\tDetail information")
+ self.items.append(self.__line2)
+ for s in lib_list:
+ self.items.append("{} Code Size = {} RO Data = {} RW Data = {} ZI Data = {}".
+ format(s['Name'], s['Code'], s['RO'], s['RW'], s['ZI']))
+ for t in obj_list:
+ if t['Lib'] == s['Name']:
+ self.items.append(index + "{} Code Size = {} RO Data = {} RW Data = {} ZI Data = {}".format(
+ t['Name'], t['Code'], t['RO'], t['RW'], t['ZI']))
+ count = 0
+ cursor = self.__cur.execute("select * from Function WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' ORDER BY size DESC".
+ format(self.section_name,
+ s['Name'],
+ t['Name']))
+ for row in cursor:
+ if row and count == 0:
+ self.items.append(index * 2 + "Code size = {}".
+ format(t['Code']))
+ count = count + 1
+ self.items.append(index * 3 + "{:<6} {} ".
+ format(row[2], row[0]))
+
+ def get_certain_data(type_name, s, t):
+ count = 0
+ cursor = self.__cur.execute("select * from Data WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' and type = '{}' ORDER BY size DESC".
+ format(self.section_name,
+ s['Name'],
+ t['Name'],
+ type_name))
+ for row in cursor:
+ if row and count == 0:
+ self.items.append(index * 2 + "{} Data = {}".
+ format(type_name, t[type_name]))
+ count = count + 1
+ self.items.append(index * 3 + "{:<6} {}".
+ format(row[2], row[0]))
+
+ get_certain_data('RO', s, t)
+ get_certain_data('RW', s, t)
+ get_certain_data('ZI', s, t)
+ self.items.append(self.__line2)
+
+ def draw_section_func(self):
+ self.items = ["{:<50}{:<32}{:<10}{:<16}{:<40}{:<40}".
+ format("Name",
+ "Section",
+ "Size",
+ "Address",
+ "Object File",
+ "Library")]
+ cursor = self.__cur.execute("select * from Function WHERE section = '{}' ORDER BY size DESC".
+ format(self.section_name))
+ for row in cursor:
+ self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}{:<40}".
+ format(row[0], row[1], row[2], row[3], row[4], row[5]))
+
+ def draw_section_data(self):
+ self.items = ["{:<50}{:<32}{:<10}{:<16}{:<16}{:<40}{:<40}".
+ format("Name",
+ "Section",
+ "Size",
+ "Address",
+ "Type",
+ "Object File",
+ "Library")]
+
+ cursor = self.__cur.execute("select * from Data WHERE section = '{}' ORDER BY size DESC".
+ format(self.section_name))
+ for row in cursor:
+ data_name = row[0]
+ if len(data_name) >= 50:
+ data_name = data_name[:40] + "-->"
+ self.items.append("{:<50}{:<32}{:<10}{:<16}{:<16}{:<40}{:<40}".
+ format(data_name, row[1], row[2], row[3], row[4], row[5], row[6]))
+
+ def __quick_append(self):
+ self.items.append(self.__line1)
+
+ self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}".
+ format("Name",
+ "Section",
+ "Size",
+ "Type",
+ "Object File"))
+ self.items.append(self.__line2)
+
+ def __quick_append_data(self, cursor):
+ flag = False
+ for row in cursor:
+ if not flag:
+ self.__quick_append()
+ data_name = row[0]
+ if len(data_name) >= 50:
+ data_name = data_name[:40] + "-->"
+ self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}".
+ format(data_name, row[1], row[2], row[4], row[5]))
+ flag = True
+
+ def draw_library_page(self):
+ self.items = ["{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format("Name",
+ "Flash size",
+ "RAM size",
+ "Code",
+ "RO data",
+ "RW data",
+ "ZI data",
+ "Inc. data",
+ "Debug")]
+
+ cursor = self.__cur.execute(
+ "select * from Library ORDER BY flashsize DESC")
+ for row in cursor:
+ self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
+
+ def draw_library_detail_page(self):
+ flag = False
+ """
+ Draw title.
+ """
+ self.items = [self.__line1, "{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format("Name",
+ "Flash size",
+ "RAM size",
+ "Code",
+ "RO data",
+ "RW data",
+ "ZI data",
+ "Inc. data"),
+ self.__line2]
+
+ cursor = self.__cur.execute("select * from Library WHERE name = '{}'".
+ format(self.library_name))
+ for row in cursor:
+ self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]))
+ break
+
+ """
+ Draw object files.
+ """
+ self.items.append(self.__line1)
+ self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format("Name",
+ "Flash size",
+ "RAM size",
+ "Code",
+ "RO data",
+ "RW data",
+ "ZI data",
+ "Inc. data"))
+ self.items.append(self.__line2)
+
+ cursor = self.__cur.execute("select * from Object WHERE library = '{}' ORDER BY flashsize DESC".
+ format(self.library_name))
+ for row in cursor:
+ self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format(row[0], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
+
+ """
+ Draw functions.
+ """
+ cursor = self.__cur.execute("select * from Function WHERE lib_file = '{}' ORDER BY size DESC".
+ format(self.library_name))
+ for row in cursor:
+ if not flag:
+ self.__quick_append()
+ self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}".
+ format(row[0], row[1], row[2], "Code", row[4]))
+ flag = True
+
+ """
+ Draw RO data.
+ """
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and lib_file = '{}' ORDER BY size DESC".
+ format(self.library_name))
+ self.__quick_append_data(cursor)
+
+ """
+ Draw RW data.
+ """
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and lib_file = '{}' ORDER BY size DESC".
+ format(self.library_name))
+ self.__quick_append_data(cursor)
+
+ """
+ Draw ZI data.
+ """
+ cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and lib_file = '{}' ORDER BY size DESC".
+ format(self.library_name))
+ self.__quick_append_data(cursor)
+ self.items.append(self.__line1)
+
+ def draw_obj_page(self):
+ self.items = ["{:<50}{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format("Name",
+ "Library",
+ "Flash size",
+ "RAM size",
+ "Code",
+ "RO data",
+ "RW data",
+ "ZI data",
+ "Inc. data",
+ "Debug")]
+ cursor = self.__cur.execute(
+ "select * from Object WHERE library = 'no library' ORDER BY flashsize DESC")
+ for row in cursor:
+ self.items.append("{:<50}{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]))
+ cursor = self.__cur.execute(
+ "select * from Object WHERE library != 'no library' ORDER BY flashsize DESC")
+ for row in cursor:
+ self.items.append("{:<50}{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]))
+
+ def draw_obj_detail_page(self):
+ flag = False
+ self.items = [self.__line1,
+ "{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format("Name",
+ "Flash size",
+ "RAM size",
+ "Code",
+ "RO data",
+ "RW data",
+ "ZI data",
+ "Inc. data"),
+ self.__line2]
+
+ cursor = self.__cur.execute("select * from Object WHERE name = '{}'".
+ format(self.obj_file))
+ for row in cursor:
+ self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
+ format(row[0], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
+ break
+
+ cursor = self.__cur.execute("select * from Function WHERE obj_file = '{}' ORDER BY size DESC".
+ format(self.obj_file))
+ for row in cursor:
+ if not flag:
+ self.__quick_append()
+ self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}".
+ format(row[0], row[1], row[2], "Code", row[4]))
+ flag = True
+
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and obj_file = '{}' ORDER BY size DESC".
+ format(self.obj_file))
+ self.__quick_append_data(cursor)
+
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and obj_file = '{}' ORDER BY size DESC".
+ format(self.obj_file))
+ self.__quick_append_data(cursor)
+
+ cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and obj_file = '{}' ORDER BY size DESC".
+ format(self.obj_file))
+ self.__quick_append_data(cursor)
+ self.items.append(self.__line1)
+
+ def draw_function_page(self, search_func):
+ self.items = []
+ self.items.append("{:<50}{:<50}{:<10}{:<16}{:<40}{:<40}".
+ format("Name",
+ "Section",
+ "Size",
+ "Address",
+ "Object File",
+ "Library"))
+ if search_func:
+ cursor = self.__cur.execute("select * from Function WHERE name LIKE '%{}%'".
+ format(search_func))
+ else:
+ cursor = self.__cur.execute(
+ "select * from Function ORDER BY size DESC")
+ for row in cursor:
+ self.items.append("{:<50}{:<50}{:<10}{:<16}{:<40}{:<40}".
+ format(row[0], row[1], row[2], row[3], row[4], row[5]))
+
+ def draw_function_detail_page(self):
+ if self.obj_file:
+ cursor = self.__cur.execute("select * from Function WHERE name = '{}' and obj_file = '{}'".
+ format(self.function_name, self.obj_file))
+ else:
+ cursor = self.__cur.execute("select * from Function WHERE name = '{}'".
+ format(self.function_name))
+ for row in cursor:
+ self.items = ["=================================================",
+ "Name\t\t\t: {}".format(row[0]),
+ "Symbol type\t\t: Function",
+ "Section\t\t\t: {}".format(row[1]),
+ "Size\t\t\t: {}".format(row[2]),
+ "Base address\t\t: {}".format(row[3]),
+ "Object file\t\t: {}".format(row[4]),
+ "Library\t\t\t: {}".format(row[5]),
+ "================================================="]
+
+ def draw_data_page(self, search_data):
+ self.items = ["{:<50}{:<50}{:<10}{:<16}{:<16}{:<40}{:<40}".
+ format("Name",
+ "Section",
+ "Size",
+ "Address",
+ "Type",
+ "Object File",
+ "Library")]
+ if search_data:
+ cursor = self.__cur.execute("select * from Data WHERE name LIKE '%{}%'".
+ format(search_data))
+ else:
+ cursor = self.__cur.execute("select * from Data ORDER BY size DESC")
+ for row in cursor:
+ data_name = row[0]
+ if len(data_name) >= 50:
+ data_name = data_name[:40] + "-->"
+ self.items.append("{:<50}{:<50}{:<10}{:<16}{:<16}{:<40}{:<40}".
+ format(data_name, row[1], row[2], row[3], row[4], row[5], row[6]))
+
+ def draw_data_detail_page(self):
+ if self.obj_file:
+ cursor = self.__cur.execute("select * from Data WHERE name = '{}' and obj_file = '{}'".
+ format(self.data_name, self.obj_file))
+ else:
+ cursor = self.__cur.execute("select * from Data WHERE name = '{}'".
+ format(self.data_name))
+
+ for row in cursor:
+ self.items = ["=================================================",
+ "Name\t\t\t: {}".format(row[0]),
+ "Symbol type\t\t: {}".format(row[4]),
+ "Section\t\t\t: {}".format(row[1]),
+ "Size\t\t\t: {}".format(row[2]),
+ "Base address\t\t: {}".format(row[3]),
+ "Object file\t\t: {}".format(row[5]),
+ "Library\t\t\t: {}".format(row[6]),
+ "================================================="]
+
+ def run(self):
+ """
+ Continue running the TUI until get interrupted
+ """
+ self.__init_curses()
+ try:
+ self.__draw_page()
+ self.__input_stream()
+ except KeyboardInterrupt:
+ pass
+ finally:
+ curses.endwin()