172 lines
5.4 KiB
C++
172 lines
5.4 KiB
C++
//-------------------------------------------------------------------------
|
|
// Mimic GDB's debug file-seeking mechanism. Let:
|
|
// PATH be for-each components of the full DWARF_DEBUG_FILE_DIRECTORY.
|
|
// BIN be the full path to the binary file.
|
|
// DLINK the value of the section ".gnu_debuglink"
|
|
// BLDID build ID from note section GNU/3
|
|
// BLDCAR the lowercase hex-formatted value of the first byte of BLDID
|
|
// BLDCDR the lowercase hex-formatted value of the remaining bytes of BLDID
|
|
//
|
|
// 1) Look for file by build ID
|
|
// foreach PATH in DWARF_DEBUG_FILE_DIRECTORY:
|
|
// if $PATH/.build-id/$BLDCAR/$BLDCRD.debug exists and matches:
|
|
// found!
|
|
// 2) If not found, look for file by debug link
|
|
// if dir($BIN)/$DLINK exists and matches:
|
|
// found!
|
|
// if dir($BIN)/.debug/$DLINK exists and matches:
|
|
// found!
|
|
// foreach PATH in DWARF_DEBUG_FILE_DIRECTORY:
|
|
// if $PATH/dir($BIN)/$DLINK exists and matches:
|
|
// found!
|
|
class debug_info_file_visitor_t
|
|
{
|
|
public:
|
|
char fullpath[MAXSTR]; // current path
|
|
enum checkmethod_t
|
|
{
|
|
BUILDID,
|
|
DEBUGLINK
|
|
};
|
|
|
|
// visit fullpath
|
|
// returns 0 - continue to search
|
|
virtual int visit_fullpath(checkmethod_t check_method)
|
|
{
|
|
int code = 0;
|
|
if ( qfileexist(fullpath) )
|
|
{
|
|
code = 1;
|
|
if ( check_method == DEBUGLINK )
|
|
code = check_debuglink_crc32() ? 1 : 0;
|
|
}
|
|
return code;
|
|
}
|
|
|
|
int call_visit_fullpath(checkmethod_t check_method)
|
|
{
|
|
int code = visit_fullpath(check_method);
|
|
debugout("debug_info_file_visitor_t::visit_fullpath(check_method=%s), fullpath=%s => %d\n",
|
|
check_method == BUILDID ? "BUILDID" : "DEBUGLINK",
|
|
fullpath,
|
|
code);
|
|
return code;
|
|
}
|
|
|
|
debug_info_file_visitor_t(
|
|
const char *_glbl_deb_dirs, // global debug directories
|
|
bool from_envvar, // taken from environment variable
|
|
const char *_path_to_binary, // binary's absolute file name
|
|
const char *_debuglink, // name of the separate debug info file
|
|
uint32 _debuglink_crc32, // CRC32 of the separate debug info file
|
|
const char *_buildid) // build ID
|
|
: path_to_binary(_path_to_binary),
|
|
debuglink(_debuglink),
|
|
buildid(_buildid),
|
|
debuglink_crc32(_debuglink_crc32)
|
|
{
|
|
fullpath[0] = '\0';
|
|
const char *sep = from_envvar ? DELIMITER : ";"; //-V583
|
|
char buf[QMAXPATH];
|
|
qstrncpy(buf, _glbl_deb_dirs, sizeof(buf));
|
|
char *saved_ptr;
|
|
char *p = qstrtok(buf, sep, &saved_ptr);
|
|
while ( p != NULL )
|
|
{
|
|
glbl_deb_dirs.push_back(p);
|
|
p = qstrtok(NULL, sep, &saved_ptr);
|
|
}
|
|
}
|
|
virtual ~debug_info_file_visitor_t() {}
|
|
|
|
// accept visitor
|
|
// stop searching if visitor returns non-zero,
|
|
// returns visitor's result
|
|
int accept(void)
|
|
{
|
|
int code = 0;
|
|
|
|
// Look for file by build ID
|
|
if ( !glbl_deb_dirs.empty() && !buildid.empty() )
|
|
{
|
|
// looks in the .build-id subdirectory of each one of the global debug directories
|
|
// for a file named nn/nnnnnnnn.debug,
|
|
// where nn are the first 2 hex characters of the build ID bit string,
|
|
// and nnnnnnnn are the rest of the bit string
|
|
qstring bid_car(buildid.c_str(), 2);
|
|
qstring bid_cdr(buildid.c_str() + 2);
|
|
bid_cdr.append(".debug");
|
|
|
|
for ( qstrvec_t::const_iterator p=glbl_deb_dirs.begin(); p != glbl_deb_dirs.end(); ++p )
|
|
{
|
|
qmakepath(fullpath, sizeof(fullpath), p->c_str(), ".build-id", bid_car.c_str(), bid_cdr.c_str(), NULL);
|
|
code = call_visit_fullpath(BUILDID);
|
|
if ( code != 0 )
|
|
goto END;
|
|
}
|
|
}
|
|
|
|
// If not found, look for file by debug link
|
|
if ( !debuglink.empty() )
|
|
{
|
|
char bindir[QMAXPATH];
|
|
if ( qdirname(bindir, sizeof(bindir), path_to_binary.c_str()) )
|
|
{
|
|
// in the directory of the executable file
|
|
qmakepath(fullpath, sizeof(fullpath), bindir, debuglink.c_str(), NULL);
|
|
code = call_visit_fullpath(DEBUGLINK);
|
|
if ( code != 0 )
|
|
goto END;
|
|
|
|
// then in a subdirectory of that directory named .debug
|
|
qmakepath(fullpath, sizeof(fullpath), bindir, ".debug", debuglink.c_str(), NULL);
|
|
code = call_visit_fullpath(DEBUGLINK);
|
|
if ( code != 0 )
|
|
goto END;
|
|
|
|
// and finally under each one of the global debug directories,
|
|
// in a subdirectory whose name is identical to the leading directories
|
|
// of the executable's absolute file name
|
|
for ( qstrvec_t::const_iterator p=glbl_deb_dirs.begin(); p != glbl_deb_dirs.end(); ++p )
|
|
{
|
|
qmakepath(fullpath, sizeof(fullpath), p->c_str(), bindir, debuglink.c_str(), NULL);
|
|
code = call_visit_fullpath(DEBUGLINK);
|
|
if ( code != 0 )
|
|
goto END;
|
|
}
|
|
}
|
|
}
|
|
|
|
END:
|
|
return code;
|
|
}
|
|
|
|
// check debuglink file CRC32
|
|
bool check_debuglink_crc32(void)
|
|
{
|
|
linput_t *li = open_linput(fullpath, false);
|
|
uint32 crc32 = calc_file_crc32(li);
|
|
close_linput(li);
|
|
return debuglink_crc32 == crc32;
|
|
}
|
|
|
|
private:
|
|
qstrvec_t glbl_deb_dirs;
|
|
const qstring path_to_binary;
|
|
const qstring debuglink;
|
|
const qstring buildid;
|
|
uint32 debuglink_crc32;
|
|
|
|
AS_PRINTF(2, 3) void debugout(const char *format, ...)
|
|
{
|
|
if ( (debug & LOOK_FOR_DEBUG_FILE_DEBUG_FLAG) != 0 )
|
|
{
|
|
va_list va;
|
|
va_start(va, format);
|
|
vmsg(format, va);
|
|
va_end(va);
|
|
}
|
|
}
|
|
};
|
|
#undef DIFV_DEB
|