printStack: rewritten to utilize dladdr for resolution of the stack addresses
Patch provided by Alexey Matveichev Resolves bug-report http://www.openfoam.org/mantisbt/view.php?id=1676
This commit is contained in:
parent
8b9a57af74
commit
218dafd76b
1 changed files with 102 additions and 177 deletions
|
|
@ -24,12 +24,11 @@ License
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "error.H"
|
#include "error.H"
|
||||||
#include "IStringStream.H"
|
|
||||||
#include "OStringStream.H"
|
#include "OStringStream.H"
|
||||||
#include "OSspecific.H"
|
#include "OSspecific.H"
|
||||||
#include "IFstream.H"
|
#include "IFstream.H"
|
||||||
#include "ReadHex.H"
|
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <cxxabi.h>
|
#include <cxxabi.h>
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
@ -43,70 +42,70 @@ namespace Foam
|
||||||
|
|
||||||
string pOpen(const string &cmd, label line=0)
|
string pOpen(const string &cmd, label line=0)
|
||||||
{
|
{
|
||||||
const int MAX = 1000;
|
string res = "\n";
|
||||||
|
|
||||||
FILE *cmdPipe = popen(cmd.c_str(), "r");
|
FILE *cmdPipe = popen(cmd.c_str(), "r");
|
||||||
|
|
||||||
if (cmdPipe)
|
if (cmdPipe)
|
||||||
{
|
{
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
// Read line number of lines
|
// Read line number of lines
|
||||||
for (label cnt = 0; cnt <= line; cnt++)
|
for (label cnt = 0; cnt <= line; cnt++)
|
||||||
{
|
{
|
||||||
char buffer[MAX];
|
size_t linecap = 0;
|
||||||
char* s = fgets(buffer, MAX-1, cmdPipe);
|
ssize_t linelen;
|
||||||
|
linelen = getline(&buf, &linecap, cmdPipe);
|
||||||
|
|
||||||
if (s == NULL)
|
if (linelen < 0)
|
||||||
{
|
{
|
||||||
return "";
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt == line)
|
if (cnt == line)
|
||||||
{
|
{
|
||||||
string str(buffer);
|
res = string(buf);
|
||||||
return str.substr(0, str.size()-1);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buf != NULL)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
pclose(cmdPipe);
|
pclose(cmdPipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return res.substr(0, res.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// use popen to call addr2line (using bfd.h directly would have
|
inline word addressToWord(const uintptr_t addr)
|
||||||
// meant relinking everything)
|
{
|
||||||
|
OStringStream nStream;
|
||||||
|
nStream << "0x" << hex << addr;
|
||||||
|
return nStream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void printSourceFileAndLine
|
void printSourceFileAndLine
|
||||||
(
|
(
|
||||||
Ostream& os,
|
Ostream& os,
|
||||||
const HashTable<label, fileName>& addressMap,
|
|
||||||
const fileName& filename,
|
const fileName& filename,
|
||||||
const word& address
|
Dl_info *info,
|
||||||
|
void *addr
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
word myAddress = address;
|
uintptr_t address = uintptr_t(addr);
|
||||||
|
word myAddress = addressToWord(address);
|
||||||
|
|
||||||
if (filename.ext() == "so")
|
if (filename.ext() == "so")
|
||||||
{
|
{
|
||||||
// Convert offset into .so into offset into executable.
|
// Convert address into offset into dynamic library
|
||||||
|
uintptr_t offset = uintptr_t(info->dli_fbase);
|
||||||
void *addr;
|
intptr_t relativeAddress = address - offset;
|
||||||
sscanf(myAddress.c_str(), "%p", &addr);
|
myAddress = addressToWord(relativeAddress);
|
||||||
|
|
||||||
Dl_info info;
|
|
||||||
|
|
||||||
dladdr(addr, &info);
|
|
||||||
|
|
||||||
uintptr_t offset = uintptr_t(info.dli_fbase);
|
|
||||||
|
|
||||||
IStringStream addressStr(address.substr(2));
|
|
||||||
uintptr_t addressValue = ReadHex<uintptr_t>(addressStr);
|
|
||||||
intptr_t relativeAddress = addressValue - offset;
|
|
||||||
|
|
||||||
// Reconstruct hex word from address
|
|
||||||
OStringStream nStream;
|
|
||||||
nStream << "0x" << hex << relativeAddress;
|
|
||||||
myAddress = nStream.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename[0] == '/')
|
if (filename[0] == '/')
|
||||||
|
|
@ -139,35 +138,58 @@ void printSourceFileAndLine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void getSymbolForRaw
|
fileName absolutePath(const char* fn)
|
||||||
(
|
|
||||||
Ostream& os,
|
|
||||||
const string& raw,
|
|
||||||
const fileName& filename,
|
|
||||||
const word& address
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
if (filename.size() && filename[0] == '/')
|
fileName fname(fn);
|
||||||
{
|
|
||||||
string fcnt = pOpen
|
|
||||||
(
|
|
||||||
"addr2line -f --demangle=auto --exe "
|
|
||||||
+ filename
|
|
||||||
+ " "
|
|
||||||
+ address
|
|
||||||
);
|
|
||||||
|
|
||||||
if (fcnt != "")
|
if (fname[0] != '/' && fname[0] != '~')
|
||||||
|
{
|
||||||
|
string tmp = pOpen("which " + fname);
|
||||||
|
|
||||||
|
if (tmp[0] == '/' || tmp[0] == '~')
|
||||||
{
|
{
|
||||||
os << fcnt.c_str();
|
fname = tmp;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os << "Uninterpreted: " << raw.c_str();
|
|
||||||
|
return fname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void error::safePrintStack(std::ostream& os)
|
word demangleSymbol(const char* sn)
|
||||||
|
{
|
||||||
|
word res;
|
||||||
|
int st;
|
||||||
|
char* cxx_sname = abi::__cxa_demangle
|
||||||
|
(
|
||||||
|
sn,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
&st
|
||||||
|
);
|
||||||
|
|
||||||
|
if (st == 0 && cxx_sname)
|
||||||
|
{
|
||||||
|
res = word(cxx_sname);
|
||||||
|
free(cxx_sname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = word(sn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::error::safePrintStack(std::ostream& os)
|
||||||
{
|
{
|
||||||
// Get raw stack symbols
|
// Get raw stack symbols
|
||||||
void *array[100];
|
void *array[100];
|
||||||
|
|
@ -187,143 +209,46 @@ void error::safePrintStack(std::ostream& os)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void error::printStack(Ostream& os)
|
void Foam::error::printStack(Ostream& os)
|
||||||
{
|
{
|
||||||
// Reads the starting addresses for the dynamically linked libraries
|
|
||||||
// from the /proc/pid/maps-file
|
|
||||||
// I'm afraid this works only for Linux 2.6-Kernels (may work on 2.4)
|
|
||||||
// Note2: the filenames in here will have softlinks resolved so will
|
|
||||||
// go wrong when having e.g. OpenFOAM installed under a softlink.
|
|
||||||
|
|
||||||
HashTable<label, fileName> addressMap;
|
|
||||||
{
|
|
||||||
IFstream is("/proc/" + name(pid()) + "/maps");
|
|
||||||
|
|
||||||
while (is.good())
|
|
||||||
{
|
|
||||||
string line;
|
|
||||||
is.getLine(line);
|
|
||||||
|
|
||||||
string::size_type space = line.rfind(' ') + 1;
|
|
||||||
fileName libPath = line.substr(space, line.size()-space);
|
|
||||||
|
|
||||||
if (libPath.size() && libPath[0] == '/')
|
|
||||||
{
|
|
||||||
string offsetString(line.substr(0, line.find('-')));
|
|
||||||
IStringStream offsetStr(offsetString);
|
|
||||||
addressMap.insert(libPath, ReadHex<label>(offsetStr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get raw stack symbols
|
// Get raw stack symbols
|
||||||
void *array[100];
|
const size_t CALLSTACK_SIZE = 128;
|
||||||
size_t size = backtrace(array, 100);
|
|
||||||
char **strings = backtrace_symbols(array, size);
|
|
||||||
|
|
||||||
// See if they contain function between () e.g. "(__libc_start_main+0xd0)"
|
void *callstack[CALLSTACK_SIZE];
|
||||||
// and see if cplus_demangle can make sense of part before +
|
size_t size = backtrace(callstack, CALLSTACK_SIZE);
|
||||||
for (size_t i = 0; i < size; i++)
|
|
||||||
|
Dl_info *info = new Dl_info;
|
||||||
|
|
||||||
|
fileName fname = "???";
|
||||||
|
word address;
|
||||||
|
|
||||||
|
for(size_t i=0; i<size; i++)
|
||||||
{
|
{
|
||||||
string msg(strings[i]);
|
int st = dladdr(callstack[i], info);
|
||||||
fileName programFile;
|
|
||||||
word address;
|
|
||||||
|
|
||||||
os << '#' << label(i) << " ";
|
os << '#' << label(i) << " ";
|
||||||
//os << "Raw : " << msg << "\n\t";
|
if (st != 0 && info->dli_fname != NULL && info->dli_fname[0] != '\0')
|
||||||
{
|
{
|
||||||
string::size_type lPos = msg.find('[');
|
fname = absolutePath(info->dli_fname);
|
||||||
string::size_type rPos = msg.find(']');
|
|
||||||
|
|
||||||
if (lPos != string::npos && rPos != string::npos && lPos < rPos)
|
os <<
|
||||||
{
|
(
|
||||||
address = msg.substr(lPos+1, rPos-lPos-1);
|
(info->dli_sname != NULL)
|
||||||
msg = msg.substr(0, lPos);
|
? demangleSymbol(info->dli_sname)
|
||||||
}
|
: "?"
|
||||||
|
);
|
||||||
string::size_type bracketPos = msg.find('(');
|
|
||||||
string::size_type spacePos = msg.find(' ');
|
|
||||||
if (bracketPos != string::npos || spacePos != string::npos)
|
|
||||||
{
|
|
||||||
programFile = msg.substr(0, min(spacePos, bracketPos));
|
|
||||||
|
|
||||||
// not an absolute path
|
|
||||||
if (programFile[0] != '/')
|
|
||||||
{
|
|
||||||
string tmp = pOpen("which " + programFile);
|
|
||||||
if (tmp[0] == '/' || tmp[0] == '~')
|
|
||||||
{
|
|
||||||
programFile = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string::size_type bracketPos = msg.find('(');
|
|
||||||
|
|
||||||
if (bracketPos != string::npos)
|
|
||||||
{
|
|
||||||
string::size_type start = bracketPos+1;
|
|
||||||
|
|
||||||
string::size_type plusPos = msg.find('+', start);
|
|
||||||
|
|
||||||
if (plusPos != string::npos)
|
|
||||||
{
|
|
||||||
string cName(msg.substr(start, plusPos-start));
|
|
||||||
|
|
||||||
int status;
|
|
||||||
char* cplusNamePtr = abi::__cxa_demangle
|
|
||||||
(
|
|
||||||
cName.c_str(),
|
|
||||||
NULL, // have it malloc itself
|
|
||||||
0,
|
|
||||||
&status
|
|
||||||
);
|
|
||||||
|
|
||||||
if (status == 0 && cplusNamePtr)
|
|
||||||
{
|
|
||||||
os << cplusNamePtr;
|
|
||||||
free(cplusNamePtr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
os << cName.c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string::size_type endBracketPos = msg.find(')', start);
|
|
||||||
|
|
||||||
if (endBracketPos != string::npos)
|
|
||||||
{
|
|
||||||
string fullName(msg.substr(start, endBracketPos-start));
|
|
||||||
|
|
||||||
os << fullName.c_str() << nl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Print raw message
|
|
||||||
getSymbolForRaw(os, msg, programFile, address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Print raw message
|
os << "?";
|
||||||
getSymbolForRaw(os, msg, programFile, address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printSourceFileAndLine(os, addressMap, programFile, address);
|
printSourceFileAndLine(os, fname, info, callstack[i]);
|
||||||
|
os << nl;
|
||||||
os << nl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(strings);
|
delete info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
} // End namespace Foam
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue