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); 82 ~ElfError() throw() {}; 83 virtual const char* what() const throw() { return m_sMessage.c_str(); } 84 85 private: 86 std::string m_sMessage; 87 }; 88 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 103 void initElfLib() 104 { 105 if ( elf_version(EV_CURRENT) == EV_NONE) { 106 throw ElfError("", "elf_version() failed"); 107 } 108 return; 109 } 110 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 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 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 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