summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/ReaderELF.cpp
blob: a94f30715a455a9da5b2827bb154c3d5f1ecbf32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//===- lib/ReaderWriter/ELF/ReaderELF.cpp ---------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines the ELF Reader and all helper sub classes to consume an ELF
/// file and produces atoms out of it.
///
//===----------------------------------------------------------------------===//

#include "lld/ReaderWriter/Reader.h"

#include "lld/Core/Reference.h"
#include "lld/ReaderWriter/ELFTargetInfo.h"
#include "lld/ReaderWriter/ReaderArchive.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include "AtomsELF.h"
#include "FileELF.h"

#include <map>
#include <vector>

using namespace lld;
using llvm::support::endianness;
using namespace llvm::object;

namespace {
/// \brief A reader object that will instantiate correct FileELF by examining the
/// memory buffer for ELF class and bit width
class ReaderELF : public Reader {
public:
  ReaderELF(const ELFTargetInfo &ti, std::function<ReaderFunc> read)
      : Reader(ti), _elfTargetInfo(ti), _readerArchive(ti, read) {
  }

  error_code parseFile(std::unique_ptr<MemoryBuffer> mb,
                       std::vector<std::unique_ptr<File> > &result) {
    using llvm::object::ELFType;
    llvm::sys::LLVMFileType fileType =
        llvm::sys::IdentifyFileType(mb->getBufferStart(),
                                    static_cast<unsigned>(mb->getBufferSize()));

    std::size_t MaxAlignment =
        1ULL << llvm::CountTrailingZeros_64(uintptr_t(mb->getBufferStart()));

    llvm::error_code ec;
    switch (fileType) {
    case llvm::sys::ELF_Relocatable_FileType: {
      std::pair<unsigned char, unsigned char> Ident = getElfArchType(&*mb);
      std::unique_ptr<File> f;
      // Instantiate the correct FileELF template instance based on the Ident
      // pair. Once the File is created we push the file to the vector of files
      // already created during parser's life.
      if (Ident.first == llvm::ELF::ELFCLASS32 &&
          Ident.second == llvm::ELF::ELFDATA2LSB) {
        if (MaxAlignment >= 4)
          f.reset(new FileELF<ELFType<llvm::support::little, 4, false> >(
                          _elfTargetInfo, std::move(mb), ec));
        else if (MaxAlignment >= 2)
          f.reset(new FileELF<ELFType<llvm::support::little, 2, false> >(
                          _elfTargetInfo, std::move(mb), ec));
        else
          llvm_unreachable("Invalid alignment for ELF file!");
      } else if (Ident.first == llvm::ELF::ELFCLASS32 &&
                 Ident.second == llvm::ELF::ELFDATA2MSB) {
        if (MaxAlignment >= 4)
          f.reset(new FileELF<ELFType<llvm::support::big, 4, false> >(
                          _elfTargetInfo, std::move(mb), ec));
        else if (MaxAlignment >= 2)
          f.reset(new FileELF<ELFType<llvm::support::big, 2, false> >(
                          _elfTargetInfo, std::move(mb), ec));
        else
          llvm_unreachable("Invalid alignment for ELF file!");
      } else if (Ident.first == llvm::ELF::ELFCLASS64 &&
                 Ident.second == llvm::ELF::ELFDATA2MSB) {
        if (MaxAlignment >= 8)
          f.reset(new FileELF<ELFType<llvm::support::big, 8, true> >(
                          _elfTargetInfo, std::move(mb), ec));
        else if (MaxAlignment >= 2)
          f.reset(new FileELF<ELFType<llvm::support::big, 2, true> >(
                          _elfTargetInfo, std::move(mb), ec));
        else
          llvm_unreachable("Invalid alignment for ELF file!");
      } else if (Ident.first == llvm::ELF::ELFCLASS64 &&
                 Ident.second == llvm::ELF::ELFDATA2LSB) {
        if (MaxAlignment >= 8)
          f.reset(new FileELF<ELFType<llvm::support::little, 8, true> >(
                          _elfTargetInfo, std::move(mb), ec));
        else if (MaxAlignment >= 2)
          f.reset(new FileELF<ELFType<llvm::support::little, 2, true> >(
                          _elfTargetInfo, std::move(mb), ec));
        else
          llvm_unreachable("Invalid alignment for ELF file!");
      }
      if (!ec)
        result.push_back(std::move(f));
      break;
    }
    case llvm::sys::Archive_FileType:
      ec = _readerArchive.parseFile(std::move(mb), result);
      break;
    default:
      llvm_unreachable("not supported format");
      break;
    }

    if (ec)
      return ec;

    return error_code::success();
  }

private:
  const ELFTargetInfo &_elfTargetInfo;
  ReaderArchive _readerArchive;
};
} // end anon namespace.

namespace lld {
std::unique_ptr<Reader> createReaderELF(const ELFTargetInfo &eti,
                                        std::function<ReaderFunc> read) {
  return std::unique_ptr<Reader>(new ReaderELF(eti, std::move(read)));
}
} // end namespace lld
OpenPOWER on IntegriCloud