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