xref: /aosp_15_r20/art/tools/runtime_memusage/symbol_trace_info.py (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/env python
2*795d594fSAndroid Build Coastguard Worker#
3*795d594fSAndroid Build Coastguard Worker# Copyright (C) 2017 The Android Open Source Project
4*795d594fSAndroid Build Coastguard Worker#
5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*795d594fSAndroid Build Coastguard Worker#
9*795d594fSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*795d594fSAndroid Build Coastguard Worker#
11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*795d594fSAndroid Build Coastguard Worker# limitations under the License.
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker"""Outputs quantitative information about Address Sanitizer traces."""
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Workerfrom __future__ import absolute_import
20*795d594fSAndroid Build Coastguard Workerfrom __future__ import division
21*795d594fSAndroid Build Coastguard Workerfrom __future__ import print_function
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Workerfrom collections import Counter
24*795d594fSAndroid Build Coastguard Workerfrom datetime import datetime
25*795d594fSAndroid Build Coastguard Workerimport argparse
26*795d594fSAndroid Build Coastguard Workerimport bisect
27*795d594fSAndroid Build Coastguard Workerimport os
28*795d594fSAndroid Build Coastguard Workerimport re
29*795d594fSAndroid Build Coastguard Worker
30*795d594fSAndroid Build Coastguard Worker
31*795d594fSAndroid Build Coastguard Workerdef find_match(list_substrings, big_string):
32*795d594fSAndroid Build Coastguard Worker    """Returns the category a trace belongs to by searching substrings."""
33*795d594fSAndroid Build Coastguard Worker    for ind, substr in enumerate(list_substrings):
34*795d594fSAndroid Build Coastguard Worker        if big_string.find(substr) != -1:
35*795d594fSAndroid Build Coastguard Worker            return ind
36*795d594fSAndroid Build Coastguard Worker    return list_substrings.index("Uncategorized")
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker
39*795d594fSAndroid Build Coastguard Workerdef absolute_to_relative(data_lists, symbol_traces):
40*795d594fSAndroid Build Coastguard Worker    """Address changed to Dex File offset and shifting time to 0 min in ms."""
41*795d594fSAndroid Build Coastguard Worker
42*795d594fSAndroid Build Coastguard Worker    offsets = data_lists["offsets"]
43*795d594fSAndroid Build Coastguard Worker    time_offsets = data_lists["times"]
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker    # Format of time provided by logcat
46*795d594fSAndroid Build Coastguard Worker    time_format_str = "%H:%M:%S.%f"
47*795d594fSAndroid Build Coastguard Worker    first_access_time = datetime.strptime(data_lists["plot_list"][0][0],
48*795d594fSAndroid Build Coastguard Worker                                          time_format_str)
49*795d594fSAndroid Build Coastguard Worker    for ind, elem in enumerate(data_lists["plot_list"]):
50*795d594fSAndroid Build Coastguard Worker        elem_date_time = datetime.strptime(elem[0], time_format_str)
51*795d594fSAndroid Build Coastguard Worker        # Shift time values so that first access is at time 0 milliseconds
52*795d594fSAndroid Build Coastguard Worker        elem[0] = int((elem_date_time - first_access_time).total_seconds() *
53*795d594fSAndroid Build Coastguard Worker                      1000)
54*795d594fSAndroid Build Coastguard Worker        address_access = int(elem[1], 16)
55*795d594fSAndroid Build Coastguard Worker        # For each poisoned address, find highest Dex File starting address less
56*795d594fSAndroid Build Coastguard Worker        # than address_access
57*795d594fSAndroid Build Coastguard Worker        dex_start_list, dex_size_list = zip(*data_lists["dex_ends_list"])
58*795d594fSAndroid Build Coastguard Worker        dex_file_ind = bisect.bisect(dex_start_list, address_access) - 1
59*795d594fSAndroid Build Coastguard Worker        dex_offset = address_access - dex_start_list[dex_file_ind]
60*795d594fSAndroid Build Coastguard Worker        # Assumes that offsets is already sorted and constrains offset to be
61*795d594fSAndroid Build Coastguard Worker        # within range of the dex_file
62*795d594fSAndroid Build Coastguard Worker        max_offset = min(offsets[1], dex_size_list[dex_file_ind])
63*795d594fSAndroid Build Coastguard Worker        # Meant to nullify data that does not meet offset criteria if specified
64*795d594fSAndroid Build Coastguard Worker        if (dex_offset >= offsets[0] and dex_offset < max_offset and
65*795d594fSAndroid Build Coastguard Worker                elem[0] >= time_offsets[0] and elem[0] < time_offsets[1]):
66*795d594fSAndroid Build Coastguard Worker
67*795d594fSAndroid Build Coastguard Worker            elem.insert(1, dex_offset)
68*795d594fSAndroid Build Coastguard Worker            # Category that a data point belongs to
69*795d594fSAndroid Build Coastguard Worker            elem.insert(2, data_lists["cat_list"][ind])
70*795d594fSAndroid Build Coastguard Worker        else:
71*795d594fSAndroid Build Coastguard Worker            elem[:] = 4 * [None]
72*795d594fSAndroid Build Coastguard Worker            symbol_traces[ind] = None
73*795d594fSAndroid Build Coastguard Worker            data_lists["cat_list"][ind] = None
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker
76*795d594fSAndroid Build Coastguard Workerdef print_category_info(cat_split, outname, out_dir_name, title):
77*795d594fSAndroid Build Coastguard Worker    """Prints information of category and puts related traces in a files."""
78*795d594fSAndroid Build Coastguard Worker    trace_counts_dict = Counter(cat_split)
79*795d594fSAndroid Build Coastguard Worker    trace_counts_list_ordered = trace_counts_dict.most_common()
80*795d594fSAndroid Build Coastguard Worker    print(53 * "-")
81*795d594fSAndroid Build Coastguard Worker    print(title)
82*795d594fSAndroid Build Coastguard Worker    print("\tNumber of distinct traces: " +
83*795d594fSAndroid Build Coastguard Worker          str(len(trace_counts_list_ordered)))
84*795d594fSAndroid Build Coastguard Worker    print("\tSum of trace counts: " +
85*795d594fSAndroid Build Coastguard Worker          str(sum([trace[1] for trace in trace_counts_list_ordered])))
86*795d594fSAndroid Build Coastguard Worker    print("\n\tCount: How many traces appeared with count\n\t", end="")
87*795d594fSAndroid Build Coastguard Worker    print(Counter([trace[1] for trace in trace_counts_list_ordered]))
88*795d594fSAndroid Build Coastguard Worker    with open(os.path.join(out_dir_name, outname), "w") as output_file:
89*795d594fSAndroid Build Coastguard Worker        for trace in trace_counts_list_ordered:
90*795d594fSAndroid Build Coastguard Worker            output_file.write("\n\nNumber of times appeared: " +
91*795d594fSAndroid Build Coastguard Worker                              str(trace[1]) +
92*795d594fSAndroid Build Coastguard Worker                              "\n")
93*795d594fSAndroid Build Coastguard Worker            output_file.write(trace[0].strip())
94*795d594fSAndroid Build Coastguard Worker
95*795d594fSAndroid Build Coastguard Worker
96*795d594fSAndroid Build Coastguard Workerdef print_categories(categories, symbol_file_split, out_dir_name):
97*795d594fSAndroid Build Coastguard Worker    """Prints details of all categories."""
98*795d594fSAndroid Build Coastguard Worker    symbol_file_split = [trace for trace in symbol_file_split
99*795d594fSAndroid Build Coastguard Worker                         if trace is not None]
100*795d594fSAndroid Build Coastguard Worker    # Info of traces containing a call to current category
101*795d594fSAndroid Build Coastguard Worker    for cat_num, cat_name in enumerate(categories[1:]):
102*795d594fSAndroid Build Coastguard Worker        print("\nCategory #%d" % (cat_num + 1))
103*795d594fSAndroid Build Coastguard Worker        cat_split = [trace for trace in symbol_file_split
104*795d594fSAndroid Build Coastguard Worker                     if cat_name in trace]
105*795d594fSAndroid Build Coastguard Worker        cat_file_name = cat_name.lower() + "cat_output"
106*795d594fSAndroid Build Coastguard Worker        print_category_info(cat_split, cat_file_name, out_dir_name,
107*795d594fSAndroid Build Coastguard Worker                            "Traces containing: " + cat_name)
108*795d594fSAndroid Build Coastguard Worker        noncat_split = [trace for trace in symbol_file_split
109*795d594fSAndroid Build Coastguard Worker                        if cat_name not in trace]
110*795d594fSAndroid Build Coastguard Worker        print_category_info(noncat_split, "non" + cat_file_name,
111*795d594fSAndroid Build Coastguard Worker                            out_dir_name,
112*795d594fSAndroid Build Coastguard Worker                            "Traces not containing: " +
113*795d594fSAndroid Build Coastguard Worker                            cat_name)
114*795d594fSAndroid Build Coastguard Worker
115*795d594fSAndroid Build Coastguard Worker    # All traces (including uncategorized) together
116*795d594fSAndroid Build Coastguard Worker    print_category_info(symbol_file_split, "allcat_output",
117*795d594fSAndroid Build Coastguard Worker                        out_dir_name,
118*795d594fSAndroid Build Coastguard Worker                        "All traces together:")
119*795d594fSAndroid Build Coastguard Worker    # Traces containing none of keywords
120*795d594fSAndroid Build Coastguard Worker    # Only used if categories are passed in
121*795d594fSAndroid Build Coastguard Worker    if len(categories) > 1:
122*795d594fSAndroid Build Coastguard Worker        noncat_split = [trace for trace in symbol_file_split if
123*795d594fSAndroid Build Coastguard Worker                        all(cat_name not in trace
124*795d594fSAndroid Build Coastguard Worker                            for cat_name in categories)]
125*795d594fSAndroid Build Coastguard Worker        print_category_info(noncat_split, "noncat_output",
126*795d594fSAndroid Build Coastguard Worker                            out_dir_name,
127*795d594fSAndroid Build Coastguard Worker                            "Uncategorized calls")
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Worker
130*795d594fSAndroid Build Coastguard Workerdef is_directory(path_name):
131*795d594fSAndroid Build Coastguard Worker    """Checks if a path is an actual directory."""
132*795d594fSAndroid Build Coastguard Worker    if not os.path.isdir(path_name):
133*795d594fSAndroid Build Coastguard Worker        dir_error = "%s is not a directory" % (path_name)
134*795d594fSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError(dir_error)
135*795d594fSAndroid Build Coastguard Worker    return path_name
136*795d594fSAndroid Build Coastguard Worker
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Workerdef parse_args(argv):
139*795d594fSAndroid Build Coastguard Worker    """Parses arguments passed in."""
140*795d594fSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
141*795d594fSAndroid Build Coastguard Worker    parser.add_argument("-d", action="store",
142*795d594fSAndroid Build Coastguard Worker                        default="", dest="out_dir_name", type=is_directory,
143*795d594fSAndroid Build Coastguard Worker                        help="Output Directory")
144*795d594fSAndroid Build Coastguard Worker    parser.add_argument("--dex-file", action="store",
145*795d594fSAndroid Build Coastguard Worker                        default=None, dest="dex_file",
146*795d594fSAndroid Build Coastguard Worker                        type=argparse.FileType("r"),
147*795d594fSAndroid Build Coastguard Worker                        help="Baksmali Dex File Dump")
148*795d594fSAndroid Build Coastguard Worker    parser.add_argument("--offsets", action="store", nargs=2,
149*795d594fSAndroid Build Coastguard Worker                        default=[float(0), float("inf")],
150*795d594fSAndroid Build Coastguard Worker                        dest="offsets",
151*795d594fSAndroid Build Coastguard Worker                        metavar="OFFSET",
152*795d594fSAndroid Build Coastguard Worker                        type=float,
153*795d594fSAndroid Build Coastguard Worker                        help="Filters out accesses not between provided"
154*795d594fSAndroid Build Coastguard Worker                             " offsets if provided. Can provide 'inf'"
155*795d594fSAndroid Build Coastguard Worker                             " for infinity")
156*795d594fSAndroid Build Coastguard Worker    parser.add_argument("--times", action="store", nargs=2,
157*795d594fSAndroid Build Coastguard Worker                        default=[float(0), float("inf")],
158*795d594fSAndroid Build Coastguard Worker                        dest="times",
159*795d594fSAndroid Build Coastguard Worker                        metavar="TIME",
160*795d594fSAndroid Build Coastguard Worker                        type=float,
161*795d594fSAndroid Build Coastguard Worker                        help="Filters out accesses not between provided"
162*795d594fSAndroid Build Coastguard Worker                             " time offsets if provided. Can provide 'inf'"
163*795d594fSAndroid Build Coastguard Worker                             " for infinity")
164*795d594fSAndroid Build Coastguard Worker    parser.add_argument("sanitizer_trace", action="store",
165*795d594fSAndroid Build Coastguard Worker                        type=argparse.FileType("r"),
166*795d594fSAndroid Build Coastguard Worker                        help="File containing sanitizer traces filtered by "
167*795d594fSAndroid Build Coastguard Worker                             "prune_sanitizer_output.py")
168*795d594fSAndroid Build Coastguard Worker    parser.add_argument("symbol_trace", action="store",
169*795d594fSAndroid Build Coastguard Worker                        type=argparse.FileType("r"),
170*795d594fSAndroid Build Coastguard Worker                        help="File containing symbolized traces that match "
171*795d594fSAndroid Build Coastguard Worker                             "sanitizer_trace")
172*795d594fSAndroid Build Coastguard Worker    parser.add_argument("dex_starts", action="store",
173*795d594fSAndroid Build Coastguard Worker                        type=argparse.FileType("r"),
174*795d594fSAndroid Build Coastguard Worker                        help="File containing starting addresses of Dex Files")
175*795d594fSAndroid Build Coastguard Worker    parser.add_argument("categories", action="store", nargs="*",
176*795d594fSAndroid Build Coastguard Worker                        help="Keywords expected to show in large amounts of"
177*795d594fSAndroid Build Coastguard Worker                             " symbolized traces")
178*795d594fSAndroid Build Coastguard Worker
179*795d594fSAndroid Build Coastguard Worker    return parser.parse_args(argv)
180*795d594fSAndroid Build Coastguard Worker
181*795d594fSAndroid Build Coastguard Worker
182*795d594fSAndroid Build Coastguard Workerdef get_dex_offset_data(line, dex_file_item):
183*795d594fSAndroid Build Coastguard Worker    """ Returns a tuple of dex file offset, item name, and data of a line."""
184*795d594fSAndroid Build Coastguard Worker    return (int(line[:line.find(":")], 16),
185*795d594fSAndroid Build Coastguard Worker            (dex_file_item,
186*795d594fSAndroid Build Coastguard Worker             line.split("|")[1].strip())
187*795d594fSAndroid Build Coastguard Worker            )
188*795d594fSAndroid Build Coastguard Worker
189*795d594fSAndroid Build Coastguard Worker
190*795d594fSAndroid Build Coastguard Workerdef read_data(parsed_argv):
191*795d594fSAndroid Build Coastguard Worker    """Reads data from filepath arguments and parses them into lists."""
192*795d594fSAndroid Build Coastguard Worker    # Using a dictionary to establish relation between lists added
193*795d594fSAndroid Build Coastguard Worker    data_lists = {}
194*795d594fSAndroid Build Coastguard Worker    categories = parsed_argv.categories
195*795d594fSAndroid Build Coastguard Worker    # Makes sure each trace maps to some category
196*795d594fSAndroid Build Coastguard Worker    categories.insert(0, "Uncategorized")
197*795d594fSAndroid Build Coastguard Worker
198*795d594fSAndroid Build Coastguard Worker    data_lists["offsets"] = parsed_argv.offsets
199*795d594fSAndroid Build Coastguard Worker    data_lists["offsets"].sort()
200*795d594fSAndroid Build Coastguard Worker
201*795d594fSAndroid Build Coastguard Worker    data_lists["times"] = parsed_argv.times
202*795d594fSAndroid Build Coastguard Worker    data_lists["times"].sort()
203*795d594fSAndroid Build Coastguard Worker
204*795d594fSAndroid Build Coastguard Worker    logcat_file_data = parsed_argv.sanitizer_trace.readlines()
205*795d594fSAndroid Build Coastguard Worker    parsed_argv.sanitizer_trace.close()
206*795d594fSAndroid Build Coastguard Worker
207*795d594fSAndroid Build Coastguard Worker    symbol_file_split = parsed_argv.symbol_trace.read().split("Stack Trace")
208*795d594fSAndroid Build Coastguard Worker    # Removes text before first trace
209*795d594fSAndroid Build Coastguard Worker    symbol_file_split = symbol_file_split[1:]
210*795d594fSAndroid Build Coastguard Worker    parsed_argv.symbol_trace.close()
211*795d594fSAndroid Build Coastguard Worker
212*795d594fSAndroid Build Coastguard Worker    dex_start_file_data = parsed_argv.dex_starts.readlines()
213*795d594fSAndroid Build Coastguard Worker    parsed_argv.dex_starts.close()
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard Worker    if parsed_argv.dex_file is not None:
216*795d594fSAndroid Build Coastguard Worker        dex_file_data = parsed_argv.dex_file.read()
217*795d594fSAndroid Build Coastguard Worker        parsed_argv.dex_file.close()
218*795d594fSAndroid Build Coastguard Worker        # Splits baksmali dump by each item
219*795d594fSAndroid Build Coastguard Worker        item_split = [s.splitlines() for s in re.split(r"\|\[[0-9]+\] ",
220*795d594fSAndroid Build Coastguard Worker                                                       dex_file_data)]
221*795d594fSAndroid Build Coastguard Worker        # Splits each item by line and creates a list of offsets and a
222*795d594fSAndroid Build Coastguard Worker        # corresponding list of the data associated with that line
223*795d594fSAndroid Build Coastguard Worker        offset_list, offset_data = zip(*[get_dex_offset_data(line, item[0])
224*795d594fSAndroid Build Coastguard Worker                                         for item in item_split
225*795d594fSAndroid Build Coastguard Worker                                         for line in item[1:]
226*795d594fSAndroid Build Coastguard Worker                                         if re.search("[0-9a-f]{6}:", line)
227*795d594fSAndroid Build Coastguard Worker                                         is not None and
228*795d594fSAndroid Build Coastguard Worker                                         line.find("|") != -1])
229*795d594fSAndroid Build Coastguard Worker        data_lists["offset_list"] = offset_list
230*795d594fSAndroid Build Coastguard Worker        data_lists["offset_data"] = offset_data
231*795d594fSAndroid Build Coastguard Worker    else:
232*795d594fSAndroid Build Coastguard Worker        dex_file_data = None
233*795d594fSAndroid Build Coastguard Worker
234*795d594fSAndroid Build Coastguard Worker    # Each element is a tuple of time and address accessed
235*795d594fSAndroid Build Coastguard Worker    data_lists["plot_list"] = [[elem[1] for elem in enumerate(line.split())
236*795d594fSAndroid Build Coastguard Worker                                if elem[0] in (1, 11)
237*795d594fSAndroid Build Coastguard Worker                                ]
238*795d594fSAndroid Build Coastguard Worker                               for line in logcat_file_data
239*795d594fSAndroid Build Coastguard Worker                               if "use-after-poison" in line or
240*795d594fSAndroid Build Coastguard Worker                               "unknown-crash" in line
241*795d594fSAndroid Build Coastguard Worker                               ]
242*795d594fSAndroid Build Coastguard Worker    # Contains a mapping between traces and the category they belong to
243*795d594fSAndroid Build Coastguard Worker    # based on arguments
244*795d594fSAndroid Build Coastguard Worker    data_lists["cat_list"] = [categories[find_match(categories, trace)]
245*795d594fSAndroid Build Coastguard Worker                              for trace in symbol_file_split]
246*795d594fSAndroid Build Coastguard Worker
247*795d594fSAndroid Build Coastguard Worker    # Contains a list of starting address of all dex files to calculate dex
248*795d594fSAndroid Build Coastguard Worker    # offsets
249*795d594fSAndroid Build Coastguard Worker    data_lists["dex_ends_list"] = [(int(line.split()[9], 16),
250*795d594fSAndroid Build Coastguard Worker                                    int(line.split()[12])
251*795d594fSAndroid Build Coastguard Worker                                    )
252*795d594fSAndroid Build Coastguard Worker                                   for line in dex_start_file_data
253*795d594fSAndroid Build Coastguard Worker                                   if "RegisterDexFile" in line
254*795d594fSAndroid Build Coastguard Worker                                   ]
255*795d594fSAndroid Build Coastguard Worker    # Dex File Starting addresses must be sorted because bisect requires sorted
256*795d594fSAndroid Build Coastguard Worker    # lists.
257*795d594fSAndroid Build Coastguard Worker    data_lists["dex_ends_list"].sort()
258*795d594fSAndroid Build Coastguard Worker
259*795d594fSAndroid Build Coastguard Worker    return data_lists, categories, symbol_file_split
260*795d594fSAndroid Build Coastguard Worker
261*795d594fSAndroid Build Coastguard Worker
262*795d594fSAndroid Build Coastguard Workerdef main():
263*795d594fSAndroid Build Coastguard Worker    """Takes in trace information and outputs details about them."""
264*795d594fSAndroid Build Coastguard Worker    parsed_argv = parse_args(None)
265*795d594fSAndroid Build Coastguard Worker    data_lists, categories, symbol_file_split = read_data(parsed_argv)
266*795d594fSAndroid Build Coastguard Worker
267*795d594fSAndroid Build Coastguard Worker    # Formats plot_list such that each element is a data point
268*795d594fSAndroid Build Coastguard Worker    absolute_to_relative(data_lists, symbol_file_split)
269*795d594fSAndroid Build Coastguard Worker    for file_ext, cat_name in enumerate(categories):
270*795d594fSAndroid Build Coastguard Worker        out_file_name = os.path.join(parsed_argv.out_dir_name, "time_output_" +
271*795d594fSAndroid Build Coastguard Worker                                     str(file_ext) +
272*795d594fSAndroid Build Coastguard Worker                                     ".dat")
273*795d594fSAndroid Build Coastguard Worker        with open(out_file_name, "w") as output_file:
274*795d594fSAndroid Build Coastguard Worker            output_file.write("# Category: " + cat_name + "\n")
275*795d594fSAndroid Build Coastguard Worker            output_file.write("# Time, Dex File Offset_10, Dex File Offset_16,"
276*795d594fSAndroid Build Coastguard Worker                              " Address, Item Accessed, Item Member Accessed"
277*795d594fSAndroid Build Coastguard Worker                              " Unaligned\n")
278*795d594fSAndroid Build Coastguard Worker            for time, dex_offset, category, address in data_lists["plot_list"]:
279*795d594fSAndroid Build Coastguard Worker                if category == cat_name:
280*795d594fSAndroid Build Coastguard Worker                    output_file.write(
281*795d594fSAndroid Build Coastguard Worker                        str(time) +
282*795d594fSAndroid Build Coastguard Worker                        " " +
283*795d594fSAndroid Build Coastguard Worker                        str(dex_offset) +
284*795d594fSAndroid Build Coastguard Worker                        " #" +
285*795d594fSAndroid Build Coastguard Worker                        hex(dex_offset) +
286*795d594fSAndroid Build Coastguard Worker                        " " +
287*795d594fSAndroid Build Coastguard Worker                        str(address))
288*795d594fSAndroid Build Coastguard Worker                    if "offset_list" in data_lists:
289*795d594fSAndroid Build Coastguard Worker                        dex_offset_index = bisect.bisect(
290*795d594fSAndroid Build Coastguard Worker                            data_lists["offset_list"],
291*795d594fSAndroid Build Coastguard Worker                            dex_offset) - 1
292*795d594fSAndroid Build Coastguard Worker                        aligned_dex_offset = (data_lists["offset_list"]
293*795d594fSAndroid Build Coastguard Worker                                                        [dex_offset_index])
294*795d594fSAndroid Build Coastguard Worker                        dex_offset_data = (data_lists["offset_data"]
295*795d594fSAndroid Build Coastguard Worker                                                     [dex_offset_index])
296*795d594fSAndroid Build Coastguard Worker                        output_file.write(
297*795d594fSAndroid Build Coastguard Worker                            " " +
298*795d594fSAndroid Build Coastguard Worker                            "|".join(dex_offset_data) +
299*795d594fSAndroid Build Coastguard Worker                            " " +
300*795d594fSAndroid Build Coastguard Worker                            str(aligned_dex_offset != dex_offset))
301*795d594fSAndroid Build Coastguard Worker                    output_file.write("\n")
302*795d594fSAndroid Build Coastguard Worker    print_categories(categories, symbol_file_split, parsed_argv.out_dir_name)
303*795d594fSAndroid Build Coastguard Worker
304*795d594fSAndroid Build Coastguard Worker
305*795d594fSAndroid Build Coastguard Workerif __name__ == "__main__":
306*795d594fSAndroid Build Coastguard Worker    main()
307