• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4#
5# Copyright (c) 2022 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import sys
20import argparse
21import os
22import platform
23import subprocess
24import stat
25
26
27def gen_symbols(tmp_file, sort_lines, symbols_path):
28    modes = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP
29    with os.fdopen(os.open(tmp_file, os.O_RDWR | os.O_CREAT, modes), 'w', encoding='utf-8') as output_file:
30        for item in sort_lines:
31            output_file.write('{}\n'.format(item))
32
33    with os.fdopen(os.open(symbols_path, os.O_RDWR | os.O_CREAT, modes), 'w', encoding='utf-8') as output_file:
34        cmd = 'sort {}'.format(tmp_file)
35        subprocess.run(cmd.split(), stdout=output_file)
36
37
38def create_mini_debug_info(binary_path, stripped_binary_path, root_path, clang_base_dir, adlt_llvm_tool):
39    # temporary file path
40    dynsyms_path = stripped_binary_path + ".dynsyms"
41    funcsysms_path = stripped_binary_path + ".funcsyms"
42    keep_path = stripped_binary_path + ".keep"
43    debug_path = stripped_binary_path + ".debug"
44    mini_debug_path = stripped_binary_path + ".minidebug"
45
46    # llvm tools path
47    host_platform = platform.uname().system.lower()
48    host_cpu = platform.uname().machine.lower()
49    llvm_dir_path = os.path.join(
50        clang_base_dir, host_platform + '-' + host_cpu, 'llvm/bin')
51    if not os.path.exists(llvm_dir_path):
52        llvm_dir_path = os.path.join(root_path, 'out/llvm-install/bin')
53    if adlt_llvm_tool:
54        llvm_dir_path = adlt_llvm_tool
55    llvm_nm_path = os.path.join(llvm_dir_path, "llvm-nm")
56    llvm_objcopy_path = os.path.join(llvm_dir_path, "llvm-objcopy")
57
58    cmd_list = []
59
60    gen_symbols_cmd = llvm_nm_path + " -D " + binary_path + " --format=posix --defined-only"
61    gen_func_symbols_cmd = llvm_nm_path + " " + binary_path + " --format=posix --defined-only"
62    gen_keep_symbols_cmd = "comm -13 " + dynsyms_path + " " + funcsysms_path
63    gen_keep_debug_cmd = llvm_objcopy_path + \
64        " --only-keep-debug " + binary_path + " " + debug_path
65    gen_mini_debug_cmd = llvm_objcopy_path + " -S --remove-section .gdb_index --remove-section .comment --keep-symbols=" + \
66        keep_path + " " + debug_path + " " + mini_debug_path
67    compress_debuginfo = "xz " + mini_debug_path
68    gen_stripped_binary = llvm_objcopy_path + " --add-section .gnu_debugdata=" + \
69        mini_debug_path + ".xz " + stripped_binary_path
70
71
72    tmp_file1 = '{}.tmp1'.format(dynsyms_path)
73    tmp_file2 = '{}.tmp2'.format(dynsyms_path)
74    modes = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP
75    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT, modes), 'w', encoding='utf-8') as output_file:
76        subprocess.run(gen_symbols_cmd.split(), stdout=output_file)
77
78    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT, modes), 'r', encoding='utf-8') as output_file:
79        lines = output_file.readlines()
80        sort_lines = []
81        for line in lines:
82            columns = line.strip().split()
83            if columns:
84                sort_lines.append(columns[0])
85
86    gen_symbols(tmp_file2, sort_lines, dynsyms_path)
87    os.remove(tmp_file1)
88    os.remove(tmp_file2)
89
90
91    tmp_file1 = '{}.tmp1'.format(funcsysms_path)
92    tmp_file2 = '{}.tmp2'.format(funcsysms_path)
93    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT, modes), 'w', encoding='utf-8') as output_file:
94        subprocess.run(gen_func_symbols_cmd.split(), stdout=output_file)
95
96    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT, modes), 'r', encoding='utf-8') as output_file:
97        lines = output_file.readlines()
98        sort_lines = []
99        for line in lines:
100            columns = line.strip().split()
101            if len(columns) > 2 and ('t' in columns[1] or 'T' in columns[1] or 'd' in columns[1]):
102                sort_lines.append(columns[0])
103
104    gen_symbols(tmp_file2, sort_lines, funcsysms_path)
105    os.remove(tmp_file1)
106    os.remove(tmp_file2)
107
108
109    with os.fdopen(os.open(keep_path, os.O_RDWR | os.O_CREAT, modes), 'w', encoding='utf-8') as output_file:
110        subprocess.run(gen_keep_symbols_cmd.split(), stdout=output_file)
111
112
113    cmd_list.append(gen_keep_debug_cmd)
114    cmd_list.append(gen_mini_debug_cmd)
115    cmd_list.append(compress_debuginfo)
116    cmd_list.append(gen_stripped_binary)
117
118    # execute each cmd to generate temporary file
119    # which .gnu_debugdata section depends on
120    for cmd in cmd_list:
121        subprocess.call(cmd.split(), shell=False)
122
123    # remove temporary file
124    os.remove(dynsyms_path)
125    os.remove(funcsysms_path)
126    os.remove(keep_path)
127    os.remove(debug_path)
128    os.remove(mini_debug_path + ".xz")
129
130
131def main():
132    parser = argparse.ArgumentParser(description=__doc__)
133    parser.add_argument("--unstripped-path",
134                        help="unstripped binary path")
135    parser.add_argument("--stripped-path",
136                        help="stripped binary path")
137    parser.add_argument("--root-path",
138                        help="root path is used to search llvm toolchain")
139    parser.add_argument("--clang-base-dir", help="")
140    parser.add_argument("--adlt-llvm-tool", help="")
141    args = parser.parse_args()
142
143    create_mini_debug_info(args.unstripped_path,
144                           args.stripped_path, args.root_path, args.clang_base_dir, args.adlt_llvm_tool)
145
146
147if __name__ == "__main__":
148    sys.exit(main())
149