1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_soltools.hxx"
26
27 /*
28 * adjustvisibilty -- a tool to adjust the visibility of the so called
29 * 'fix and continue' globalized symbols generated by
30 * the Sun Studio 8 compiler from 'DEFAULT' to 'HIDDEN'
31 *
32 * References: "Linker and Libraries Guide", Solaris 9 documentation
33 * "Stabs Interface", SunStudio 8 documentation
34 */
35
36 #include <string>
37 #include <iostream>
38 #include <exception>
39 #include <stdexcept>
40 #include <cerrno>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <libelf.h>
44 #include <gelf.h>
45 #include <utime.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <limits>
49 #include <stdio.h>
50
51 // Note: There is no GELF_ST_VISIBILITY macro in gelf.h, we roll our own.
52 #define GELF_ST_VISIBILITY(o) ((o)&0x3) // See "Linker and Libraries Guide".
53
54 // See "Linker and Libraries Guide", ELF object format description.
55 static const char* SymbolType[STT_NUM] = {
56 "NOTYPE",
57 "OBJECT",
58 "FUNC ",
59 "SECT ",
60 "FILE ",
61 "COMM ",
62 "TLS "
63 };
64
65 static const char* SymbolBinding[STB_NUM] = {
66 "LOCAL ",
67 "GLOBAL",
68 "WEAK "
69 };
70
71 static const char* SymbolVisibility[4] = { // Note: There is no STV_NUM macro
72 "DEFAULT ",
73 "INTERNAL ",
74 "HIDDEN ",
75 "PROTECTED"
76 };
77
78 class ElfError : public std::exception
79 {
80 public:
81 ElfError(const std::string& rFile, const std::string& rMessage);
~ElfError()82 ~ElfError() throw() {};
what() const83 virtual const char* what() const throw() { return m_sMessage.c_str(); }
84
85 private:
86 std::string m_sMessage;
87 };
88
ElfError(const std::string & rFile,const std::string & rMessage)89 ElfError::ElfError(const std::string& rFile, const std::string& rMessage)
90 {
91 if ( rFile != "" ) {
92 m_sMessage = rFile;
93 m_sMessage += ": ";
94 }
95 m_sMessage += rMessage;
96 const char *pElfMsg = elf_errmsg(0);
97 if ( pElfMsg ) {
98 m_sMessage += ": ";
99 m_sMessage += pElfMsg;
100 }
101 }
102
initElfLib()103 void initElfLib()
104 {
105 if ( elf_version(EV_CURRENT) == EV_NONE) {
106 throw ElfError("", "elf_version() failed");
107 }
108 return;
109 }
110
isFixAndContinueSymbol(const std::string & rSymbol)111 bool isFixAndContinueSymbol(const std::string& rSymbol)
112 {
113 // The globalized 'fix and continue' symbols have the following
114 // form, see "Stabs interface", page 164:
115 // {.$}X{ABC}uniquepattern[.function_name][EQUIVn][.variable_name]
116 char c0 = rSymbol[0];
117 char c1 = rSymbol[1];
118 char c2 = rSymbol[2];
119 if ( c0 == '.' || c0 == '$' ) {
120 if ( c1 == 'X' ) {
121 if ( c2 == 'A' || c2 == 'B' || c2 == 'C' || c2 == 'D' ) {
122 return true;
123 }
124 }
125 }
126 return false;
127 }
128
adjustVisibility(const std::string & rFile,int fd,bool bVerbose)129 void adjustVisibility( const std::string& rFile, int fd, bool bVerbose)
130 {
131 if ( bVerbose ) {
132 std::cout << "File: " << rFile << ": adjusting 'fix and continue' symbol visibility\n";
133 }
134
135 try {
136 Elf* pElf;
137 if ((pElf = elf_begin(fd, ELF_C_RDWR, 0)) == NULL) {
138 throw ElfError(rFile, "elf_begin() failed");
139 }
140 // Check if file is ELF file.
141 if ( elf_kind(pElf) != ELF_K_ELF ) {
142 throw ElfError(rFile, "elf_kind() failed, file is not an ELF object file");
143 }
144
145 // Iterate over sections.
146 Elf_Scn* pScn = 0;
147 while ( (pScn = elf_nextscn(pElf, pScn)) != 0 ) {
148 GElf_Shdr aShdr;
149 if ( gelf_getshdr(pScn, &aShdr) == 0 ) {
150 throw ElfError(rFile, "gelf_getshdr() failed");
151 }
152 if ( aShdr.sh_type != SHT_SYMTAB ) {
153 continue;
154 }
155 // Section is a symbol section. Get the assiociated data.
156 Elf_Data* pSymbolData;
157 if ( (pSymbolData = elf_getdata(pScn, 0)) == NULL ) {
158 throw ElfError(rFile, "elf_getdata() failed");
159 }
160 // Iterate over symbol table.
161 GElf_Xword nSymbols = aShdr.sh_size / aShdr.sh_entsize;
162 if ( nSymbols > std::numeric_limits< int >::max() )
163 {
164 throw ElfError(rFile, "too many symbols");
165 }
166 for ( int nIndex = 0; nIndex < nSymbols; ++nIndex) {
167 // Get symbol.
168 GElf_Sym aSymbol;
169 if ( gelf_getsym(pSymbolData, nIndex, &aSymbol) == NULL )
170 {
171 throw ElfError(rFile, "gelf_getsym() failed");
172 }
173 std::string sSymbolName(elf_strptr(pElf, aShdr.sh_link, aSymbol.st_name));
174 if ( isFixAndContinueSymbol(sSymbolName) ) {
175 // Get the symbol visibility.
176 unsigned int nSymbolVisibility = GELF_ST_VISIBILITY(aSymbol.st_other);
177 if ( bVerbose ) {
178 // Get the symbol type and binding.
179 unsigned int nSymbolType = GELF_ST_TYPE(aSymbol.st_info);
180 unsigned int nSymbolBind = GELF_ST_BIND(aSymbol.st_info);
181 std::cout << "Symbol: " << sSymbolName << ", "
182 << "Type: ";
183 if ( SymbolType[nSymbolType] ) {
184 std::cout << SymbolType[nSymbolType];
185 } else {
186 std::cout << nSymbolType;
187 }
188 std::cout << ", Binding: ";
189 if ( SymbolBinding[nSymbolBind] ) {
190 std::cout << SymbolBinding[nSymbolBind];
191 } else {
192 std::cout << nSymbolBind;
193 }
194 std::cout << ", Visibility: ";
195 if ( SymbolVisibility[nSymbolVisibility] ) {
196 std::cout << SymbolVisibility[nSymbolVisibility];
197 } else {
198 std::cout << nSymbolVisibility;
199 }
200 std::cout << "-> " << SymbolVisibility[STV_HIDDEN] << "\n";
201 }
202 // Toggle visibility to "hidden".
203 aSymbol.st_other = GELF_ST_VISIBILITY(STV_HIDDEN);
204 // Write back symbol data to underlying structure.
205 if ( gelf_update_sym(pSymbolData, nIndex, &aSymbol) == NULL )
206 {
207 throw ElfError(rFile, "gelf_update_sym() failed");
208 }
209 }
210 }
211 }
212 // Write changed object file to disk.
213 if ( elf_update(pElf, ELF_C_WRITE) == -1 ) {
214 throw ElfError(rFile, "elf_update() failed");
215 }
216 elf_end(pElf);
217
218 } catch (ElfError& e) {
219 close(fd);
220 throw;
221 }
222 return;
223 }
224
processObject(const std::string & rFile,bool bPreserve,bool bVerbose)225 void processObject(const std::string& rFile, bool bPreserve, bool bVerbose)
226 {
227 int fd;
228 struct stat aStatBuf;
229
230 if ((fd = open(rFile.c_str(), O_RDWR)) == -1) {
231 std::string sMessage("adjustVisibilty() failed: can't open file ");
232 sMessage += rFile;
233 sMessage += ": ";
234 sMessage += std::strerror(errno);
235 throw std::runtime_error(sMessage);
236 }
237
238 if ( bPreserve ) {
239 if ( fstat(fd, &aStatBuf) == -1) {
240 std::string sMessage("adjustVisibilty() failed: can't stat file ");
241 sMessage += rFile;
242 sMessage += ": ";
243 sMessage += std::strerror(errno);
244 throw std::runtime_error(sMessage);
245 }
246 }
247
248 adjustVisibility(rFile, fd, bVerbose);
249
250 close(fd);
251
252 if ( bPreserve ) {
253 struct utimbuf aUtimBuf = {aStatBuf.st_atime, aStatBuf.st_mtime};
254 if ( utime(rFile.c_str(), &aUtimBuf) == -1 ) {
255 std::string sMessage("adjustVisibilty() failed: can't reset timestamp ");
256 sMessage += rFile;
257 sMessage += ": ";
258 sMessage += std::strerror(errno);
259 throw std::runtime_error(sMessage);
260 }
261 }
262 return;
263 }
264
main(int argc,char * argv[])265 int main(int argc, char* argv[])
266 {
267 int c;
268 bool bPreserve = false;
269 bool bVerbose = false;
270
271 while ( (c = getopt(argc, argv, "pv")) != -1 ) {
272 switch(c) {
273 case 'p':
274 bPreserve = true;
275 break;
276 case 'v':
277 bVerbose = true;
278 break;
279 case '?':
280 std::cerr << "Unrecognized option: -" << optopt << "\n";
281 break;
282 default:
283 break;
284 }
285 }
286
287 if ( optind == argc ) {
288 std::cout << "usage: " << argv[0] << " [-pv] <elf-object> ...\n";
289 std::cout << " -p preserve time stamps\n";
290 std::cout << " -v verbose\n";
291 return 1;
292 }
293
294 try {
295 initElfLib();
296
297 for ( ; optind < argc; optind++ ) {
298 processObject(std::string(argv[optind]), bPreserve, bVerbose);
299 }
300
301 } catch (std::exception& e) {
302 std::cerr << argv[0] << ": " << e.what() << "\n";
303 return 1;
304 }
305
306 return 0;
307 }
308