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/README.rst b/code-size-analyze-tool/README.rst
index 31957bb..add23e2 100644
--- a/code-size-analyze-tool/README.rst
+++ b/code-size-analyze-tool/README.rst
@@ -14,41 +14,88 @@
their address and detail information.
* Diff two databases to see the code size increasement or decreasement.
-***************
-Install sqlite3
-***************
+******************
+Install dependency
+******************
Linux
=====
-Install sqlite3 for python.
+Install curse and database.
.. code-block:: bash
- sudo apt-get install python3-dev libmysqlclient-dev
- pip install mysqlclient
+ sudo apt-get install python3-dev libmysqlclient-dev libncursesw6 libncurses6
+ pip install mysqlclient XlsxWriter
+Windows
+=======
-*****
-Usage
-*****
-
-The command is:
+In power shell, use pip to install packages.
.. code-block:: bash
- python3 code_size_analyze.py -i <map file path> --gnuarm
- python3 code_size_analyze.py -i <map file path> --armcc
- python3 code_size_analyze.py --ui
+ pip install mysqlclient XlsxWriter windows-curses
-It is required to input map file path for the script before show the UI. While
-input the map file, compiler information such as ``--gnuarm`` or ``--armcc``
-is required.
+**********************
+Code size analyze tool
+**********************
-keys
-====
+The commands of code size analyze tool usage are:
+
+.. code-block:: bash
+
+ python3 code_size_analyze.py [-h] [-i MAP_FILE_INPUT] [-u]
+ <--gnuarm|--armcc>
+ [-a] [-s] [-l] [-o] [-f] [-d]
+ [--dump_section SECTION_NAME]
+ [--dump_library LIBRARY_NAME]
+ [--dump_obj OBJ_NAME]
+ [--dump_function DUMP_FUNCTION_NAME]
+ [--dump_data DUMP_DATA_NAME]
+ [--search_func FUNCTION_NAME]
+ [--search_data DATA_NAME]
+
+ options:
+ -h, --help show this help message and exit
+ -i MAP_FILE_INPUT map file path <path>/tfm_s.map
+ -u, --ui show UI
+ --gnuarm gnuarm map file input
+ --armcc armclang map file input
+ -a, --all show total
+ -s, --list_section list section
+ -l, --list_library list library
+ -o, --list_obj list object file
+ -f, --list_function list function
+ -d, --list_data list data
+ --dump_section SECTION_NAME dump section
+ --dump_library LIBRARY_NAME dump library
+ --dump_obj OBJ_NAME dump object file
+ --dump_function DUMP_FUNCTION_NAME dump function
+ --dump_data DUMP_DATA_NAME dump data
+ --search_func FUNCTION_NAME search function
+ --search_data DATA_NAME search data
+
+Create database
+===============
+
+It is required to input map file path for the script before show the UI. One of
+the options like ``--gnuarm`` or ``--armcc`` is required. Keep the compiler
+option same from the beginning to the end.
+
+.. code-block:: bash
+
+ python3 code_size_analyze.py -i MAP_FILE_INPUT <--gnuarm|--armcc>
+
+Show the UI
+===========
The script ui.py supplies a menu to choose what developers may be interested.
-There are several keys to move cursor.
+
+.. code-block:: bash
+
+ python3 code_size_analyze.py -u <--gnuarm|--armcc>
+
+There are several keys to use UI.
* UP: Move UP, mouse scrolling up is same.
* DOWN: Move down, mouse scrolling down is same.
@@ -56,31 +103,34 @@
* LEFT: Move left.
* Enter: Move to next page if it can be unfolded.
* ``Q`` or ``q``: Escape to previous page or close script if it in top menu.
+* ``s`` or ``S``: Enter output file name to save the content of current page.
+* ``:`` : Start search and enter the function or data name.
-Search
-======
+Dump detail information
+=======================
-In ``Function detail`` and ``library detail`` pages, developers can search for
-specific target with key word of target name. Press ``:`` to start search and
-enter the name in the last line of window. All the targets with key word will
-be given.
+You can get the list of all sections, libraries, object files, functions or
+data. You can also dump the specific symbol with the name.
-You can also search or dump the target in command line without Ui, for example:
.. code-block:: bash
- python3 code_size_analyze.py --search_func <func_name>
+ python3 code_size_analyze.py <--gnuarm|--armcc> -s
+ python3 code_size_analyze.py <--gnuarm|--armcc> --dump_section SECTION_NAME
-All the features provided by UI can be used in command line too. Enter ``-h`` to
-get the help information and choose the option to use.
-Save
-====
+Search specific function or data
+================================
-In any page, press ``s`` or ``S`` to start enter output file name to save the
-content of this page.
+You can search the target with keyword in command line. For example:
-Diff
-====
+.. code-block:: bash
+
+ python3 code_size_analyze.py <--gnuarm|--armcc> --search_func FUNCTION_NAME
+ python3 code_size_analyze.py <--gnuarm|--armcc> --search_data DATA_NAME
+
+*******************
+Code size diff tool
+*******************
Use ``code_size_diff.py`` to diff two diffrent build results with same compiler.
Firstly, use ``code_size_analyze.py`` to prepare two different databases. For
@@ -88,13 +138,18 @@
.. code-block:: bash
- cd <TF-M workspace>
- git checkout branch1
- # Build with ARMCLANG
- python3 code_size_analyze.py -i <map file 1> --armcc
- mv data.db output/branch1.db
+ usage: code_size_diff.py [-h] -i [input_dbs [input_dbs ...]]
+ [-a] [-f] [-d] [-o] [-l]
- # Do the same steps to create branch2.db
+ optional arguments:
+ -h, --help show this help message and exit
+ -i [input_dbs [input_dbs ...]], --input [input_dbs [input_dbs ...]]
+ Input two different data base files
+ -a, --diff_all diff summary
+ -f, --diff_function diff function
+ -d, --diff_data diff data
+ -o, --diff_obj diff object file
+ -l, --diff_lib diff library
Then compare two database with the diff tool, the branch1 is base.
@@ -113,4 +168,4 @@
--------------
-*Copyright (c) 2021, Arm Limited. All rights reserved.*
+*Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
diff --git a/code-size-analyze-tool/code_size_analyze.py b/code-size-analyze-tool/code_size_analyze.py
index edfaa3e..4aa6763 100644
--- a/code-size-analyze-tool/code_size_analyze.py
+++ b/code-size-analyze-tool/code_size_analyze.py
@@ -1,1571 +1,106 @@
-# -----------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited. All rights reserved.
+# ------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
-# -----------------------------------------------------------------------------
+# ------------------------------------------------------------------------------
-import sqlite3
import argparse
import os
-import glob
-import curses
-import curses.textpad
+import sys
+sys.path.append("src")
+from ui import UI
+from sq import SQ
-line1 = "─" * 128
-line2 = "-" * 128
none_databse = "Cannot find database file! Please use this command to create \
-databse:\n\n\tpython3 code_size_analyze.py -i <map file path>\n"
-cmd_file="Enter the file name:"
-cmd_func="Enter the function name:"
-cmd_data="Enter the data name:"
-
-class UI(object):
- UP, DOWN = -1, 1
-
- def __init__(self):
- """
- Initialize variables.
- """
- self.con = sqlite3.connect("data.db")
- self.cur = self.con.cursor()
-
- # Window variables
- self.window = None
- self.width = 0
- self.height = 0
-
- # Page variables
- self.items = []
-
- # Menu variables
- self.menu_depth = 0
- self.detail = 0
- self.section_detail = 0
-
- # Internal variables
- self.file_name = ""
- self.function_name = ""
- self.data_name = ""
- self.section_name = ""
- self.library_name = ""
- self.obj_file = ""
-
- 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
- self.page = self.bottom // self.max_lines
-
- def run(self):
- """
- Continue running the TUI until get interrupted
- """
- # Create window.
- self.init_curses()
- try:
- self.draw_page()
- self.input_stream() # Get keys input
- except KeyboardInterrupt:
- pass
- finally:
- curses.endwin()
-
- 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
- # If press 'q' or 'Q', escape this page
- elif ch == ord('q') or ch == ord('Q'):
- if self.menu_depth == 0:
- break
- self.menu_depth = max(self.menu_depth - 1, 0)
- self.draw_page()
- # If press ENTER, get into next page if it exists
- elif ch == 10:
- self.get_menu_choose()
- self.menu_depth = self.menu_depth + 1
- self.draw_page()
- # If press ':', get target name form input line
- elif ch == 58:
- if self.menu_depth == 1:
- # Search functions or data
- if self.detail == 3:
- self.draw_function_page(self.get_input_line_msg(cmd_func))
- if self.detail == 4:
- self.draw_data_page(self.get_input_line_msg(cmd_data))
- # If press 's' or 'S', save to file
- elif ch == ord('s') or ch == ord('S'):
- self.save_file(self.get_input_line_msg(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 paging(self, direction):
- """
- Paging the window when pressing left/right arrow keys
- """
- current_page = (self.top + self.current) // self.max_lines
- next_page = current_page + direction
- if next_page == self.page:
- self.current = min(self.current, self.bottom % self.max_lines - 1)
- if (direction == self.UP) and (current_page > 0):
- self.top = max(0, self.top - self.max_lines)
- return
- if (direction == self.DOWN) and (current_page < self.page):
- self.top += self.max_lines
- 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_file_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()
- # Draw section detail menu, here self.detail is 2
- elif self.menu_depth == 3 and self.detail == 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()
- # Only section detail menu can move to menu depth 5, here function
- # detail and data detail are also supported.
- elif self.menu_depth == 4:
- if self.section_detail == 2:
- self.draw_function_detail_page()
- if self.section_detail == 3:
- self.draw_data_detail_page()
-
- # Refresh page variables
- self.bottom = len(self.items)
- self.current = 0
- self.current_x = 0
- self.top = 0
- self.page = self.bottom // self.max_lines
-
- 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:
- # Get section name which will be used to draw its detail page in
- # draw_page() function.
- if self.detail == 2:
- self.section_name = \
- self.items[self.top + self.current].split()[0]
- # 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.
- elif self.detail == 3:
- self.function_name = \
- self.items[self.top + self.current].split()[0]
- self.obj_file = \
- self.items[self.top + self.current].split()[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.
- elif self.detail == 4:
- self.data_name = \
- self.items[self.top + self.current].split()[0]
- self.obj_file = \
- self.items[self.top + self.current].split()[5]
- # Get library name which will be used to draw its detail page in
- # draw_page() function.
- elif self.detail == 5:
- self.library_name = \
- self.items[self.top + self.current].split()[0]
- # Get object file name which will be used to draw its detail
- # page in draw_page() function.
- elif self.detail == 6:
- 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:
- # Only section page's detail can change menu depth.
- self.menu_depth = self.menu_depth - 1
- else:
- # Except first line
- self.menu_depth = self.menu_depth - 1
- if self.menu_depth == 3:
- if self.current + self.top > 0:
- # 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.
- 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]
- # 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.
- 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:
- # 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
- if self.menu_depth == 4:
- # Max menu depth.
- self.menu_depth = self.menu_depth - 1
-
- def draw_file_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")
- 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[4], row[4]/1024),
- "RAM size\t: {:<8}\t{:<4.2f}\tKB = RW + ZI".
- format(row[5], row[5]/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(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(line1)
- return ret
-
- def insert_column_line(title):
- """
- Quickly insert column line.
- """
- self.items.append(title)
- self.items.append(line2)
- self.items.append(colums_name)
- self.items.append(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 = [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, line2)
- self.items.insert(0, "\t\t\t\t\t\t\tSection information")
- self.items.insert(0, line1)
-
- """
- Dump detail information of the section.
- """
- index = 4 * ' '
- self.items.append("\t\t\t\t\t\t\tDetail information")
- self.items.append(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(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(line1)
-
- self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}".
- format("Name",
- "Section",
- "Size",
- "Type",
- "Object File"))
- self.items.append(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 = [line1, "{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
- format("Name",
- "Flash size",
- "RAM size",
- "Code",
- "RO data",
- "RW data",
- "ZI data",
- "Inc. data"),
- 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(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(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(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 = [line1,
- "{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
- format("Name",
- "Flash size",
- "RAM size",
- "Code",
- "RO data",
- "RW data",
- "ZI data",
- "Inc. data"),
- 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(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]),
- "================================================="]
- self.items.append("Called symbol:")
- content = row[6].split('|')
- for s in content:
- self.items.append("\t"+s)
- self.items.append("Dst symbol:")
- content = row[7].split('|')
- for s in content:
- self.items.append("\t"+s)
-
- 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]),
- "================================================="]
- self.items.append("Called symbol:")
- content = row[7].split('|')
- for s in content:
- self.items.append("\t"+s)
- self.items.append("Dst symbol:")
- content = row[8].split('|')
- for s in content:
- self.items.append("\t"+s)
-
-def collect_summary():
- """
- Program Size: Code=181622 RO-data=26226 RW-data=3128 ZI-data=79364
- """
- cur.execute('''create table Summary
- (Code INT NOT NULL,
- RO_data INT NOT NULL,
- RW_data INT NOT NULL,
- ZI_data INT NOT NULL,
- Flash INT NOT NULL,
- RAM INT NOT NULL
- );''')
- code_size = ro_data = rw_data = zi_data = flash_size = ram_size = 0
- if gnuarm:
- for s in 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]
- elif armcc:
- for line in open(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
- cur.execute("insert into Summary values (?,?,?,?,?,?)",
- (code_size, ro_data, rw_data, zi_data, flash_size, ram_size))
-
-def collect_section():
- cur.execute('''create table Section
- (name TEXT NOT NULL,
- size INT NOT NULL,
- address TEXT NOT NULL,
- pad_size INT NOT NULL
- );''')
- 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,
- called_symbol STRING NOT_NULL,
- dst_symbol STRING NOT_NULL
- );''')
- 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,
- called_symbol TEXT NOT_NULL,
- dst_symbol TEXT NOT_NULL
- );''')
- if gnuarm:
- for s in gnuarm_info:
- if s[3] == "text":
- cur.execute("insert into Function values (?, ?, ?, ?, ?, ?, ?, ?)",
- (s[0], "Unknown", s[1], s[2], s[4], s[5], "", ""))
- if s[3] == "rodata":
- cur.execute("insert into Data values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
- (s[0], "Unknown", s[1], s[2], "RO", s[4], s[5], "", ""))
- if s[3] == "data":
- cur.execute("insert into Data values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
- (s[0], "Unknown", s[1], s[2], "RW", s[4], s[5], "", ""))
- if s[3] == "bss":
- cur.execute("insert into Data values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
- (s[0], "Unknown", s[1], s[2], "ZI", s[4], s[5], "", ""))
- elif armcc:
- """
- Execution Region TFM_UNPRIV_CODE (Base: 0x10085360, Size: 0x000327e0, Max: 0xffffffff, ABSOLUTE)
-
- Base Addr Size Type Attr Idx E Section Name Object
-
- 0x10085360 0x00000008 Code RO 3759 * !!!main c_w.l(__main.o)
- 0x10085368 0x00000034 Code RO 4234 !!!scatter c_w.l(__scatter.o)
- 0x1008539c 0x0000005a Code RO 4232 !!dczerorl2 c_w.l(__dczerorl2.o)
- """
- line_idx, line_start = 0, 0
- section_name = ""
- section_addr = ""
- section_size = 0
- section_pad_size = 0
- for line in open(file_path, "r"):
- line_idx += 1
-
- if line.find("Execution Region") > 0:
- if len(section_name) > 0:
- 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]
- dst_symbol, called_symbol = "", ""
- 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]
- for line in open(file_path, "r"):
- if line.find(func_name) > 0:
- if line.find("refers to {}({}".format(object_file, content[5].strip())) > 0 or line.find("refers (Special) to {}({}".format(object_file, content[5].strip())) > 0:
- dst_symbol = dst_symbol + get_dst(line, func_name)
- elif line.find("{}({}) refers to".format(object_file, content[5].strip())) > 0 or \
- line.find('{}({}) refers (Special) to'.format(object_file, content[5].strip())) > 0:
- called_symbol = called_symbol + \
- get_src(line, func_name)
- cur.execute("insert into Function values (?, ?, ?, ?, ?, ?, ?, ?)",
- (func_name,
- section_name,
- int(content[1].strip(), 16),
- content[0].strip(),
- object_file,
- lib_file,
- called_symbol,
- dst_symbol))
- if line.find(" Data ") > 0 or line.find(" Zero ") > 0:
- content = line.split()
- if len(content) == 7:
- dst_symbol, called_symbol = "", ""
- 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]
- for line in open(file_path, "r"):
- if line.find(data_name) > 0:
- if line.find("refers to {}({}".format(object_file, data_name)) > 0 or line.find("refers (Special) to {}({}".format(object_file, data_name)) > 0:
- dst_symbol = dst_symbol + get_dst(line, data_name)
- elif line.find("{}({}) refers to".format(object_file, data_name)) > 0 or \
- line.find('{}({}) refers (Special) to'.format(object_file, data_name)) > 0:
- called_symbol = called_symbol + \
- get_src(line, data_name)
- cur.execute("insert into Data values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
- (data_name,
- section_name,
- int(content[1].strip(), 16),
- content[0].strip(),
- data_type,
- object_file,
- lib_file,
- called_symbol,
- dst_symbol))
-
-def format_info(content):
- if content:
- object_file = content[0:content.find('(')]
- target = content[content.find('(') + 1:content.find(')')]
- return "{:<50}".format(object_file) + ' : ' + target + '|'
-
-def get_dst(line, target):
- ret = ""
- content = []
- if line.find('refers to') > 0:
- content = line.split('refers to')
- if line.find('refers (Special) to') > 0:
- content = line.split('refers (Special) to')
- if content and content[1].find(target) > 0:
- ret = format_info(content[0].strip())
- return ret
-
-def get_src(line, target):
- ret = ""
- content = []
- if line.find('refers to') > 0:
- content = line.split('refers to')
- if line.find('refers (Special) to') > 0:
- content = line.split('refers (Special) to')
- if content and content[0].find(target) > 0:
- ret = format_info(content[1].strip())
- return ret
-
-def collect_set(index):
- name_list = []
- detail_list = []
- for s in 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 collect_library():
- 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
- );''')
- if gnuarm:
- lib_detail_list = collect_set(5)
- for s in lib_detail_list:
- 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 armcc:
- """
- Code (inc. data) RO Data RW Data ZI Data Debug Library Name
-
- 1520 0 0 0 1152 284 libtfm_app_rot_partition_core_test_2.a
- 300 48 0 0 1032 64 libtfm_app_rot_partition_flih_test.a
- 462 0 0 0 772 40 libtfm_app_rot_partition_ipc_client.a
- 4364 6 20 28 6729 1312 libtfm_app_rot_partition_ps.a
- """
- line_idx, line_start = 0, 0
- for line in open(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:
- 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():
- 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 gnuarm:
- obj_lib = ""
- obj_detail_list = collect_set(4)
- for s in obj_detail_list:
- for t in gnuarm_info:
- if t[4] == s['name']:
- obj_lib = t[5]
- break
- 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 armcc:
- """
- Code (inc. data) RO Data RW Data ZI Data Debug Object Name
-
- 0 0 48 0 328 0 load_info_idle_sp.o
- 0 0 48 0 72 0 load_info_ns_agent.o
- 0 0 83 0 92 0 load_info_tfm_crypto.o
-
- Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name
-
- 90 0 0 0 0 0 __dczerorl2.o
- 8 0 0 0 0 68 __main.o
- 0 0 0 0 0 0 __rtentry.o
- """
- line_idx, line_start = 0, 0
- for line in open(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:
- 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(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(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"
- 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_info_from_gnuarm_map():
- """
- Collect information from GNUARM map file.
- """
- text = os.popen('cat ' + file_path).read()
- text = text[text.find('Linker script and memory map\n'):]
-
- for type in ["text", "data", "bss", "rodata"]:
- values = []
- i = 0
- key_type = '.' + type + '.'
- i_max = text.rfind(key_type) + text[text.rfind(key_type):].find(')') + 2
- while (i < i_max) & (text[i:].find(key_type) != -1):
- temp = ''
- i = len(text[:i]) + text[i:].find(key_type)
- while (text[i-2] != '.' or text[i-1] != 'o' ) or (text[i] != '\n' and text[i] != ')'):
- temp = temp + text[i]
- i += 1
- if(i >= i_max):
- break
- temp = temp.replace('\n', ' ').replace('\t', ' ')
- if (temp.find('0x') >= 0):
- values.append(temp)
- i += 1
-
- """
- Get detail data from lines.
- """
- for line in values:
- sym = line[line.find(key_type):line.find("0x")].replace('\n', '').replace('\t', '').replace(' ', '').replace(key_type, '')
- addr = "0x" + line.split()[1][-10:]
- pos = line.find("0x", line.find('0x') + 1)
- if (pos == -1):
- continue
- line = line[pos:]
- size = int(line.split(' ')[0], 16)
- lib = line[line.rfind('/') + 1:line.rfind('.o') + 2]
- obj = lib[lib.find("(") + 1:lib.rfind('.o')]
- if lib.find('(') > 0:
- lib = lib[:lib.find("(")]
- else:
- lib = "no library"
- gnuarm_info.append([sym, size, addr, type, obj + ".o", lib])
-
- """
- Read some common symbols from GNUARM map file. These symbols are bss data.
- """
- text = os.popen('cat ' + file_path).read()
- text = text[text.find("Allocating common symbols") + len("Allocating common symbols"):text.find("Discarded input sections")]
- common_symbol_list = text.split()[4:]
- for i in range(int(len(common_symbol_list) / 3)):
- common_symbol = common_symbol_list[3 * i]
- for line in open(file_path, "r"):
- if line.find(common_symbol) > 0 and line.find("0x0000") > 0:
- addr = "0x" + line.split()[0][-10:]
- common_symbol_size = int(common_symbol_list[3 * i + 1], 16)
- temp = common_symbol_list[3 * i + 2]
- lib = temp[temp.rfind('/') + 1:temp.rfind('.o') + 2]
- obj = lib[lib.find("(") + 1:lib.rfind('.o')]
- if lib.find('(') > 0:
- lib = lib[:lib.find("(")]
- else:
- lib = "no library"
- gnuarm_info.append([common_symbol, common_symbol_size, addr, "bss", obj + ".o", lib])
+databse:\n\n\tpython3 code_size_analyze.py -i <map file path> --gnuarm/--armcc\n"
def main(args):
- output = ""
+ """
+ It is required to input only one of '--gnuarm' and '--armcc'.
+ """
+ if (args.gnuarm_compiler and args.armclang_compiler) or \
+ (not args.gnuarm_compiler and not args.armclang_compiler):
+ print("Error: Need \'--gnuarm\' or \'--armcc\'")
+ exit(0)
+
+ """
+ Class 'sq' is to create a sqlite3 database from map file of compiler.
+ """
if args.map_file_input:
- if args.gnuarm_compiler and args.armclang_compiler:
- print("Error: Need \'--gnuarm\' or \'--armcc\'")
- if args.gnuarm_compiler or args.armclang_compiler:
- global cur, file_path, gnuarm_info, gnuarm, armcc
- gnuarm = armcc = False
- for infile in glob.glob(os.path.join(os.getcwd(), '*.db')):
- os.remove(infile)
- file_path = args.map_file_input
- con = sqlite3.connect("data.db")
- cur = con.cursor()
- if args.gnuarm_compiler:
- gnuarm_info = []
- gnuarm = True
- get_info_from_gnuarm_map()
- else:
- armcc = True
- collect_summary()
- collect_section()
- collect_library()
- collect_obj()
- con.commit()
- con.close()
- else:
- print("Error: Need \'--gnuarm\' or \'--armcc\'")
+ sq = SQ()
+ sq.gnuarm = True if args.gnuarm_compiler else False
+ sq.armcc = True if args.armclang_compiler else False
+ sq.file_path = args.map_file_input
+ sq.update()
- if args.ui_show:
- if os.path.exists('data.db'):
- ui = UI()
+ if os.path.exists('data.db'):
+ """
+ Class 'ui' is to show the ui in terminal or export plaintext.
+ """
+ ui = UI()
+ ui.gnuarm = True if args.gnuarm_compiler else False
+ ui.armcc = True if args.armclang_compiler else False
+ output = ""
+ if args.ui_show:
ui.run()
- ui.con.close()
else:
- print(none_databse)
+ if args.all:
+ ui.draw_summary_page()
- if args.all:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_summary_page()
- output = ui.items
- else:
- print(none_databse)
+ if args.list_function:
+ ui.draw_function_page("")
- if args.list_function:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_function_page("")
- output = ui.items
- else:
- print(none_databse)
+ if args.function_name:
+ ui.draw_function_page(args.function_name)
- if args.function_name:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_function_page(args.function_name)
- output = ui.items
- else:
- print(none_databse)
+ if args.dump_function_name:
+ ui.function_name = args.dump_function_name
+ ui.draw_function_detail_page()
- if args.dump_function_name:
- if os.path.exists('data.db'):
- ui = UI()
- ui.function_name = args.dump_function_name
- ui.draw_function_detail_page()
- output = ui.items
- else:
- print(none_databse)
+ if args.list_data:
+ ui.draw_data_page("")
- if args.list_data:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_data_page("")
- output = ui.items
- else:
- print(none_databse)
+ if args.data_name:
+ ui.draw_data_page(args.data_name)
- if args.data_name:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_data_page(args.data_name)
- output = ui.items
- else:
- print(none_databse)
+ if args.dump_data_name:
+ ui.data_name = args.dump_data_name
+ ui.draw_data_detail_page()
- if args.dump_data_name:
- if os.path.exists('data.db'):
- ui = UI()
- ui.data_name = args.dump_data_name
- ui.draw_data_detail_page()
- output = ui.items
- else:
- print(none_databse)
+ if args.list_obj:
+ ui.draw_obj_page()
- if args.list_obj:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_obj_page()
- output = ui.items
- else:
- print(none_databse)
+ if args.obj_name:
+ ui.obj_file = args.obj_name
+ ui.draw_obj_detail_page()
- if args.obj_name:
- if os.path.exists('data.db'):
- ui = UI()
- ui.obj_file = args.obj_name
- ui.draw_obj_detail_page()
- output = ui.items
- else:
- print(none_databse)
+ if args.list_library:
+ ui.draw_library_page()
- if args.list_library:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_library_page()
- output = ui.items
- else:
- print(none_databse)
+ if args.library_name:
+ ui.library_name = args.library_name
+ ui.draw_library_detail_page()
- if args.library_name:
- if os.path.exists('data.db'):
- ui = UI()
- ui.library_name = args.library_name
- ui.draw_library_detail_page()
- output = ui.items
- else:
- print(none_databse)
- if args.list_section:
- if os.path.exists('data.db'):
- ui = UI()
- ui.draw_section_page()
- output = ui.items
- else:
- print(none_databse)
+ if args.list_section:
+ ui.draw_section_page()
- if args.section_name:
- if os.path.exists('data.db'):
- ui = UI()
- ui.section_name = args.section_name
- ui.draw_section_lib()
- output = ui.items
- else:
- print(none_databse)
+ if args.section_name:
+ ui.section_name = args.section_name
+ ui.draw_section_lib()
- if output:
- for s in output:
- print(s)
+ output = ui.items
+ if output:
+ for s in output:
+ print(s)
+ ui.con.close()
+ else:
+ print(none_databse)
def parse_args():
"""
+ List the arguments for program.
"""
-
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input',
@@ -1575,71 +110,62 @@
dest='ui_show',
action='store_true',
help='show UI')
-
parser.add_argument('--gnuarm',
dest='gnuarm_compiler',
action='store_true',
help='gnuarm map file input')
-
parser.add_argument('--armcc',
dest='armclang_compiler',
action='store_true',
help='armclang map file input')
-
parser.add_argument('-a', '--all',
dest='all',
action='store_true',
help='show total')
-
- parser.add_argument('-f', '--list_function',
- dest='list_function',
- action='store_true',
- help='list function')
- parser.add_argument('--search_func',
- dest='function_name',
- help='search function')
- parser.add_argument('--dump_function',
- dest='dump_function_name',
- help='dump function')
-
- parser.add_argument('-d', '--list_data',
- dest='list_data',
- action='store_true',
- help='list data')
- parser.add_argument('--search_data',
- dest='data_name',
- help='search data')
- parser.add_argument('--dump_data',
- dest='dump_data_name',
- help='dump data')
-
- parser.add_argument('-o', '--list_obj',
- dest='list_obj',
- action='store_true',
- help='list object file')
- parser.add_argument('--dump_obj',
- dest='obj_name',
- help='dump object file')
-
- parser.add_argument('-l', '--list_library',
- dest='list_library',
- action='store_true',
- help='list library')
- parser.add_argument('--dump_library',
- dest='library_name',
- help='dump library')
-
parser.add_argument('-s', '--list_section',
dest='list_section',
action='store_true',
help='list section')
+ parser.add_argument('-l', '--list_library',
+ dest='list_library',
+ action='store_true',
+ help='list library')
+ parser.add_argument('-o', '--list_obj',
+ dest='list_obj',
+ action='store_true',
+ help='list object file')
+ parser.add_argument('-f', '--list_function',
+ dest='list_function',
+ action='store_true',
+ help='list function')
+ parser.add_argument('-d', '--list_data',
+ dest='list_data',
+ action='store_true',
+ help='list data')
parser.add_argument('--dump_section',
dest='section_name',
help='dump section')
+ parser.add_argument('--dump_library',
+ dest='library_name',
+ help='dump library')
+ parser.add_argument('--dump_obj',
+ dest='obj_name',
+ help='dump object file')
+ parser.add_argument('--dump_function',
+ dest='dump_function_name',
+ help='dump function')
+ parser.add_argument('--dump_data',
+ dest='dump_data_name',
+ help='dump data')
+ parser.add_argument('--search_func',
+ dest='function_name',
+ help='search function')
+ parser.add_argument('--search_data',
+ dest='data_name',
+ help='search data')
args = parser.parse_args()
return args
-
if __name__ == '__main__':
main(parse_args())
exit(0)
diff --git a/code-size-analyze-tool/code_size_diff.py b/code-size-analyze-tool/code_size_diff.py
index 16748f7..ffd4d84 100644
--- a/code-size-analyze-tool/code_size_diff.py
+++ b/code-size-analyze-tool/code_size_diff.py
@@ -1,9 +1,9 @@
-# -----------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited. All rights reserved.
+# ------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
-# -----------------------------------------------------------------------------
+# ------------------------------------------------------------------------------
import sqlite3
import argparse
@@ -12,9 +12,9 @@
cursor1 = cur1.execute("select * from Summary")
cursor2 = cur2.execute("select * from Summary")
for row in cursor1:
- data1 = [row[0], row[1], row[2], row[3], row[4], row[5]]
+ data1 = [row[0], row[1], row[2], row[3], row[6], row[7]]
for row in cursor2:
- data2 = [row[0], row[1], row[2], row[3], row[4], row[5]]
+ data2 = [row[0], row[1], row[2], row[3], row[6], row[7]]
text = ["Code size:", "RO data:", "RW data:",
"ZI data:", "Flash size:", "RAM size:"]
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()