• 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
24
25
26def gen_symbols(tmp_file, sort_lines, symbols_path):
27    with os.fdopen(os.open(tmp_file, os.O_RDWR | os.O_CREAT), 'w', encoding='utf-8') as output_file:
28        for item in sort_lines:
29            output_file.write('{}\n'.format(item))
30
31    with os.fdopen(os.open(symbols_path, os.O_RDWR | os.O_CREAT), 'w', encoding='utf-8') as output_file:
32        cmd = 'sort {}'.format(tmp_file)
33        subprocess.run(cmd.split(), stdout=output_file)
34
35
36def create_mini_debug_info(binary_path, stripped_binary_path, root_path, clang_base_dir):
37    # temporary file path
38    dynsyms_path = stripped_binary_path + ".dynsyms"
39    funcsysms_path = stripped_binary_path + ".funcsyms"
40    keep_path = stripped_binary_path + ".keep"
41    debug_path = stripped_binary_path + ".debug"
42    mini_debug_path = stripped_binary_path + ".minidebug"
43
44    # llvm tools path
45    host_platform = platform.uname().system.lower()
46    host_cpu = platform.uname().machine.lower()
47    llvm_dir_path = os.path.join(
48        clang_base_dir, host_platform + '-' + host_cpu, 'llvm/bin')
49    if not os.path.exists(llvm_dir_path):
50        llvm_dir_path = os.path.join(root_path, 'out/llvm-install/bin')
51    llvm_nm_path = os.path.join(llvm_dir_path, "llvm-nm")
52    llvm_objcopy_path = os.path.join(llvm_dir_path, "llvm-objcopy")
53
54    cmd_list = []
55
56    gen_symbols_cmd = llvm_nm_path + " -D " + binary_path + " --format=posix --defined-only"
57    gen_func_symbols_cmd = llvm_nm_path + " " + binary_path + " --format=posix --defined-only"
58    gen_keep_symbols_cmd = "comm -13 " + dynsyms_path + " " + funcsysms_path
59    gen_keep_debug_cmd = llvm_objcopy_path + \
60        " --only-keep-debug " + binary_path + " " + debug_path
61    gen_mini_debug_cmd = llvm_objcopy_path + " -S --remove-section .gbd_index --remove-section .comment --keep-symbols=" + \
62        keep_path + " " + debug_path + " " + mini_debug_path
63    compress_debuginfo = "xz " + mini_debug_path
64    gen_stripped_binary = llvm_objcopy_path + " --add-section .gnu_debugdata=" + \
65        mini_debug_path + ".xz " + stripped_binary_path
66
67
68    tmp_file1 = '{}.tmp1'.format(dynsyms_path)
69    tmp_file2 = '{}.tmp2'.format(dynsyms_path)
70    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT), 'w', encoding='utf-8') as output_file:
71        subprocess.run(gen_symbols_cmd.split(), stdout=output_file)
72
73    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT), 'r', encoding='utf-8') as output_file:
74        lines = output_file.readlines()
75        sort_lines = []
76        for line in lines:
77            columns = line.strip().split()
78            if columns:
79                sort_lines.append(columns[0])
80
81    gen_symbols(tmp_file2, sort_lines, dynsyms_path)
82    os.remove(tmp_file1)
83    os.remove(tmp_file2)
84
85
86    tmp_file1 = '{}.tmp1'.format(funcsysms_path)
87    tmp_file2 = '{}.tmp2'.format(funcsysms_path)
88    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT), 'w', encoding='utf-8') as output_file:
89        subprocess.run(gen_func_symbols_cmd.split(), stdout=output_file)
90
91    with os.fdopen(os.open(tmp_file1, os.O_RDWR | os.O_CREAT), 'r', encoding='utf-8') as output_file:
92        lines = output_file.readlines()
93        sort_lines = []
94        for line in lines:
95            columns = line.strip().split()
96            if len(columns) > 2 and ('t' in columns[1] or 'T' in columns[1] or 'd' in columns[1]):
97                sort_lines.append(columns[0])
98
99    gen_symbols(tmp_file2, sort_lines, funcsysms_path)
100    os.remove(tmp_file1)
101    os.remove(tmp_file2)
102
103
104    with os.fdopen(os.open(keep_path, os.O_RDWR | os.O_CREAT), 'w', encoding='utf-8') as output_file:
105        subprocess.run(gen_keep_symbols_cmd.split(), stdout=output_file)
106
107
108    cmd_list.append(gen_keep_debug_cmd)
109    cmd_list.append(gen_mini_debug_cmd)
110    cmd_list.append(compress_debuginfo)
111    cmd_list.append(gen_stripped_binary)
112
113    # execute each cmd to generate temporary file
114    # which .gnu_debugdata section depends on
115    for cmd in cmd_list:
116        subprocess.call(cmd.split(), shell=False)
117
118    # remove temporary file
119    os.remove(dynsyms_path)
120    os.remove(funcsysms_path)
121    os.remove(keep_path)
122    os.remove(debug_path)
123    os.remove(mini_debug_path + ".xz")
124
125
126def main():
127    parser = argparse.ArgumentParser(description=__doc__)
128    parser.add_argument("--unstripped-path",
129                        help="unstripped binary path")
130    parser.add_argument("--stripped-path",
131                        help="stripped binary path")
132    parser.add_argument("--root-path",
133                        help="root path is used to search llvm toolchain")
134    parser.add_argument("--clang-base-dir", help="")
135    args = parser.parse_args()
136
137    create_mini_debug_info(args.unstripped_path,
138                           args.stripped_path, args.root_path, args.clang_base_dir)
139
140
141if __name__ == "__main__":
142    sys.exit(main())
143