1 //===- ELFConfig.cpp ------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CopyConfig.h"
10 #include "llvm/ADT/Optional.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/Error.h"
14 
15 namespace llvm {
16 namespace objcopy {
17 namespace elf {
18 
parseNewSymbolInfo(StringRef FlagValue,uint8_t DefaultVisibility)19 static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
20                                                   uint8_t DefaultVisibility) {
21   // Parse value given with --add-symbol option and create the
22   // new symbol if possible. The value format for --add-symbol is:
23   //
24   // <name>=[<section>:]<value>[,<flags>]
25   //
26   // where:
27   // <name> - symbol name, can be empty string
28   // <section> - optional section name. If not given ABS symbol is created
29   // <value> - symbol value, can be decimal or hexadecimal number prefixed
30   //           with 0x.
31   // <flags> - optional flags affecting symbol type, binding or visibility:
32   //           The following are currently supported:
33   //
34   //           global, local, weak, default, hidden, file, section, object,
35   //           indirect-function.
36   //
37   //           The following flags are ignored and provided for GNU
38   //           compatibility only:
39   //
40   //           warning, debug, constructor, indirect, synthetic,
41   //           unique-object, before=<symbol>.
42   NewSymbolInfo SI;
43   StringRef Value;
44   std::tie(SI.SymbolName, Value) = FlagValue.split('=');
45   if (Value.empty())
46     return createStringError(
47         errc::invalid_argument,
48         "bad format for --add-symbol, missing '=' after '%s'",
49         SI.SymbolName.str().c_str());
50 
51   if (Value.contains(':')) {
52     std::tie(SI.SectionName, Value) = Value.split(':');
53     if (SI.SectionName.empty() || Value.empty())
54       return createStringError(
55           errc::invalid_argument,
56           "bad format for --add-symbol, missing section name or symbol value");
57   }
58 
59   SmallVector<StringRef, 6> Flags;
60   Value.split(Flags, ',');
61   if (Flags[0].getAsInteger(0, SI.Value))
62     return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
63                              Flags[0].str().c_str());
64 
65   SI.Visibility = DefaultVisibility;
66 
67   using Functor = std::function<void(void)>;
68   SmallVector<StringRef, 6> UnsupportedFlags;
69   for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
70     static_cast<Functor>(
71         StringSwitch<Functor>(Flags[I])
72             .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
73             .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
74             .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
75             .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
76             .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
77             .CaseLower("protected",
78                        [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
79             .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
80             .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
81             .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
82             .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
83             .CaseLower("indirect-function",
84                        [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
85             .CaseLower("debug", [] {})
86             .CaseLower("constructor", [] {})
87             .CaseLower("warning", [] {})
88             .CaseLower("indirect", [] {})
89             .CaseLower("synthetic", [] {})
90             .CaseLower("unique-object", [] {})
91             .StartsWithLower("before", [] {})
92             .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
93   if (!UnsupportedFlags.empty())
94     return createStringError(errc::invalid_argument,
95                              "unsupported flag%s for --add-symbol: '%s'",
96                              UnsupportedFlags.size() > 1 ? "s" : "",
97                              join(UnsupportedFlags, "', '").c_str());
98   return SI;
99 }
100 
parseConfig(const CopyConfig & Config)101 Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) {
102   ELFCopyConfig ELFConfig;
103   if (Config.NewSymbolVisibility) {
104     const uint8_t Invalid = 0xff;
105     ELFConfig.NewSymbolVisibility =
106         StringSwitch<uint8_t>(*Config.NewSymbolVisibility)
107             .Case("default", ELF::STV_DEFAULT)
108             .Case("hidden", ELF::STV_HIDDEN)
109             .Case("internal", ELF::STV_INTERNAL)
110             .Case("protected", ELF::STV_PROTECTED)
111             .Default(Invalid);
112 
113     if (ELFConfig.NewSymbolVisibility == Invalid)
114       return createStringError(errc::invalid_argument,
115                                "'%s' is not a valid symbol visibility",
116                                Config.NewSymbolVisibility->str().c_str());
117   }
118 
119   for (StringRef Arg : Config.SymbolsToAdd) {
120     Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo(
121         Arg,
122         ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
123     if (!NSI)
124       return NSI.takeError();
125     ELFConfig.SymbolsToAdd.push_back(*NSI);
126   }
127 
128   return ELFConfig;
129 }
130 
131 } // end namespace elf
132 } // end namespace objcopy
133 } // end namespace llvm
134