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