4622d11087
2005/09/05 18:39:42 rt 1.2.30.1: #i54170# Change license header: remove SISSL
310 lines
9.9 KiB
C++
310 lines
9.9 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: adjustvisibility.cxx,v $
|
|
*
|
|
* $Revision: 1.3 $
|
|
*
|
|
* last change: $Author: rt $ $Date: 2005-09-08 07:22:24 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
************************************************************************/
|
|
|
|
/*
|
|
* adjustvisibilty -- a tool to adjust the visibility of the so called
|
|
* 'fix and continue' globalized symbols generated by
|
|
* the Sun Studio 8 compiler from 'DEFAULT' to 'HIDDEN'
|
|
*
|
|
* References: "Linker and Libraries Guide", Solaris 9 documentation
|
|
* "Stabs Interface", SunStudio 8 documentation
|
|
*/
|
|
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <exception>
|
|
#include <stdexcept>
|
|
#include <cerrno>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <libelf.h>
|
|
#include <gelf.h>
|
|
#include <utime.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
// Note: There is no GELF_ST_VISIBILITY macro in gelf.h, we roll our own.
|
|
#define GELF_ST_VISIBILITY(o) ((o)&0x3) // See "Linker and Libraries Guide".
|
|
|
|
// See "Linker and Libraries Guide", ELF object format description.
|
|
static const char* SymbolType[STT_NUM] = {
|
|
"NOTYPE",
|
|
"OBJECT",
|
|
"FUNC ",
|
|
"SECT ",
|
|
"FILE ",
|
|
"COMM ",
|
|
"TLS "
|
|
};
|
|
|
|
static const char* SymbolBinding[STB_NUM] = {
|
|
"LOCAL ",
|
|
"GLOBAL",
|
|
"WEAK "
|
|
};
|
|
|
|
static const char* SymbolVisibility[4] = { // Note: There is no STV_NUM macro
|
|
"DEFAULT ",
|
|
"INTERNAL ",
|
|
"HIDDEN ",
|
|
"PROTECTED"
|
|
};
|
|
|
|
class ElfError : public std::exception
|
|
{
|
|
public:
|
|
ElfError(const std::string& rFile, const std::string& rMessage);
|
|
~ElfError() throw() {};
|
|
virtual const char* what() const throw() { return m_sMessage.c_str(); }
|
|
|
|
private:
|
|
std::string m_sMessage;
|
|
};
|
|
|
|
ElfError::ElfError(const std::string& rFile, const std::string& rMessage)
|
|
{
|
|
if ( rFile != "" ) {
|
|
m_sMessage = rFile;
|
|
m_sMessage += ": ";
|
|
}
|
|
m_sMessage += rMessage;
|
|
const char *pElfMsg = elf_errmsg(0);
|
|
if ( pElfMsg ) {
|
|
m_sMessage += ": ";
|
|
m_sMessage += pElfMsg;
|
|
}
|
|
}
|
|
|
|
void initElfLib()
|
|
{
|
|
if ( elf_version(EV_CURRENT) == EV_NONE) {
|
|
throw ElfError("", "elf_version() failed");
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool isFixAndContinueSymbol(const std::string& rSymbol)
|
|
{
|
|
// The globalized 'fix and continue' symbols have the following
|
|
// form, see "Stabs interface", page 164:
|
|
// {.$}X{ABC}uniquepattern[.function_name][EQUIVn][.variable_name]
|
|
char c0 = rSymbol[0];
|
|
char c1 = rSymbol[1];
|
|
char c2 = rSymbol[2];
|
|
if ( c0 == '.' || c0 == '$' ) {
|
|
if ( c1 == 'X' ) {
|
|
if ( c2 == 'A' || c2 == 'B' || c2 == 'C' || c2 == 'D' ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void adjustVisibility( const std::string& rFile, int fd, bool bVerbose)
|
|
{
|
|
if ( bVerbose ) {
|
|
std::cout << "File: " << rFile << ": adjusting 'fix and continue' symbol visibility\n";
|
|
}
|
|
|
|
try {
|
|
Elf* pElf;
|
|
if ((pElf = elf_begin(fd, ELF_C_RDWR, 0)) == NULL) {
|
|
throw ElfError(rFile, "elf_begin() failed");
|
|
}
|
|
// Check if file is ELF file.
|
|
if ( elf_kind(pElf) != ELF_K_ELF ) {
|
|
throw ElfError(rFile, "elf_kind() failed, file is not an ELF object file");
|
|
}
|
|
|
|
// Iterate over sections.
|
|
Elf_Scn* pScn = 0;
|
|
while ( (pScn = elf_nextscn(pElf, pScn)) != 0 ) {
|
|
GElf_Shdr aShdr;
|
|
if ( gelf_getshdr(pScn, &aShdr) == 0 ) {
|
|
throw ElfError(rFile, "gelf_getshdr() failed");
|
|
}
|
|
if ( aShdr.sh_type != SHT_SYMTAB ) {
|
|
continue;
|
|
}
|
|
// Section is a symbol section. Get the assiociated data.
|
|
Elf_Data* pSymbolData;
|
|
if ( (pSymbolData = elf_getdata(pScn, 0)) == NULL ) {
|
|
throw ElfError(rFile, "elf_getdata() failed");
|
|
}
|
|
// Iterate over symbol table.
|
|
unsigned int nSymbols = aShdr.sh_size / aShdr.sh_entsize;
|
|
for ( unsigned int nIndex = 0; nIndex < nSymbols; ++nIndex) {
|
|
// Get symbol.
|
|
GElf_Sym aSymbol;
|
|
if ( gelf_getsym(pSymbolData, nIndex, &aSymbol) == NULL )
|
|
{
|
|
throw ElfError(rFile, "gelf_getsym() failed");
|
|
}
|
|
std::string sSymbolName(elf_strptr(pElf, aShdr.sh_link, aSymbol.st_name));
|
|
if ( isFixAndContinueSymbol(sSymbolName) ) {
|
|
// Get the symbol visibility.
|
|
unsigned int nSymbolVisibility = GELF_ST_VISIBILITY(aSymbol.st_other);
|
|
if ( bVerbose ) {
|
|
// Get the symbol type and binding.
|
|
unsigned int nSymbolType = GELF_ST_TYPE(aSymbol.st_info);
|
|
unsigned int nSymbolBind = GELF_ST_BIND(aSymbol.st_info);
|
|
std::cout << "Symbol: " << sSymbolName << ", "
|
|
<< "Type: ";
|
|
if ( SymbolType[nSymbolType] ) {
|
|
std::cout << SymbolType[nSymbolType];
|
|
} else {
|
|
std::cout << nSymbolType;
|
|
}
|
|
std::cout << ", Binding: ";
|
|
if ( SymbolBinding[nSymbolBind] ) {
|
|
std::cout << SymbolBinding[nSymbolBind];
|
|
} else {
|
|
std::cout << nSymbolBind;
|
|
}
|
|
std::cout << ", Visibility: ";
|
|
if ( SymbolVisibility[nSymbolVisibility] ) {
|
|
std::cout << SymbolVisibility[nSymbolVisibility];
|
|
} else {
|
|
std::cout << nSymbolVisibility;
|
|
}
|
|
std::cout << "-> " << SymbolVisibility[STV_HIDDEN] << "\n";
|
|
}
|
|
// Toggle visibility to "hidden".
|
|
aSymbol.st_other = GELF_ST_VISIBILITY(STV_HIDDEN);
|
|
// Write back symbol data to underlying structure.
|
|
if ( gelf_update_sym(pSymbolData, nIndex, &aSymbol) == NULL )
|
|
{
|
|
throw ElfError(rFile, "gelf_update_sym() failed");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Write changed object file to disk.
|
|
if ( elf_update(pElf, ELF_C_WRITE) == -1 ) {
|
|
throw ElfError(rFile, "elf_update() failed");
|
|
}
|
|
elf_end(pElf);
|
|
|
|
} catch (ElfError& e) {
|
|
close(fd);
|
|
throw;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void processObject(const std::string& rFile, bool bPreserve, bool bVerbose)
|
|
{
|
|
int fd;
|
|
struct stat aStatBuf;
|
|
|
|
if ((fd = open(rFile.c_str(), O_RDWR)) == -1) {
|
|
std::string sMessage("adjustVisibilty() failed: can't open file ");
|
|
sMessage += rFile;
|
|
sMessage += ": ";
|
|
sMessage += std::strerror(errno);
|
|
throw std::runtime_error(sMessage);
|
|
}
|
|
|
|
if ( bPreserve ) {
|
|
if ( fstat(fd, &aStatBuf) == -1) {
|
|
std::string sMessage("adjustVisibilty() failed: can't stat file ");
|
|
sMessage += rFile;
|
|
sMessage += ": ";
|
|
sMessage += std::strerror(errno);
|
|
throw std::runtime_error(sMessage);
|
|
}
|
|
}
|
|
|
|
adjustVisibility(rFile, fd, bVerbose);
|
|
|
|
close(fd);
|
|
|
|
if ( bPreserve ) {
|
|
struct utimbuf aUtimBuf = {aStatBuf.st_atime, aStatBuf.st_mtime};
|
|
if ( utime(rFile.c_str(), &aUtimBuf) == -1 ) {
|
|
std::string sMessage("adjustVisibilty() failed: can't reset timestamp ");
|
|
sMessage += rFile;
|
|
sMessage += ": ";
|
|
sMessage += std::strerror(errno);
|
|
throw std::runtime_error(sMessage);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
int c;
|
|
bool bPreserve = false;
|
|
bool bVerbose = false;
|
|
|
|
while ( (c = getopt(argc, argv, "pv")) != -1 ) {
|
|
switch(c) {
|
|
case 'p':
|
|
bPreserve = true;
|
|
break;
|
|
case 'v':
|
|
bVerbose = true;
|
|
break;
|
|
case '?':
|
|
std::cerr << "Unrecognized option: -" << optopt << "\n";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( optind == argc ) {
|
|
std::cout << "usage: " << argv[0] << " [-pv] <elf-object> ...\n";
|
|
std::cout << " -p preserve time stamps\n";
|
|
std::cout << " -v verbose\n";
|
|
return 1;
|
|
}
|
|
|
|
try {
|
|
initElfLib();
|
|
|
|
for ( ; optind < argc; optind++ ) {
|
|
processObject(std::string(argv[optind]), bPreserve, bVerbose);
|
|
}
|
|
|
|
} catch (std::exception& e) {
|
|
std::cerr << argv[0] << ": " << e.what() << "\n";
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|