xref: /aosp_15_r20/art/tools/create_minidebuginfo/create_minidebuginfo.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include <algorithm>
18*795d594fSAndroid Build Coastguard Worker #include <deque>
19*795d594fSAndroid Build Coastguard Worker #include <map>
20*795d594fSAndroid Build Coastguard Worker #include <memory>
21*795d594fSAndroid Build Coastguard Worker #include <string>
22*795d594fSAndroid Build Coastguard Worker #include <string_view>
23*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
24*795d594fSAndroid Build Coastguard Worker #include <vector>
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/os.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
29*795d594fSAndroid Build Coastguard Worker #include "elf/elf_builder.h"
30*795d594fSAndroid Build Coastguard Worker #include "elf/elf_debug_reader.h"
31*795d594fSAndroid Build Coastguard Worker #include "elf/xz_utils.h"
32*795d594fSAndroid Build Coastguard Worker #include "stream/file_output_stream.h"
33*795d594fSAndroid Build Coastguard Worker #include "stream/vector_output_stream.h"
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker namespace art {
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker static constexpr size_t kBlockSize = 32 * KB;
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker constexpr const char kSortedSymbolName[] = "$android.symtab.sorted";
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker template<typename ElfTypes>
WriteMinidebugInfo(const std::vector<uint8_t> & input,std::vector<uint8_t> * output)42*795d594fSAndroid Build Coastguard Worker static void WriteMinidebugInfo(const std::vector<uint8_t>& input, std::vector<uint8_t>* output) {
43*795d594fSAndroid Build Coastguard Worker   using Elf_Addr = typename ElfTypes::Addr;
44*795d594fSAndroid Build Coastguard Worker   using Elf_Shdr = typename ElfTypes::Shdr;
45*795d594fSAndroid Build Coastguard Worker   using Elf_Sym = typename ElfTypes::Sym;
46*795d594fSAndroid Build Coastguard Worker   using Elf_Word = typename ElfTypes::Word;
47*795d594fSAndroid Build Coastguard Worker   using CIE = typename ElfDebugReader<ElfTypes>::CIE;
48*795d594fSAndroid Build Coastguard Worker   using FDE = typename ElfDebugReader<ElfTypes>::FDE;
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker   ElfDebugReader<ElfTypes> reader(input);
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker   std::vector<uint8_t> output_elf_data;
53*795d594fSAndroid Build Coastguard Worker   VectorOutputStream output_stream("Output ELF", &output_elf_data);
54*795d594fSAndroid Build Coastguard Worker   InstructionSet isa = ElfBuilder<ElfTypes>::GetIsaFromHeader(*reader.GetHeader());
55*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &output_stream));
56*795d594fSAndroid Build Coastguard Worker   builder->Start(/*write_program_headers=*/ false);
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker   auto* text = builder->GetText();
59*795d594fSAndroid Build Coastguard Worker   const Elf_Shdr* original_text = reader.GetSection(".text");
60*795d594fSAndroid Build Coastguard Worker   CHECK(original_text != nullptr);
61*795d594fSAndroid Build Coastguard Worker   text->AllocateVirtualMemory(original_text->sh_addr, original_text->sh_size);
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   auto* strtab = builder->GetStrTab();
64*795d594fSAndroid Build Coastguard Worker   auto* symtab = builder->GetSymTab();
65*795d594fSAndroid Build Coastguard Worker   strtab->Start();
66*795d594fSAndroid Build Coastguard Worker   {
67*795d594fSAndroid Build Coastguard Worker     std::unordered_map<uint64_t, uint64_t> dyn_funcs_by_offset;
68*795d594fSAndroid Build Coastguard Worker     reader.VisitDynamicSymbols([&](Elf_Sym sym, const char*) {
69*795d594fSAndroid Build Coastguard Worker       // Keep track of all of the dynamic function symbols.
70*795d594fSAndroid Build Coastguard Worker       if (ELF32_ST_TYPE(sym.st_info) == STT_FUNC && sym.st_size != 0) {
71*795d594fSAndroid Build Coastguard Worker         auto it = dyn_funcs_by_offset.find(sym.st_value);
72*795d594fSAndroid Build Coastguard Worker         if (it == dyn_funcs_by_offset.end() || it->second < sym.st_size) {
73*795d594fSAndroid Build Coastguard Worker           dyn_funcs_by_offset[sym.st_value] = sym.st_size;
74*795d594fSAndroid Build Coastguard Worker         }
75*795d594fSAndroid Build Coastguard Worker       }
76*795d594fSAndroid Build Coastguard Worker     });
77*795d594fSAndroid Build Coastguard Worker     std::unordered_map<uint64_t, std::string_view> funcs_by_offset;
78*795d594fSAndroid Build Coastguard Worker     std::multimap<std::string_view, Elf_Sym> syms;
79*795d594fSAndroid Build Coastguard Worker     reader.VisitFunctionSymbols([&](Elf_Sym sym, const char* name) {
80*795d594fSAndroid Build Coastguard Worker       // Exclude non-function or empty symbols.
81*795d594fSAndroid Build Coastguard Worker       if (ELF32_ST_TYPE(sym.st_info) != STT_FUNC || sym.st_size == 0) {
82*795d594fSAndroid Build Coastguard Worker         return;
83*795d594fSAndroid Build Coastguard Worker       }
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker       // Exclude symbols at the same offset as a symbol in the set of
86*795d594fSAndroid Build Coastguard Worker       // dynamic symbols.
87*795d594fSAndroid Build Coastguard Worker       auto dyn_it = dyn_funcs_by_offset.find(sym.st_value);
88*795d594fSAndroid Build Coastguard Worker       if (dyn_it != dyn_funcs_by_offset.end()) {
89*795d594fSAndroid Build Coastguard Worker         CHECK(dyn_it->second >= sym.st_size);
90*795d594fSAndroid Build Coastguard Worker         return;
91*795d594fSAndroid Build Coastguard Worker       }
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker       // Exclude symbols with the same offset as a previous symbol.
94*795d594fSAndroid Build Coastguard Worker       if (funcs_by_offset.contains(sym.st_value)) {
95*795d594fSAndroid Build Coastguard Worker         const std::string_view& previous_name = funcs_by_offset[sym.st_value];
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker         // Find the previous symbol entry.
98*795d594fSAndroid Build Coastguard Worker         auto it = syms.find(previous_name);
99*795d594fSAndroid Build Coastguard Worker         while (it != syms.end() && it->second.st_value != sym.st_value) {
100*795d594fSAndroid Build Coastguard Worker           ++it;
101*795d594fSAndroid Build Coastguard Worker         }
102*795d594fSAndroid Build Coastguard Worker         CHECK(it != syms.end());
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker         // When there is a duplicate, always choose the symbol with the
105*795d594fSAndroid Build Coastguard Worker         // largest size.
106*795d594fSAndroid Build Coastguard Worker         // In order to produce the same symbol table every time, if the
107*795d594fSAndroid Build Coastguard Worker         // symbol has the same size choose the symbol with the shortest
108*795d594fSAndroid Build Coastguard Worker         // name, or the symbol first according to ascii comparison.
109*795d594fSAndroid Build Coastguard Worker         if (sym.st_size < it->second.st_size ||
110*795d594fSAndroid Build Coastguard Worker             (sym.st_size == it->second.st_size &&
111*795d594fSAndroid Build Coastguard Worker              (previous_name.size() < strlen(name) || previous_name.compare(name) <= 0))) {
112*795d594fSAndroid Build Coastguard Worker           return;
113*795d594fSAndroid Build Coastguard Worker         }
114*795d594fSAndroid Build Coastguard Worker         syms.erase(it);
115*795d594fSAndroid Build Coastguard Worker       }
116*795d594fSAndroid Build Coastguard Worker       funcs_by_offset[sym.st_value] = name;
117*795d594fSAndroid Build Coastguard Worker       syms.emplace(name, sym);
118*795d594fSAndroid Build Coastguard Worker     });
119*795d594fSAndroid Build Coastguard Worker     if (!syms.empty()) {
120*795d594fSAndroid Build Coastguard Worker       symtab->Add(strtab->Write(kSortedSymbolName), nullptr, 0, 0, STB_GLOBAL, STT_NOTYPE);
121*795d594fSAndroid Build Coastguard Worker     }
122*795d594fSAndroid Build Coastguard Worker     for (auto& entry : syms) {
123*795d594fSAndroid Build Coastguard Worker       std::string_view name = entry.first;
124*795d594fSAndroid Build Coastguard Worker       const Elf_Sym& sym = entry.second;
125*795d594fSAndroid Build Coastguard Worker       Elf_Word name_idx = strtab->Write(name);
126*795d594fSAndroid Build Coastguard Worker       symtab->Add(name_idx, text, sym.st_value, sym.st_size, STB_GLOBAL, STT_FUNC);
127*795d594fSAndroid Build Coastguard Worker     }
128*795d594fSAndroid Build Coastguard Worker   }
129*795d594fSAndroid Build Coastguard Worker   strtab->End();
130*795d594fSAndroid Build Coastguard Worker   symtab->WriteCachedSection();
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker   auto* debug_frame = builder->GetDebugFrame();
133*795d594fSAndroid Build Coastguard Worker   debug_frame->Start();
134*795d594fSAndroid Build Coastguard Worker   {
135*795d594fSAndroid Build Coastguard Worker     std::map<std::string_view, Elf_Addr> cie_dedup;
136*795d594fSAndroid Build Coastguard Worker     std::unordered_map<const CIE*, Elf_Addr> new_cie_offset;
137*795d594fSAndroid Build Coastguard Worker     std::deque<std::pair<const FDE*, const CIE*>> entries;
138*795d594fSAndroid Build Coastguard Worker     // Read, de-duplicate and write CIE entries.  Read FDE entries.
139*795d594fSAndroid Build Coastguard Worker     reader.VisitDebugFrame(
140*795d594fSAndroid Build Coastguard Worker         [&](const CIE* cie) {
141*795d594fSAndroid Build Coastguard Worker           std::string_view key(reinterpret_cast<const char*>(cie->data()), cie->size());
142*795d594fSAndroid Build Coastguard Worker           auto it = cie_dedup.emplace(key, debug_frame->GetPosition());
143*795d594fSAndroid Build Coastguard Worker           if (/* inserted */ it.second) {
144*795d594fSAndroid Build Coastguard Worker             debug_frame->WriteFully(cie->data(), cie->size());
145*795d594fSAndroid Build Coastguard Worker           }
146*795d594fSAndroid Build Coastguard Worker           new_cie_offset[cie] = it.first->second;
147*795d594fSAndroid Build Coastguard Worker         },
148*795d594fSAndroid Build Coastguard Worker         [&](const FDE* fde, const CIE* cie) { entries.emplace_back(std::make_pair(fde, cie)); });
149*795d594fSAndroid Build Coastguard Worker     // Sort FDE entries by opcodes to improve locality for compression (saves ~25%).
150*795d594fSAndroid Build Coastguard Worker     std::stable_sort(entries.begin(), entries.end(), [](const auto& lhs, const auto& rhs) {
151*795d594fSAndroid Build Coastguard Worker       constexpr size_t opcode_offset = sizeof(FDE);
152*795d594fSAndroid Build Coastguard Worker       return std::lexicographical_compare(
153*795d594fSAndroid Build Coastguard Worker           lhs.first->data() + opcode_offset, lhs.first->data() + lhs.first->size(),
154*795d594fSAndroid Build Coastguard Worker           rhs.first->data() + opcode_offset, rhs.first->data() + rhs.first->size());
155*795d594fSAndroid Build Coastguard Worker     });
156*795d594fSAndroid Build Coastguard Worker     // Write all FDE entries while adjusting the CIE offsets to the new locations.
157*795d594fSAndroid Build Coastguard Worker     for (const auto& entry : entries) {
158*795d594fSAndroid Build Coastguard Worker       const FDE* fde = entry.first;
159*795d594fSAndroid Build Coastguard Worker       const CIE* cie = entry.second;
160*795d594fSAndroid Build Coastguard Worker       FDE new_header = *fde;
161*795d594fSAndroid Build Coastguard Worker       new_header.cie_pointer = new_cie_offset[cie];
162*795d594fSAndroid Build Coastguard Worker       debug_frame->WriteFully(&new_header, sizeof(FDE));
163*795d594fSAndroid Build Coastguard Worker       debug_frame->WriteFully(fde->data() + sizeof(FDE), fde->size() - sizeof(FDE));
164*795d594fSAndroid Build Coastguard Worker     }
165*795d594fSAndroid Build Coastguard Worker   }
166*795d594fSAndroid Build Coastguard Worker   debug_frame->End();
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker   builder->End();
169*795d594fSAndroid Build Coastguard Worker   CHECK(builder->Good());
170*795d594fSAndroid Build Coastguard Worker 
171*795d594fSAndroid Build Coastguard Worker   XzCompress(ArrayRef<const uint8_t>(output_elf_data), output, 9 /*size*/, kBlockSize);
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker 
Main(int argc,char ** argv)174*795d594fSAndroid Build Coastguard Worker static int Main(int argc, char** argv) {
175*795d594fSAndroid Build Coastguard Worker   // Check command like arguments.
176*795d594fSAndroid Build Coastguard Worker   if (argc != 3) {
177*795d594fSAndroid Build Coastguard Worker     printf("Usage: create_minidebuginfo ELF_FILE OUT_FILE\n");
178*795d594fSAndroid Build Coastguard Worker     printf("  ELF_FILE: The path to an ELF file with full symbols (before being stripped).\n");
179*795d594fSAndroid Build Coastguard Worker     printf("  OUT_FILE: The path for the generated mini-debug-info data (not an elf file).\n");
180*795d594fSAndroid Build Coastguard Worker     return 1;
181*795d594fSAndroid Build Coastguard Worker   }
182*795d594fSAndroid Build Coastguard Worker   const char* input_filename = argv[1];
183*795d594fSAndroid Build Coastguard Worker   const char* output_filename = argv[2];
184*795d594fSAndroid Build Coastguard Worker 
185*795d594fSAndroid Build Coastguard Worker   // Read input file.
186*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<File> input_file(OS::OpenFileForReading(input_filename));
187*795d594fSAndroid Build Coastguard Worker   CHECK(input_file.get() != nullptr) << "Failed to open input file";
188*795d594fSAndroid Build Coastguard Worker   std::vector<uint8_t> elf(input_file->GetLength());
189*795d594fSAndroid Build Coastguard Worker   CHECK(input_file->ReadFully(elf.data(), elf.size())) << "Failed to read input file";
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker   // Write output file.
192*795d594fSAndroid Build Coastguard Worker   std::vector<uint8_t> output;
193*795d594fSAndroid Build Coastguard Worker   if (ElfDebugReader<ElfTypes32>::IsValidElfHeader(elf)) {
194*795d594fSAndroid Build Coastguard Worker     WriteMinidebugInfo<ElfTypes32>(elf, &output);
195*795d594fSAndroid Build Coastguard Worker   } else if (ElfDebugReader<ElfTypes64>::IsValidElfHeader(elf)) {
196*795d594fSAndroid Build Coastguard Worker     WriteMinidebugInfo<ElfTypes64>(elf, &output);
197*795d594fSAndroid Build Coastguard Worker   } else {
198*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Invalid ELF file header " << input_filename;
199*795d594fSAndroid Build Coastguard Worker   }
200*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<File> output_file(OS::CreateEmptyFile(output_filename));
201*795d594fSAndroid Build Coastguard Worker   if (!output_file->WriteFully(output.data(), output.size()) || output_file->FlushClose() != 0) {
202*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Failed to write " << output_filename;
203*795d594fSAndroid Build Coastguard Worker   }
204*795d594fSAndroid Build Coastguard Worker   return 0;
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker 
207*795d594fSAndroid Build Coastguard Worker }  // namespace art
208*795d594fSAndroid Build Coastguard Worker 
main(int argc,char ** argv)209*795d594fSAndroid Build Coastguard Worker int main(int argc, char** argv) {
210*795d594fSAndroid Build Coastguard Worker   return art::Main(argc, argv);
211*795d594fSAndroid Build Coastguard Worker }
212