10b57cec5SDimitry Andric //===- MapFile.cpp --------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 9*5ffd83dbSDimitry Andric // This file implements the /map option in the same format as link.exe 10*5ffd83dbSDimitry Andric // (based on observations) 110b57cec5SDimitry Andric // 12*5ffd83dbSDimitry Andric // Header (program name, timestamp info, preferred load address) 130b57cec5SDimitry Andric // 14*5ffd83dbSDimitry Andric // Section list (Start = Section index:Base address): 15*5ffd83dbSDimitry Andric // Start Length Name Class 16*5ffd83dbSDimitry Andric // 0001:00001000 00000015H .text CODE 17*5ffd83dbSDimitry Andric // 18*5ffd83dbSDimitry Andric // Symbols list: 19*5ffd83dbSDimitry Andric // Address Publics by Value Rva + Base Lib:Object 20*5ffd83dbSDimitry Andric // 0001:00001000 main 0000000140001000 main.obj 21*5ffd83dbSDimitry Andric // 0001:00001300 ?__scrt_common_main@@YAHXZ 0000000140001300 libcmt:exe_main.obj 22*5ffd83dbSDimitry Andric // 23*5ffd83dbSDimitry Andric // entry point at 0001:00000360 24*5ffd83dbSDimitry Andric // 25*5ffd83dbSDimitry Andric // Static symbols 26*5ffd83dbSDimitry Andric // 27*5ffd83dbSDimitry Andric // 0000:00000000 __guard_fids__ 0000000140000000 libcmt : exe_main.obj 280b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric #include "MapFile.h" 310b57cec5SDimitry Andric #include "SymbolTable.h" 320b57cec5SDimitry Andric #include "Symbols.h" 330b57cec5SDimitry Andric #include "Writer.h" 340b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h" 35*5ffd83dbSDimitry Andric #include "lld/Common/Timer.h" 36*5ffd83dbSDimitry Andric #include "llvm/Support/Parallel.h" 37*5ffd83dbSDimitry Andric #include "llvm/Support/Path.h" 380b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric using namespace llvm; 410b57cec5SDimitry Andric using namespace llvm::object; 42*5ffd83dbSDimitry Andric using namespace lld; 43*5ffd83dbSDimitry Andric using namespace lld::coff; 440b57cec5SDimitry Andric 45*5ffd83dbSDimitry Andric static Timer totalMapTimer("MAP emission (Cumulative)", Timer::root()); 46*5ffd83dbSDimitry Andric static Timer symbolGatherTimer("Gather symbols", totalMapTimer); 47*5ffd83dbSDimitry Andric static Timer symbolStringsTimer("Build symbol strings", totalMapTimer); 48*5ffd83dbSDimitry Andric static Timer writeTimer("Write to file", totalMapTimer); 490b57cec5SDimitry Andric 50*5ffd83dbSDimitry Andric // Print out the first two columns of a line. 51*5ffd83dbSDimitry Andric static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) { 52*5ffd83dbSDimitry Andric os << format(" %04x:%08llx", sec, addr); 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric 55*5ffd83dbSDimitry Andric // Write the time stamp with the format used by link.exe 56*5ffd83dbSDimitry Andric // It seems identical to strftime with "%c" on msvc build, but we need a 57*5ffd83dbSDimitry Andric // locale-agnostic version. 58*5ffd83dbSDimitry Andric static void writeFormattedTimestamp(raw_ostream &os, time_t tds) { 59*5ffd83dbSDimitry Andric constexpr const char *const days[7] = {"Sun", "Mon", "Tue", "Wed", 60*5ffd83dbSDimitry Andric "Thu", "Fri", "Sat"}; 61*5ffd83dbSDimitry Andric constexpr const char *const months[12] = {"Jan", "Feb", "Mar", "Apr", 62*5ffd83dbSDimitry Andric "May", "Jun", "Jul", "Aug", 63*5ffd83dbSDimitry Andric "Sep", "Oct", "Nov", "Dec"}; 64*5ffd83dbSDimitry Andric tm *time = localtime(&tds); 65*5ffd83dbSDimitry Andric os << format("%s %s %2d %02d:%02d:%02d %d", days[time->tm_wday], 66*5ffd83dbSDimitry Andric months[time->tm_mon], time->tm_mday, time->tm_hour, time->tm_min, 67*5ffd83dbSDimitry Andric time->tm_sec, time->tm_year + 1900); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 70*5ffd83dbSDimitry Andric static void sortUniqueSymbols(std::vector<Defined *> &syms) { 71*5ffd83dbSDimitry Andric // Build helper vector 72*5ffd83dbSDimitry Andric using SortEntry = std::pair<Defined *, size_t>; 73*5ffd83dbSDimitry Andric std::vector<SortEntry> v; 74*5ffd83dbSDimitry Andric v.resize(syms.size()); 75*5ffd83dbSDimitry Andric for (size_t i = 0, e = syms.size(); i < e; ++i) 76*5ffd83dbSDimitry Andric v[i] = SortEntry(syms[i], i); 770b57cec5SDimitry Andric 78*5ffd83dbSDimitry Andric // Remove duplicate symbol pointers 79*5ffd83dbSDimitry Andric parallelSort(v, std::less<SortEntry>()); 80*5ffd83dbSDimitry Andric auto end = std::unique(v.begin(), v.end(), 81*5ffd83dbSDimitry Andric [](const SortEntry &a, const SortEntry &b) { 82*5ffd83dbSDimitry Andric return a.first == b.first; 830b57cec5SDimitry Andric }); 84*5ffd83dbSDimitry Andric v.erase(end, v.end()); 85*5ffd83dbSDimitry Andric 86*5ffd83dbSDimitry Andric // Sort by RVA then original order 87*5ffd83dbSDimitry Andric parallelSort(v, [](const SortEntry &a, const SortEntry &b) { 88*5ffd83dbSDimitry Andric // Add config->imageBase to avoid comparing "negative" RVAs. 89*5ffd83dbSDimitry Andric // This can happen with symbols of Absolute kind 90*5ffd83dbSDimitry Andric uint64_t rvaa = config->imageBase + a.first->getRVA(); 91*5ffd83dbSDimitry Andric uint64_t rvab = config->imageBase + b.first->getRVA(); 92*5ffd83dbSDimitry Andric return rvaa < rvab || (rvaa == rvab && a.second < b.second); 93*5ffd83dbSDimitry Andric }); 94*5ffd83dbSDimitry Andric 95*5ffd83dbSDimitry Andric syms.resize(v.size()); 96*5ffd83dbSDimitry Andric for (size_t i = 0, e = v.size(); i < e; ++i) 97*5ffd83dbSDimitry Andric syms[i] = v[i].first; 980b57cec5SDimitry Andric } 99*5ffd83dbSDimitry Andric 100*5ffd83dbSDimitry Andric // Returns the lists of all symbols that we want to print out. 101*5ffd83dbSDimitry Andric static void getSymbols(std::vector<Defined *> &syms, 102*5ffd83dbSDimitry Andric std::vector<Defined *> &staticSyms) { 103*5ffd83dbSDimitry Andric 104*5ffd83dbSDimitry Andric for (ObjFile *file : ObjFile::instances) 105*5ffd83dbSDimitry Andric for (Symbol *b : file->getSymbols()) { 106*5ffd83dbSDimitry Andric if (!b || !b->isLive()) 107*5ffd83dbSDimitry Andric continue; 108*5ffd83dbSDimitry Andric if (auto *sym = dyn_cast<DefinedCOFF>(b)) { 109*5ffd83dbSDimitry Andric COFFSymbolRef symRef = sym->getCOFFSymbol(); 110*5ffd83dbSDimitry Andric if (!symRef.isSectionDefinition() && 111*5ffd83dbSDimitry Andric symRef.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL) { 112*5ffd83dbSDimitry Andric if (symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC) 113*5ffd83dbSDimitry Andric staticSyms.push_back(sym); 114*5ffd83dbSDimitry Andric else 115*5ffd83dbSDimitry Andric syms.push_back(sym); 116*5ffd83dbSDimitry Andric } 117*5ffd83dbSDimitry Andric } else if (auto *sym = dyn_cast<Defined>(b)) { 118*5ffd83dbSDimitry Andric syms.push_back(sym); 119*5ffd83dbSDimitry Andric } 120*5ffd83dbSDimitry Andric } 121*5ffd83dbSDimitry Andric 122*5ffd83dbSDimitry Andric for (ImportFile *file : ImportFile::instances) { 123*5ffd83dbSDimitry Andric if (!file->live) 124*5ffd83dbSDimitry Andric continue; 125*5ffd83dbSDimitry Andric 126*5ffd83dbSDimitry Andric if (!file->thunkSym) 127*5ffd83dbSDimitry Andric continue; 128*5ffd83dbSDimitry Andric 129*5ffd83dbSDimitry Andric if (!file->thunkLive) 130*5ffd83dbSDimitry Andric continue; 131*5ffd83dbSDimitry Andric 132*5ffd83dbSDimitry Andric if (auto *thunkSym = dyn_cast<Defined>(file->thunkSym)) 133*5ffd83dbSDimitry Andric syms.push_back(thunkSym); 134*5ffd83dbSDimitry Andric 135*5ffd83dbSDimitry Andric if (auto *impSym = dyn_cast_or_null<Defined>(file->impSym)) 136*5ffd83dbSDimitry Andric syms.push_back(impSym); 137*5ffd83dbSDimitry Andric } 138*5ffd83dbSDimitry Andric 139*5ffd83dbSDimitry Andric sortUniqueSymbols(syms); 140*5ffd83dbSDimitry Andric sortUniqueSymbols(staticSyms); 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric // Construct a map from symbols to their stringified representations. 144*5ffd83dbSDimitry Andric static DenseMap<Defined *, std::string> 145*5ffd83dbSDimitry Andric getSymbolStrings(ArrayRef<Defined *> syms) { 1460b57cec5SDimitry Andric std::vector<std::string> str(syms.size()); 1470b57cec5SDimitry Andric parallelForEachN((size_t)0, syms.size(), [&](size_t i) { 1480b57cec5SDimitry Andric raw_string_ostream os(str[i]); 149*5ffd83dbSDimitry Andric Defined *sym = syms[i]; 150*5ffd83dbSDimitry Andric 151*5ffd83dbSDimitry Andric uint16_t sectionIdx = 0; 152*5ffd83dbSDimitry Andric uint64_t address = 0; 153*5ffd83dbSDimitry Andric SmallString<128> fileDescr; 154*5ffd83dbSDimitry Andric 155*5ffd83dbSDimitry Andric if (auto *absSym = dyn_cast<DefinedAbsolute>(sym)) { 156*5ffd83dbSDimitry Andric address = absSym->getVA(); 157*5ffd83dbSDimitry Andric fileDescr = "<absolute>"; 158*5ffd83dbSDimitry Andric } else if (isa<DefinedSynthetic>(sym)) { 159*5ffd83dbSDimitry Andric fileDescr = "<linker-defined>"; 160*5ffd83dbSDimitry Andric } else if (isa<DefinedCommon>(sym)) { 161*5ffd83dbSDimitry Andric fileDescr = "<common>"; 162*5ffd83dbSDimitry Andric } else if (Chunk *chunk = sym->getChunk()) { 163*5ffd83dbSDimitry Andric address = sym->getRVA(); 164*5ffd83dbSDimitry Andric if (OutputSection *sec = chunk->getOutputSection()) 165*5ffd83dbSDimitry Andric address -= sec->header.VirtualAddress; 166*5ffd83dbSDimitry Andric 167*5ffd83dbSDimitry Andric sectionIdx = chunk->getOutputSectionIdx(); 168*5ffd83dbSDimitry Andric 169*5ffd83dbSDimitry Andric InputFile *file; 170*5ffd83dbSDimitry Andric if (auto *impSym = dyn_cast<DefinedImportData>(sym)) 171*5ffd83dbSDimitry Andric file = impSym->file; 172*5ffd83dbSDimitry Andric else if (auto *thunkSym = dyn_cast<DefinedImportThunk>(sym)) 173*5ffd83dbSDimitry Andric file = thunkSym->wrappedSym->file; 174*5ffd83dbSDimitry Andric else 175*5ffd83dbSDimitry Andric file = sym->getFile(); 176*5ffd83dbSDimitry Andric 177*5ffd83dbSDimitry Andric if (file) { 178*5ffd83dbSDimitry Andric if (!file->parentName.empty()) { 179*5ffd83dbSDimitry Andric fileDescr = sys::path::filename(file->parentName); 180*5ffd83dbSDimitry Andric sys::path::replace_extension(fileDescr, ""); 181*5ffd83dbSDimitry Andric fileDescr += ":"; 182*5ffd83dbSDimitry Andric } 183*5ffd83dbSDimitry Andric fileDescr += sys::path::filename(file->getName()); 184*5ffd83dbSDimitry Andric } 185*5ffd83dbSDimitry Andric } 186*5ffd83dbSDimitry Andric writeHeader(os, sectionIdx, address); 187*5ffd83dbSDimitry Andric os << " "; 188*5ffd83dbSDimitry Andric os << left_justify(sym->getName(), 26); 189*5ffd83dbSDimitry Andric os << " "; 190*5ffd83dbSDimitry Andric os << format_hex_no_prefix((config->imageBase + sym->getRVA()), 16); 191*5ffd83dbSDimitry Andric if (!fileDescr.empty()) { 192*5ffd83dbSDimitry Andric os << " "; // FIXME : Handle "f" and "i" flags sometimes generated 193*5ffd83dbSDimitry Andric // by link.exe in those spaces 194*5ffd83dbSDimitry Andric os << fileDescr; 195*5ffd83dbSDimitry Andric } 1960b57cec5SDimitry Andric }); 1970b57cec5SDimitry Andric 198*5ffd83dbSDimitry Andric DenseMap<Defined *, std::string> ret; 1990b57cec5SDimitry Andric for (size_t i = 0, e = syms.size(); i < e; ++i) 2000b57cec5SDimitry Andric ret[syms[i]] = std::move(str[i]); 2010b57cec5SDimitry Andric return ret; 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 204*5ffd83dbSDimitry Andric void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) { 2050b57cec5SDimitry Andric if (config->mapFile.empty()) 2060b57cec5SDimitry Andric return; 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric std::error_code ec; 20985868e8aSDimitry Andric raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); 2100b57cec5SDimitry Andric if (ec) 2110b57cec5SDimitry Andric fatal("cannot open " + config->mapFile + ": " + ec.message()); 2120b57cec5SDimitry Andric 213*5ffd83dbSDimitry Andric ScopedTimer t1(totalMapTimer); 214*5ffd83dbSDimitry Andric 2150b57cec5SDimitry Andric // Collect symbol info that we want to print out. 216*5ffd83dbSDimitry Andric ScopedTimer t2(symbolGatherTimer); 217*5ffd83dbSDimitry Andric std::vector<Defined *> syms; 218*5ffd83dbSDimitry Andric std::vector<Defined *> staticSyms; 219*5ffd83dbSDimitry Andric getSymbols(syms, staticSyms); 220*5ffd83dbSDimitry Andric t2.stop(); 2210b57cec5SDimitry Andric 222*5ffd83dbSDimitry Andric ScopedTimer t3(symbolStringsTimer); 223*5ffd83dbSDimitry Andric DenseMap<Defined *, std::string> symStr = getSymbolStrings(syms); 224*5ffd83dbSDimitry Andric DenseMap<Defined *, std::string> staticSymStr = getSymbolStrings(staticSyms); 225*5ffd83dbSDimitry Andric t3.stop(); 2260b57cec5SDimitry Andric 227*5ffd83dbSDimitry Andric ScopedTimer t4(writeTimer); 228*5ffd83dbSDimitry Andric SmallString<128> AppName = sys::path::filename(config->outputFile); 229*5ffd83dbSDimitry Andric sys::path::replace_extension(AppName, ""); 230*5ffd83dbSDimitry Andric 231*5ffd83dbSDimitry Andric // Print out the file header 232*5ffd83dbSDimitry Andric os << " " << AppName << "\n"; 233*5ffd83dbSDimitry Andric os << "\n"; 234*5ffd83dbSDimitry Andric 235*5ffd83dbSDimitry Andric os << " Timestamp is " << format_hex_no_prefix(config->timestamp, 8) << " ("; 236*5ffd83dbSDimitry Andric if (config->repro) { 237*5ffd83dbSDimitry Andric os << "Repro mode"; 238*5ffd83dbSDimitry Andric } else { 239*5ffd83dbSDimitry Andric writeFormattedTimestamp(os, config->timestamp); 240*5ffd83dbSDimitry Andric } 241*5ffd83dbSDimitry Andric os << ")\n"; 242*5ffd83dbSDimitry Andric 243*5ffd83dbSDimitry Andric os << "\n"; 244*5ffd83dbSDimitry Andric os << " Preferred load address is " 245*5ffd83dbSDimitry Andric << format_hex_no_prefix(config->imageBase, 16) << "\n"; 246*5ffd83dbSDimitry Andric os << "\n"; 247*5ffd83dbSDimitry Andric 248*5ffd83dbSDimitry Andric // Print out section table. 249*5ffd83dbSDimitry Andric os << " Start Length Name Class\n"; 250*5ffd83dbSDimitry Andric 2510b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 252*5ffd83dbSDimitry Andric // Merge display of chunks with same sectionName 253*5ffd83dbSDimitry Andric std::vector<std::pair<SectionChunk *, SectionChunk *>> ChunkRanges; 2540b57cec5SDimitry Andric for (Chunk *c : sec->chunks) { 2550b57cec5SDimitry Andric auto *sc = dyn_cast<SectionChunk>(c); 2560b57cec5SDimitry Andric if (!sc) 2570b57cec5SDimitry Andric continue; 2580b57cec5SDimitry Andric 259*5ffd83dbSDimitry Andric if (ChunkRanges.empty() || 260*5ffd83dbSDimitry Andric c->getSectionName() != ChunkRanges.back().first->getSectionName()) { 261*5ffd83dbSDimitry Andric ChunkRanges.emplace_back(sc, sc); 262*5ffd83dbSDimitry Andric } else { 263*5ffd83dbSDimitry Andric ChunkRanges.back().second = sc; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric } 26685868e8aSDimitry Andric 267*5ffd83dbSDimitry Andric const bool isCodeSection = 268*5ffd83dbSDimitry Andric (sec->header.Characteristics & COFF::IMAGE_SCN_CNT_CODE) && 269*5ffd83dbSDimitry Andric (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_READ) && 270*5ffd83dbSDimitry Andric (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE); 271*5ffd83dbSDimitry Andric StringRef SectionClass = (isCodeSection ? "CODE" : "DATA"); 272*5ffd83dbSDimitry Andric 273*5ffd83dbSDimitry Andric for (auto &cr : ChunkRanges) { 274*5ffd83dbSDimitry Andric size_t size = 275*5ffd83dbSDimitry Andric cr.second->getRVA() + cr.second->getSize() - cr.first->getRVA(); 276*5ffd83dbSDimitry Andric 277*5ffd83dbSDimitry Andric auto address = cr.first->getRVA() - sec->header.VirtualAddress; 278*5ffd83dbSDimitry Andric writeHeader(os, sec->sectionIndex, address); 279*5ffd83dbSDimitry Andric os << " " << format_hex_no_prefix(size, 8) << "H"; 280*5ffd83dbSDimitry Andric os << " " << left_justify(cr.first->getSectionName(), 23); 281*5ffd83dbSDimitry Andric os << " " << SectionClass; 282*5ffd83dbSDimitry Andric os << '\n'; 283*5ffd83dbSDimitry Andric } 284*5ffd83dbSDimitry Andric } 285*5ffd83dbSDimitry Andric 286*5ffd83dbSDimitry Andric // Print out the symbols table (without static symbols) 287*5ffd83dbSDimitry Andric os << "\n"; 288*5ffd83dbSDimitry Andric os << " Address Publics by Value Rva+Base" 289*5ffd83dbSDimitry Andric " Lib:Object\n"; 290*5ffd83dbSDimitry Andric os << "\n"; 291*5ffd83dbSDimitry Andric for (Defined *sym : syms) 292*5ffd83dbSDimitry Andric os << symStr[sym] << '\n'; 293*5ffd83dbSDimitry Andric 294*5ffd83dbSDimitry Andric // Print out the entry point. 295*5ffd83dbSDimitry Andric os << "\n"; 296*5ffd83dbSDimitry Andric 297*5ffd83dbSDimitry Andric uint16_t entrySecIndex = 0; 298*5ffd83dbSDimitry Andric uint64_t entryAddress = 0; 299*5ffd83dbSDimitry Andric 300*5ffd83dbSDimitry Andric if (!config->noEntry) { 301*5ffd83dbSDimitry Andric Defined *entry = dyn_cast_or_null<Defined>(config->entry); 302*5ffd83dbSDimitry Andric if (entry) { 303*5ffd83dbSDimitry Andric Chunk *chunk = entry->getChunk(); 304*5ffd83dbSDimitry Andric entrySecIndex = chunk->getOutputSectionIdx(); 305*5ffd83dbSDimitry Andric entryAddress = 306*5ffd83dbSDimitry Andric entry->getRVA() - chunk->getOutputSection()->header.VirtualAddress; 307*5ffd83dbSDimitry Andric } 308*5ffd83dbSDimitry Andric } 309*5ffd83dbSDimitry Andric os << " entry point at "; 310*5ffd83dbSDimitry Andric os << format("%04x:%08llx", entrySecIndex, entryAddress); 311*5ffd83dbSDimitry Andric os << "\n"; 312*5ffd83dbSDimitry Andric 313*5ffd83dbSDimitry Andric // Print out the static symbols 314*5ffd83dbSDimitry Andric os << "\n"; 315*5ffd83dbSDimitry Andric os << " Static symbols\n"; 316*5ffd83dbSDimitry Andric os << "\n"; 317*5ffd83dbSDimitry Andric for (Defined *sym : staticSyms) 318*5ffd83dbSDimitry Andric os << staticSymStr[sym] << '\n'; 319*5ffd83dbSDimitry Andric 320*5ffd83dbSDimitry Andric t4.stop(); 321*5ffd83dbSDimitry Andric t1.stop(); 322*5ffd83dbSDimitry Andric } 323