~aleteoryx/muditaos

ref: sign_test muditaos/tools/find_global_data.py -rwxr-xr-x 5.6 KiB
a217eeb3 — Dawid Wojtas [BH-2024] Fix lack of alarm directory after updating software 1 year, 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env python3
"""
Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

detect static globals in code

@package globalFinder
"""

import argparse
import magic
import os
import re
import subprocess
import sys

from enum import Enum
from queue import Queue
from threading import Thread


class ArchType(Enum):
    """Define supported architecture types"""

    X86 = 1
    ARM = 2


class Finder():
    """Finds potential places where global can be.

    This class holds all necessary variables and is responsible for holding and
    presenting results.

    Attributes
    ----------
    elfPath : str
        path to inspected ELF
    arch : ArchType
        detected architecture
    objdump : str
        used `objdump` command (depends on arch)
    nm : str
        used `nm` command (depends on arch)
    sections : Queue
        stores list of sections with "StaticSymbol"
    resultsQueue : Queue
        stores found items, all threads are puting results here one result one item
    results : dict
        gathers results from `resultsQueue` used for counting items and printing report
    """

    armRe = re.compile("ELF 32-bit .*ARM.*")
    x86Re = re.compile("ELF (64|32)-bit .*x86.*")
    staticSymbol = "_Z41__static_initialization_and_destruction_0ii"
    staticRe = re.compile("([0-9a-fA-F]+) ([0-9a-fA-F]+) .*" + staticSymbol + ".*")

    def __init__(self, path):
        """
        Parameters
        ----------
        path : str
            path to elf that will be inspected
        """

        self.elfPath = path
        self.arch = None
        self.objdump = None
        self.nm = None
        self.sections = Queue()
        self.resultsQueue = Queue()
        self.results = {}

    def checkArch(self):
        """Detect elf architecture"""

        magicString = magic.from_file(self.elfPath)
        if self.x86Re.match(magicString):
            self.arch = ArchType.X86
            self.objdump = "objdump"
            self.nm = "nm"
        elif self.armRe.match(magicString):
            self.arch = ArchType.ARM
            self.objdump = "arm-none-eabi-objdump"
            self.nm = "arm-none-eabi-nm"
        else:
            self.arch = None

    def findStatic(self):
        """find sections with static initialization symbol"""

        print("searching for statics")
        out = subprocess.run([self.nm, "--print-size", self.elfPath], capture_output=True, text=True)
        lines = out.stdout.split('\n')
        for line in lines:
            match = self.staticRe.match(line)
            if match:
                startAddress = int(match.group(1), 16)
                sectionSize = int(match.group(2), 16)
                endAddress = startAddress + sectionSize
                self.sections.put(("0x%x" % startAddress, "0x%x" % endAddress))

    def countResults(self):
        """Count found items"""

        while not self.resultsQueue.empty():
            path, lineNo = self.resultsQueue.get()
            realpath = os.path.realpath(path)
            key = realpath + ":" + lineNo
            if key not in self.results:
                self.results[key] = 1
            else:
                self.results[key] += 1


class StaticChecker(Thread):
    """Checks if found sections contain static symbols.

    This calass runs in separate processes objdump, deasembles section and search for hpp file.
    if found such place is logged.

    Attributes
    ----------

    finder : Finder
        access communication queues, and all other needed variables
    hppRegexp : re
        regexp for detecting hpp files
    """

    hppRegexp = re.compile("(.*\.hpp):([0-9]+)")

    def __init__(self, finder):
        """
        Parameters
        ----------

        finder : Finder
            Finder object to work with
        """

        Thread.__init__(self)
        self.finder = finder

    def run(self):
        while True:
            print("-thread start:", self.native_id, self.finder.sections.qsize())
            if not self.finder.sections.empty():
                startAddress, stopAddress = self.finder.sections.get()
                try:
                    out = subprocess.run([self.finder.objdump,
                                          "--start-address="+startAddress,
                                          "--stop-address="+stopAddress,
                                          "-d", "-l",
                                          self.finder.elfPath
                                          ],
                                         capture_output=True, text=True)
                    for line in out.stdout.split('\n'):
                        reMatch = self.hppRegexp.match(line)
                        if reMatch:
                            self.finder.resultsQueue.put((reMatch.group(1), reMatch.group(2)))
                            print(" ", reMatch.group(1), reMatch.group(2))
                finally:
                    self.finder.sections.task_done()
            else:
                return


def main():
    parser = argparse.ArgumentParser(description="Find globals in code")
    parser.add_argument('elfPath', help="Path to elf file")
    args = parser.parse_args()
    finder = Finder(args.elfPath)
    finder.checkArch()
    finder.findStatic()
    cpuCount = os.cpu_count()
    if cpuCount is None:
        cpuCount = 2
    for _ in range(cpuCount):
        staticChecker = StaticChecker(finder)
        staticChecker.daemon = True
        staticChecker.start()
    finder.sections.join()
    finder.countResults()
    if len(finder.results) >= 1:
        print(finder.results)
        sys.exit(1)


if __name__ == "__main__":
    main()