Files
sigmaker-ida/idasdk76/plugins/dwarf/look_for_debug_file.cpp
2021-10-31 21:20:46 +02:00

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