Clone of official tools

Revision:
22:9e85236d8716
Parent:
13:ab47a20b66f0
Child:
24:25bff2709c20
--- a/memap.py	Fri Jul 15 22:58:15 2016 +0100
+++ b/memap.py	Sat Jul 16 00:34:03 2016 +0100
@@ -10,6 +10,7 @@
 import csv
 import json
 import argparse
+from utils import argparse_uppercase_type, argparse_lowercase_hyphen_type, argparse_filestring_type
 from prettytable import PrettyTable
 
 debug = False
@@ -26,9 +27,9 @@
 
         self.misc_flash_sections = ('.interrupts', '.flash_config')
 
-        self.other_sections = ('.interrupts_ram', '.init', '.ARM.extab', \
-                               '.ARM.exidx', '.ARM.attributes', '.eh_frame', \
-                               '.init_array', '.fini_array', '.jcr', '.stab', \
+        self.other_sections = ('.interrupts_ram', '.init', '.ARM.extab',
+                               '.ARM.exidx', '.ARM.attributes', '.eh_frame',
+                               '.init_array', '.fini_array', '.jcr', '.stab',
                                '.stabstr', '.ARM.exidx', '.ARM')
 
         # sections to print info (generic for all toolchains)
@@ -43,6 +44,9 @@
         # list of all object files and mappting to module names
         self.object_to_module = dict()
 
+        # Memory usage summary structure
+        self.mem_summary = dict()
+
     def module_add(self, module_name, size, section):
         """
         Adds a module / section to the list
@@ -67,7 +71,7 @@
                 return i  # should name of the section (assuming it's a known one)
 
         if line.startswith('.'):
-            return 'unknown'     # all others are clasified are unknown
+            return 'unknown'     # all others are classified are unknown
         else:
             return False         # everything else, means no change in section
 
@@ -336,6 +340,8 @@
                     else:
                         self.object_to_module.update({object_name:module_name})
 
+    export_formats = ["json", "csv-ci", "table"]
+
     def generate_output(self, export_format, file_output=None):
         """
         Generates summary of memory map data
@@ -363,11 +369,12 @@
 
         # Create table
         columns = ['Module']
-        for i in list(self.print_sections):
-            columns.append(i)
+        columns.extend(self.print_sections)
 
         table = PrettyTable(columns)
         table.align["Module"] = "l"
+        for col in self.print_sections:
+            table.align[col] = 'r'
 
         for i in list(self.print_sections):
             table.align[i] = 'r'
@@ -388,8 +395,12 @@
             for k in self.print_sections:
                 row.append(self.modules[i][k])
 
-            json_obj.append({"module":i, "size":{\
-                k:self.modules[i][k] for k in self.print_sections}})
+            json_obj.append({
+                "module":i,
+                "size":{
+                    k:self.modules[i][k] for k in self.print_sections
+                }
+            })
 
             table.add_row(row)
 
@@ -399,16 +410,19 @@
 
         table.add_row(subtotal_row)
 
+        summary = {
+            'summary':{
+                'static_ram':(subtotal['.data']+subtotal['.bss']),
+                'heap':(subtotal['.heap']),
+                'stack':(subtotal['.stack']),
+                'total_ram':(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']),
+                'total_flash':(subtotal['.text']+subtotal['.data']+misc_flash_mem),
+            }
+        }
+
         if export_format == 'json':
-            json_obj.append({\
-                  'summary':{\
-                  'total_static_ram':(subtotal['.data']+subtotal['.bss']),\
-                  'allocated_heap':(subtotal['.heap']),\
-                  'allocated_stack':(subtotal['.stack']),\
-                  'total_ram':(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']),\
-                  'total_flash':(subtotal['.text']+subtotal['.data']+misc_flash_mem),}})
-
-            file_desc.write(json.dumps(json_obj, indent=4))
+            json_to_file = json_obj + [summary]
+            file_desc.write(json.dumps(json_to_file, indent=4))
             file_desc.write('\n')
 
         elif export_format == 'csv-ci': # CSV format for the CI system
@@ -467,33 +481,40 @@
         if file_desc is not sys.stdout:
             file_desc.close()
 
+        self.mem_summary = json_obj + [summary]
+
         return True
 
+    def get_memory_summary(self):
+        """! Object is available only after self.generate_output('json') is called
+        @return Return memory summary object
+        """
+        return self.mem_summary
+
+    toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "IAR"]
+
     def parse(self, mapfile, toolchain):
         """
         Parse and decode map file depending on the toolchain
         """
 
+        result = True
         try:
-            file_input = open(mapfile, 'rt')
+            with open(mapfile, 'rt') as file_input:
+                if toolchain == "ARM" or toolchain == "ARM_STD" or toolchain == "ARM_MICRO":
+                    self.search_objects(os.path.abspath(mapfile), "ARM")
+                    self.parse_map_file_armcc(file_input)
+                elif toolchain == "GCC_ARM":
+                    self.parse_map_file_gcc(file_input)
+                elif toolchain == "IAR":
+                    self.search_objects(os.path.abspath(mapfile), toolchain)
+                    self.parse_map_file_iar(file_input)
+                else:
+                    result = False
         except IOError as error:
             print "I/O error({0}): {1}".format(error.errno, error.strerror)
-            return False
-
-        if toolchain == "ARM" or toolchain == "ARM_STD" or toolchain == "ARM_MICRO":
-            self.search_objects(os.path.abspath(mapfile), "ARM")
-            self.parse_map_file_armcc(file_input)
-        elif toolchain == "GCC_ARM":
-            self.parse_map_file_gcc(file_input)
-        elif toolchain == "IAR":
-            self.search_objects(os.path.abspath(mapfile), toolchain)
-            self.parse_map_file_iar(file_input)
-        else:
-            return False
-
-        file_input.close()
-
-        return True
+            result = False
+        return result
 
 def main():
 
@@ -502,15 +523,15 @@
     # Parser handling
     parser = argparse.ArgumentParser(description="Memory Map File Analyser for ARM mbed\nversion %s" % version)
 
-    parser.add_argument('file', help='memory map file')
+    parser.add_argument('file', type=argparse_filestring_type, help='memory map file')
 
-    parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (ARM, GCC_ARM, IAR)',\
-                        required=True)
+    parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (%s)' % ", ".join(MemapParser.toolchains),\
+                        required=True, type=argparse_uppercase_type(MemapParser.toolchains, "toolchain"))
 
     parser.add_argument('-o', '--output', help='output file name', required=False)
 
-    parser.add_argument('-e', '--export', dest='export', required=False,\
-                        help="export format (examples: 'json', 'csv-ci', 'table': default)")
+    parser.add_argument('-e', '--export', dest='export', required=False, default='table', type=argparse_lowercase_hyphen_type(MemapParser.export_formats,'export format'),\
+                        help="export format (examples: %s: default)" % ", ".join(MemapParser.export_formats))
 
     parser.add_argument('-v', '--version', action='version', version=version)
 
@@ -528,13 +549,8 @@
     # Parse and decode a map file
     if args.file and args.toolchain:
         if memap.parse(args.file, args.toolchain) is False:
-            print "Unknown toolchain for memory statistics %s" %  args.toolchain
             sys.exit(0)
 
-    # default export format is table
-    if not args.export:
-        args.export = 'table'
-
     # Write output in file
     if args.output != None:
         memap.generate_output(args.export, args.output)