1/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "bcc/Support/LinkerConfig.h"
18#include "bcc/Support/Log.h"
19
20#include <llvm/Support/Signals.h>
21
22#include <mcld/MC/MCLDInfo.h>
23#include <mcld/MC/MCLDFile.h>
24#include <mcld/MC/MCLDDirectory.h>
25#include <mcld/LD/TextDiagnosticPrinter.h>
26#include <mcld/Support/Path.h>
27#include <mcld/Support/MsgHandling.h>
28#include <mcld/Support/raw_ostream.h>
29
30using namespace bcc;
31
32LinkerConfig::LinkerConfig(const std::string &pTriple)
33  : mTriple(pTriple), mShared(false), mSOName(), mTarget(NULL), mLDInfo(NULL),
34    mDiagLineInfo(NULL), mDiagPrinter(NULL) {
35
36  initializeTarget();
37  initializeLDInfo();
38  initializeDiagnostic();
39}
40
41LinkerConfig::~LinkerConfig() {
42  delete mLDInfo;
43
44  if (mDiagPrinter->getNumErrors() != 0) {
45    // If here, the program failed ungracefully. Run the interrupt handlers to
46    // ensure any other cleanups (e.g., files that registered by
47    // RemoveFileOnSignal(...)) getting done before exit.
48    llvm::sys::RunInterruptHandlers();
49  }
50  mDiagPrinter->finish();
51
52  delete mDiagLineInfo;
53  delete mDiagPrinter;
54}
55
56bool LinkerConfig::initializeTarget() {
57  std::string error;
58  mTarget = mcld::TargetRegistry::lookupTarget(mTriple, error);
59  if (NULL != mTarget) {
60    return true;
61  } else {
62    ALOGE("Cannot initialize mcld::Target for given triple '%s'! (%s)\n",
63          mTriple.c_str(), error.c_str());
64    return false;
65  }
66}
67
68bool LinkerConfig::initializeLDInfo() {
69  if (NULL != mLDInfo) {
70    ALOGE("Cannot initialize mcld::MCLDInfo for given triple '%s!\n",
71          mTriple.c_str());
72    return false;
73  }
74
75  mLDInfo = new mcld::MCLDInfo(getTriple(), 1, 32);
76  return true;
77}
78
79bool LinkerConfig::initializeDiagnostic() {
80  // Set up MsgHandler.
81  mDiagLineInfo = mTarget->createDiagnosticLineInfo(*mTarget, mTriple);
82
83  mDiagPrinter = new mcld::TextDiagnosticPrinter(mcld::errs(), *mLDInfo);
84
85  mcld::InitializeDiagnosticEngine(*mLDInfo, mDiagLineInfo, mDiagPrinter);
86
87  return true;
88}
89
90void LinkerConfig::setShared(bool pEnable) {
91  mShared = pEnable;
92  return;
93}
94
95void LinkerConfig::setBsymbolic(bool pEnable) {
96  mLDInfo->options().setBsymbolic(pEnable);
97  return;
98}
99
100void LinkerConfig::setSOName(const std::string &pSOName) {
101  mSOName = pSOName;
102  return;
103}
104
105void LinkerConfig::setDyld(const std::string &pDyld) {
106  mLDInfo->options().setDyld(pDyld);
107  return;
108}
109
110void LinkerConfig::setSysRoot(const std::string &pSysRoot) {
111  mLDInfo->options().setSysroot(mcld::sys::fs::Path(pSysRoot));
112  return;
113}
114
115void LinkerConfig::addWrap(const std::string &pWrapSymbol) {
116  bool exist = false;
117
118  // Add wname -> __wrap_wname.
119  mcld::StringEntry<llvm::StringRef>* to_wrap =
120               mLDInfo->scripts().renameMap().insert(pWrapSymbol, exist);
121
122  std::string to_wrap_str = "__wrap_" + pWrapSymbol;
123  to_wrap->setValue(to_wrap_str);
124
125  if (exist) {
126    mcld::warning(mcld::diag::rewrap) << pWrapSymbol << to_wrap_str;
127  }
128
129  // Add __real_wname -> wname.
130  std::string from_real_str = "__real_" + pWrapSymbol;
131  mcld::StringEntry<llvm::StringRef>* from_real =
132             mLDInfo->scripts().renameMap().insert(from_real_str, exist);
133  from_real->setValue(pWrapSymbol);
134
135  if (exist) {
136    mcld::warning(mcld::diag::rewrap) << pWrapSymbol << from_real_str;
137  }
138
139  return;
140}
141
142void LinkerConfig::addPortable(const std::string &pPortableSymbol) {
143  bool exist = false;
144
145  // Add pname -> pname_portable.
146  mcld::StringEntry<llvm::StringRef>* to_port =
147                mLDInfo->scripts().renameMap().insert(pPortableSymbol, exist);
148
149  std::string to_port_str = pPortableSymbol + "_portable";
150  to_port->setValue(to_port_str);
151
152  if (exist) {
153    mcld::warning(mcld::diag::rewrap) << pPortableSymbol << to_port_str;
154}
155
156  // Add __real_pname -> pname.
157  std::string from_real_str = "__real_" + pPortableSymbol;
158  mcld::StringEntry<llvm::StringRef>* from_real =
159           mLDInfo->scripts().renameMap().insert(from_real_str, exist);
160
161  from_real->setValue(pPortableSymbol);
162
163  if (exist) {
164    mcld::warning(mcld::diag::rewrap) << pPortableSymbol << from_real_str;
165  }
166
167  return;
168}
169
170void LinkerConfig::addSearchDir(const std::string &pDirPath) {
171  // SearchDirs will remove the created MCLDDirectory.
172  mcld::MCLDDirectory* sd = new mcld::MCLDDirectory(pDirPath);
173
174  if (sd->isInSysroot()) {
175    sd->setSysroot(mLDInfo->options().sysroot());
176  }
177
178  if (exists(sd->path()) && is_directory(sd->path())) {
179    mLDInfo->options().directories().add(*sd);
180  } else {
181    mcld::warning(mcld::diag::warn_cannot_open_search_dir) << sd->name();
182  }
183
184  return;
185}
186