1343171Sdim//===- Reader.cpp ---------------------------------------------------------===//
2343171Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6343171Sdim//
7343171Sdim//===----------------------------------------------------------------------===//
8343171Sdim
9343171Sdim#include "Reader.h"
10343171Sdim#include "Object.h"
11343171Sdim#include "llvm/ADT/ArrayRef.h"
12343171Sdim#include "llvm/ADT/StringRef.h"
13353358Sdim#include "llvm/BinaryFormat/COFF.h"
14343171Sdim#include "llvm/Object/COFF.h"
15343171Sdim#include "llvm/Support/ErrorHandling.h"
16343171Sdim#include <cstddef>
17343171Sdim#include <cstdint>
18343171Sdim
19343171Sdimnamespace llvm {
20343171Sdimnamespace objcopy {
21343171Sdimnamespace coff {
22343171Sdim
23343171Sdimusing namespace object;
24353358Sdimusing namespace COFF;
25343171Sdim
26343171SdimError COFFReader::readExecutableHeaders(Object &Obj) const {
27343171Sdim  const dos_header *DH = COFFObj.getDOSHeader();
28343171Sdim  Obj.Is64 = COFFObj.is64();
29343171Sdim  if (!DH)
30343171Sdim    return Error::success();
31343171Sdim
32343171Sdim  Obj.IsPE = true;
33343171Sdim  Obj.DosHeader = *DH;
34343171Sdim  if (DH->AddressOfNewExeHeader > sizeof(*DH))
35343171Sdim    Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
36343171Sdim                                    DH->AddressOfNewExeHeader - sizeof(*DH));
37343171Sdim
38343171Sdim  if (COFFObj.is64()) {
39360784Sdim    Obj.PeHeader = *COFFObj.getPE32PlusHeader();
40343171Sdim  } else {
41360784Sdim    const pe32_header *PE32 = COFFObj.getPE32Header();
42343171Sdim    copyPeHeader(Obj.PeHeader, *PE32);
43343171Sdim    // The pe32plus_header (stored in Object) lacks the BaseOfData field.
44343171Sdim    Obj.BaseOfData = PE32->BaseOfData;
45343171Sdim  }
46343171Sdim
47343171Sdim  for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
48343171Sdim    const data_directory *Dir;
49343171Sdim    if (auto EC = COFFObj.getDataDirectory(I, Dir))
50343171Sdim      return errorCodeToError(EC);
51343171Sdim    Obj.DataDirectories.emplace_back(*Dir);
52343171Sdim  }
53343171Sdim  return Error::success();
54343171Sdim}
55343171Sdim
56343171SdimError COFFReader::readSections(Object &Obj) const {
57353358Sdim  std::vector<Section> Sections;
58343171Sdim  // Section indexing starts from 1.
59343171Sdim  for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
60343171Sdim    const coff_section *Sec;
61343171Sdim    if (auto EC = COFFObj.getSection(I, Sec))
62343171Sdim      return errorCodeToError(EC);
63353358Sdim    Sections.push_back(Section());
64353358Sdim    Section &S = Sections.back();
65343171Sdim    S.Header = *Sec;
66360784Sdim    S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
67353358Sdim    ArrayRef<uint8_t> Contents;
68353358Sdim    if (Error E = COFFObj.getSectionContents(Sec, Contents))
69353358Sdim      return E;
70353358Sdim    S.setContentsRef(Contents);
71343171Sdim    ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
72343171Sdim    for (const coff_relocation &R : Relocs)
73343171Sdim      S.Relocs.push_back(R);
74353358Sdim    if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
75353358Sdim      S.Name = *NameOrErr;
76353358Sdim    else
77353358Sdim      return NameOrErr.takeError();
78343171Sdim  }
79353358Sdim  Obj.addSections(Sections);
80343171Sdim  return Error::success();
81343171Sdim}
82343171Sdim
83343171SdimError COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
84343171Sdim  std::vector<Symbol> Symbols;
85343171Sdim  Symbols.reserve(COFFObj.getRawNumberOfSymbols());
86353358Sdim  ArrayRef<Section> Sections = Obj.getSections();
87343171Sdim  for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
88343171Sdim    Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
89343171Sdim    if (!SymOrErr)
90343171Sdim      return SymOrErr.takeError();
91343171Sdim    COFFSymbolRef SymRef = *SymOrErr;
92343171Sdim
93343171Sdim    Symbols.push_back(Symbol());
94343171Sdim    Symbol &Sym = Symbols.back();
95343171Sdim    // Copy symbols from the original form into an intermediate coff_symbol32.
96343171Sdim    if (IsBigObj)
97343171Sdim      copySymbol(Sym.Sym,
98343171Sdim                 *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
99343171Sdim    else
100343171Sdim      copySymbol(Sym.Sym,
101343171Sdim                 *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
102343171Sdim    if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name))
103343171Sdim      return errorCodeToError(EC);
104353358Sdim
105353358Sdim    ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
106353358Sdim    size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
107353358Sdim    assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
108353358Sdim    // The auxillary symbols are structs of sizeof(coff_symbol16) each.
109353358Sdim    // In the big object format (where symbols are coff_symbol32), each
110353358Sdim    // auxillary symbol is padded with 2 bytes at the end. Copy each
111353358Sdim    // auxillary symbol to the Sym.AuxData vector. For file symbols,
112353358Sdim    // the whole range of aux symbols are interpreted as one null padded
113353358Sdim    // string instead.
114353358Sdim    if (SymRef.isFileRecord())
115353358Sdim      Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
116353358Sdim                              AuxData.size())
117353358Sdim                        .rtrim('\0');
118353358Sdim    else
119353358Sdim      for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
120353358Sdim        Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
121353358Sdim
122353358Sdim    // Find the unique id of the section
123353358Sdim    if (SymRef.getSectionNumber() <=
124353358Sdim        0) // Special symbol (undefined/absolute/debug)
125353358Sdim      Sym.TargetSectionId = SymRef.getSectionNumber();
126353358Sdim    else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
127353358Sdim             Sections.size())
128353358Sdim      Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
129353358Sdim    else
130353358Sdim      return createStringError(object_error::parse_failed,
131353358Sdim                               "section number out of range");
132353358Sdim    // For section definitions, check if it is comdat associative, and if
133353358Sdim    // it is, find the target section unique id.
134353358Sdim    const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
135353358Sdim    const coff_aux_weak_external *WE = SymRef.getWeakExternal();
136353358Sdim    if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
137353358Sdim      int32_t Index = SD->getNumber(IsBigObj);
138353358Sdim      if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
139353358Sdim        return createStringError(object_error::parse_failed,
140353358Sdim                                 "unexpected associative section index");
141353358Sdim      Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
142353358Sdim    } else if (WE) {
143353358Sdim      // This is a raw symbol index for now, but store it in the Symbol
144353358Sdim      // until we've added them to the Object, which assigns the final
145353358Sdim      // unique ids.
146353358Sdim      Sym.WeakTargetSymbolId = WE->TagIndex;
147353358Sdim    }
148343171Sdim    I += 1 + SymRef.getNumberOfAuxSymbols();
149343171Sdim  }
150343171Sdim  Obj.addSymbols(Symbols);
151343171Sdim  return Error::success();
152343171Sdim}
153343171Sdim
154353358SdimError COFFReader::setSymbolTargets(Object &Obj) const {
155343171Sdim  std::vector<const Symbol *> RawSymbolTable;
156343171Sdim  for (const Symbol &Sym : Obj.getSymbols()) {
157343171Sdim    RawSymbolTable.push_back(&Sym);
158343171Sdim    for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
159343171Sdim      RawSymbolTable.push_back(nullptr);
160343171Sdim  }
161353358Sdim  for (Symbol &Sym : Obj.getMutableSymbols()) {
162353358Sdim    // Convert WeakTargetSymbolId from the original raw symbol index to
163353358Sdim    // a proper unique id.
164353358Sdim    if (Sym.WeakTargetSymbolId) {
165353358Sdim      if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
166353358Sdim        return createStringError(object_error::parse_failed,
167353358Sdim                                 "weak external reference out of range");
168353358Sdim      const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
169353358Sdim      if (Target == nullptr)
170353358Sdim        return createStringError(object_error::parse_failed,
171353358Sdim                                 "invalid SymbolTableIndex");
172353358Sdim      Sym.WeakTargetSymbolId = Target->UniqueId;
173353358Sdim    }
174353358Sdim  }
175353358Sdim  for (Section &Sec : Obj.getMutableSections()) {
176343171Sdim    for (Relocation &R : Sec.Relocs) {
177343171Sdim      if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
178353358Sdim        return createStringError(object_error::parse_failed,
179353358Sdim                                 "SymbolTableIndex out of range");
180343171Sdim      const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
181343171Sdim      if (Sym == nullptr)
182353358Sdim        return createStringError(object_error::parse_failed,
183353358Sdim                                 "invalid SymbolTableIndex");
184343171Sdim      R.Target = Sym->UniqueId;
185343171Sdim      R.TargetName = Sym->Name;
186343171Sdim    }
187343171Sdim  }
188343171Sdim  return Error::success();
189343171Sdim}
190343171Sdim
191343171SdimExpected<std::unique_ptr<Object>> COFFReader::create() const {
192360784Sdim  auto Obj = std::make_unique<Object>();
193343171Sdim
194343171Sdim  bool IsBigObj = false;
195360784Sdim  if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {
196343171Sdim    Obj->CoffFileHeader = *CFH;
197343171Sdim  } else {
198360784Sdim    const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();
199343171Sdim    if (!CBFH)
200353358Sdim      return createStringError(object_error::parse_failed,
201353358Sdim                               "no COFF file header returned");
202343171Sdim    // Only copying the few fields from the bigobj header that we need
203343171Sdim    // and won't recreate in the end.
204343171Sdim    Obj->CoffFileHeader.Machine = CBFH->Machine;
205343171Sdim    Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
206343171Sdim    IsBigObj = true;
207343171Sdim  }
208343171Sdim
209343171Sdim  if (Error E = readExecutableHeaders(*Obj))
210343171Sdim    return std::move(E);
211343171Sdim  if (Error E = readSections(*Obj))
212343171Sdim    return std::move(E);
213343171Sdim  if (Error E = readSymbols(*Obj, IsBigObj))
214343171Sdim    return std::move(E);
215353358Sdim  if (Error E = setSymbolTargets(*Obj))
216343171Sdim    return std::move(E);
217343171Sdim
218343171Sdim  return std::move(Obj);
219343171Sdim}
220343171Sdim
221343171Sdim} // end namespace coff
222343171Sdim} // end namespace objcopy
223343171Sdim} // end namespace llvm
224