OOO330
[LibreOffice.git] / soltools / adjustvisibility / adjustvisibility.cxx
blobe67017018b1af676a02873094061787f5cd95454
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_soltools.hxx"
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'
36 * References: "Linker and Libraries Guide", Solaris 9 documentation
37 * "Stabs Interface", SunStudio 8 documentation
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>
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".
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 "
69 static const char* SymbolBinding[STB_NUM] = {
70 "LOCAL ",
71 "GLOBAL",
72 "WEAK "
75 static const char* SymbolVisibility[4] = { // Note: There is no STV_NUM macro
76 "DEFAULT ",
77 "INTERNAL ",
78 "HIDDEN ",
79 "PROTECTED"
82 class ElfError : public std::exception
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(); }
89 private:
90 std::string m_sMessage;
93 ElfError::ElfError(const std::string& rFile, const std::string& rMessage)
95 if ( rFile != "" ) {
96 m_sMessage = rFile;
97 m_sMessage += ": ";
99 m_sMessage += rMessage;
100 const char *pElfMsg = elf_errmsg(0);
101 if ( pElfMsg ) {
102 m_sMessage += ": ";
103 m_sMessage += pElfMsg;
107 void initElfLib()
109 if ( elf_version(EV_CURRENT) == EV_NONE) {
110 throw ElfError("", "elf_version() failed");
112 return;
115 bool isFixAndContinueSymbol(const std::string& rSymbol)
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;
130 return false;
133 void adjustVisibility( const std::string& rFile, int fd, bool bVerbose)
135 if ( bVerbose ) {
136 std::cout << "File: " << rFile << ": adjusting 'fix and continue' symbol visibility\n";
139 try {
140 Elf* pElf;
141 if ((pElf = elf_begin(fd, ELF_C_RDWR, 0)) == NULL) {
142 throw ElfError(rFile, "elf_begin() failed");
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");
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");
156 if ( aShdr.sh_type != SHT_SYMTAB ) {
157 continue;
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");
164 // Iterate over symbol table.
165 GElf_Xword nSymbols = aShdr.sh_size / aShdr.sh_entsize;
166 if ( nSymbols > std::numeric_limits< int >::max() )
168 throw ElfError(rFile, "too many symbols");
170 for ( int nIndex = 0; nIndex < nSymbols; ++nIndex) {
171 // Get symbol.
172 GElf_Sym aSymbol;
173 if ( gelf_getsym(pSymbolData, nIndex, &aSymbol) == NULL )
175 throw ElfError(rFile, "gelf_getsym() failed");
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;
192 std::cout << ", Binding: ";
193 if ( SymbolBinding[nSymbolBind] ) {
194 std::cout << SymbolBinding[nSymbolBind];
195 } else {
196 std::cout << nSymbolBind;
198 std::cout << ", Visibility: ";
199 if ( SymbolVisibility[nSymbolVisibility] ) {
200 std::cout << SymbolVisibility[nSymbolVisibility];
201 } else {
202 std::cout << nSymbolVisibility;
204 std::cout << "-> " << SymbolVisibility[STV_HIDDEN] << "\n";
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 )
211 throw ElfError(rFile, "gelf_update_sym() failed");
216 // Write changed object file to disk.
217 if ( elf_update(pElf, ELF_C_WRITE) == -1 ) {
218 throw ElfError(rFile, "elf_update() failed");
220 elf_end(pElf);
222 } catch (ElfError& e) {
223 close(fd);
224 throw;
226 return;
229 void processObject(const std::string& rFile, bool bPreserve, bool bVerbose)
231 int fd;
232 struct stat aStatBuf;
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);
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);
252 adjustVisibility(rFile, fd, bVerbose);
254 close(fd);
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);
266 return;
269 int main(int argc, char* argv[])
271 int c;
272 bool bPreserve = false;
273 bool bVerbose = false;
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;
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;
298 try {
299 initElfLib();
301 for ( ; optind < argc; optind++ ) {
302 processObject(std::string(argv[optind]), bPreserve, bVerbose);
305 } catch (std::exception& e) {
306 std::cerr << argv[0] << ": " << e.what() << "\n";
307 return 1;
310 return 0;