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