mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-22 22:44:34 +00:00
Merge pull request #674 from tiago-rodrigues/trodrigues/offline_symbol_resolve_and_imagecache2
Add image cache to avoid calling dladdr() and add libbacktrace elf image list refresh
This commit is contained in:
commit
9bc014b183
@ -86,6 +86,7 @@ set_option(TRACY_NO_CRASH_HANDLER "Disable crash handling" OFF)
|
|||||||
set_option(TRACY_TIMER_FALLBACK "Use lower resolution timers" OFF)
|
set_option(TRACY_TIMER_FALLBACK "Use lower resolution timers" OFF)
|
||||||
set_option(TRACE_CLIENT_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF)
|
set_option(TRACE_CLIENT_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF)
|
||||||
set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF)
|
set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF)
|
||||||
|
set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF)
|
||||||
|
|
||||||
if(NOT TRACY_STATIC)
|
if(NOT TRACY_STATIC)
|
||||||
target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS)
|
target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS)
|
||||||
|
@ -90,9 +90,133 @@ extern "C" const char* ___tracy_demangle( const char* mangled )
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if TRACY_HAS_CALLSTACK == 3
|
||||||
|
# define TRACY_USE_IMAGE_CACHE
|
||||||
|
# include <link.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace tracy
|
namespace tracy
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
// when we have access to dl_iterate_phdr(), we can build a cache of address ranges to image paths
|
||||||
|
// so we can quickly determine which image an address falls into.
|
||||||
|
// We refresh this cache only when we hit an address that doesn't fall into any known range.
|
||||||
|
class ImageCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct ImageEntry
|
||||||
|
{
|
||||||
|
void* m_startAddress = nullptr;
|
||||||
|
void* m_endAddress = nullptr;
|
||||||
|
char* m_name = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageCache()
|
||||||
|
{
|
||||||
|
m_images = (FastVector<ImageEntry>*)tracy_malloc( sizeof( FastVector<ImageEntry> ) );
|
||||||
|
new(m_images) FastVector<ImageEntry>( 512 );
|
||||||
|
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
~ImageCache()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
m_images->~FastVector<ImageEntry>();
|
||||||
|
tracy_free( m_images );
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImageEntry* GetImageForAddress( void* address )
|
||||||
|
{
|
||||||
|
const ImageEntry* entry = GetImageForAddressImpl( address );
|
||||||
|
if( !entry )
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
return GetImageForAddressImpl( address );
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
tracy::FastVector<ImageEntry>* m_images;
|
||||||
|
|
||||||
|
static int Callback( struct dl_phdr_info* info, size_t size, void* data )
|
||||||
|
{
|
||||||
|
ImageCache* cache = reinterpret_cast<ImageCache*>( data );
|
||||||
|
|
||||||
|
ImageEntry* image = cache->m_images->push_next();
|
||||||
|
image->m_startAddress = reinterpret_cast<void*>( info->dlpi_addr );
|
||||||
|
const uint32_t headerCount = info->dlpi_phnum;
|
||||||
|
assert( headerCount > 0);
|
||||||
|
image->m_endAddress = reinterpret_cast<void*>( info->dlpi_addr +
|
||||||
|
info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr + info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz);
|
||||||
|
|
||||||
|
const char* imageName = nullptr;
|
||||||
|
// the base executable name isn't provided when iterating with dl_iterate_phdr, get it with dladdr()
|
||||||
|
if( info->dlpi_name && info->dlpi_name[0] != '\0' )
|
||||||
|
{
|
||||||
|
imageName = info->dlpi_name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Dl_info dlInfo;
|
||||||
|
if( dladdr( (void *)info->dlpi_addr, &dlInfo ) )
|
||||||
|
{
|
||||||
|
imageName = dlInfo.dli_fname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(imageName != nullptr)
|
||||||
|
{
|
||||||
|
size_t sz = strlen( imageName ) + 1;
|
||||||
|
image->m_name = (char*)tracy_malloc( sz );
|
||||||
|
memcpy( (void*)image->m_name, imageName, sz );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
image->m_name = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Refresh()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
dl_iterate_phdr( Callback, this );
|
||||||
|
|
||||||
|
std::sort( m_images->begin(), m_images->end(),
|
||||||
|
[]( const ImageEntry& lhs, const ImageEntry& rhs ) { return lhs.m_startAddress > rhs.m_startAddress; } );
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImageEntry* GetImageForAddressImpl( void* address ) const
|
||||||
|
{
|
||||||
|
auto it = std::lower_bound( m_images->begin(), m_images->end(), address,
|
||||||
|
[]( const ImageEntry& lhs, const void* rhs ) { return lhs.m_startAddress > rhs; } );
|
||||||
|
|
||||||
|
if( it != m_images->end() && address < it->m_endAddress )
|
||||||
|
{
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
for( ImageEntry& entry : *m_images )
|
||||||
|
{
|
||||||
|
tracy_free( entry.m_name );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_images->clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif //#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
|
||||||
// when "TRACY_SYMBOL_OFFLINE_RESOLVE" is set, instead of fully resolving symbols at runtime,
|
// when "TRACY_SYMBOL_OFFLINE_RESOLVE" is set, instead of fully resolving symbols at runtime,
|
||||||
// simply resolve the offset and image name (which will be enough the resolving to be done offline)
|
// simply resolve the offset and image name (which will be enough the resolving to be done offline)
|
||||||
#ifdef TRACY_SYMBOL_OFFLINE_RESOLVE
|
#ifdef TRACY_SYMBOL_OFFLINE_RESOLVE
|
||||||
@ -607,6 +731,9 @@ struct backtrace_state* cb_bts = nullptr;
|
|||||||
int cb_num;
|
int cb_num;
|
||||||
CallstackEntry cb_data[MaxCbTrace];
|
CallstackEntry cb_data[MaxCbTrace];
|
||||||
int cb_fixup;
|
int cb_fixup;
|
||||||
|
#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
static ImageCache* s_imageCache = nullptr;
|
||||||
|
#endif //#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
|
||||||
#ifdef TRACY_DEBUGINFOD
|
#ifdef TRACY_DEBUGINFOD
|
||||||
debuginfod_client* s_debuginfod;
|
debuginfod_client* s_debuginfod;
|
||||||
@ -779,6 +906,13 @@ void InitCallstackCritical()
|
|||||||
|
|
||||||
void InitCallstack()
|
void InitCallstack()
|
||||||
{
|
{
|
||||||
|
InitRpmalloc();
|
||||||
|
|
||||||
|
#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
s_imageCache = (ImageCache*)tracy_malloc( sizeof( ImageCache ) );
|
||||||
|
new(s_imageCache) ImageCache();
|
||||||
|
#endif //#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
|
||||||
#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
|
#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
|
||||||
s_shouldResolveSymbolsOffline = ShouldResolveSymbolsOffline();
|
s_shouldResolveSymbolsOffline = ShouldResolveSymbolsOffline();
|
||||||
#endif //#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
|
#endif //#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
|
||||||
@ -869,6 +1003,13 @@ debuginfod_client* GetDebuginfodClient()
|
|||||||
|
|
||||||
void EndCallstack()
|
void EndCallstack()
|
||||||
{
|
{
|
||||||
|
#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
if( s_imageCache )
|
||||||
|
{
|
||||||
|
s_imageCache->~ImageCache();
|
||||||
|
tracy_free( s_imageCache );
|
||||||
|
}
|
||||||
|
#endif //#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
#ifndef TRACY_DEMANGLE
|
#ifndef TRACY_DEMANGLE
|
||||||
___tracy_free_demangle_buffer();
|
___tracy_free_demangle_buffer();
|
||||||
#endif
|
#endif
|
||||||
@ -1041,12 +1182,12 @@ void SymInfoError( void* /*data*/, const char* /*msg*/, int /*errnum*/ )
|
|||||||
cb_data[cb_num-1].symAddr = 0;
|
cb_data[cb_num-1].symAddr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetSymbolForOfflineResolve(void* address, Dl_info& dlinfo, CallstackEntry& cbEntry)
|
void GetSymbolForOfflineResolve(void* address, uint64_t imageBaseAddress, CallstackEntry& cbEntry)
|
||||||
{
|
{
|
||||||
// tagged with a string that we can identify as an unresolved symbol
|
// tagged with a string that we can identify as an unresolved symbol
|
||||||
cbEntry.name = CopyStringFast( "[unresolved]" );
|
cbEntry.name = CopyStringFast( "[unresolved]" );
|
||||||
// set .so relative offset so it can be resolved offline
|
// set .so relative offset so it can be resolved offline
|
||||||
cbEntry.symAddr = (uint64_t)address - (uint64_t)(dlinfo.dli_fbase);
|
cbEntry.symAddr = (uint64_t)address - imageBaseAddress;
|
||||||
cbEntry.symLen = 0x0;
|
cbEntry.symLen = 0x0;
|
||||||
cbEntry.file = CopyStringFast( "[unknown]" );
|
cbEntry.file = CopyStringFast( "[unknown]" );
|
||||||
cbEntry.line = 0;
|
cbEntry.line = 0;
|
||||||
@ -1057,17 +1198,29 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
|||||||
InitRpmalloc();
|
InitRpmalloc();
|
||||||
if( ptr >> 63 == 0 )
|
if( ptr >> 63 == 0 )
|
||||||
{
|
{
|
||||||
const char* symloc = nullptr;
|
const char* imageName = nullptr;
|
||||||
|
uint64_t imageBaseAddress = 0x0;
|
||||||
|
|
||||||
|
#ifdef TRACY_USE_IMAGE_CACHE
|
||||||
|
const auto* image = s_imageCache->GetImageForAddress((void*)ptr);
|
||||||
|
if( image )
|
||||||
|
{
|
||||||
|
imageName = image->m_name;
|
||||||
|
imageBaseAddress = uint64_t(image->m_startAddress);
|
||||||
|
}
|
||||||
|
#else
|
||||||
Dl_info dlinfo;
|
Dl_info dlinfo;
|
||||||
if( dladdr( (void*)ptr, &dlinfo ) )
|
if( dladdr( (void*)ptr, &dlinfo ) )
|
||||||
{
|
{
|
||||||
symloc = dlinfo.dli_fname;
|
imageName = dlinfo.dli_fname;
|
||||||
|
imageBaseAddress = uint64_t( dlinfo.dli_fbase );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( s_shouldResolveSymbolsOffline )
|
if( s_shouldResolveSymbolsOffline )
|
||||||
{
|
{
|
||||||
cb_num = 1;
|
cb_num = 1;
|
||||||
GetSymbolForOfflineResolve( (void*)ptr, dlinfo, cb_data[0] );
|
GetSymbolForOfflineResolve( (void*)ptr, imageBaseAddress, cb_data[0] );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1078,7 +1231,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
|||||||
backtrace_syminfo( cb_bts, ptr, SymInfoCallback, SymInfoError, nullptr );
|
backtrace_syminfo( cb_bts, ptr, SymInfoCallback, SymInfoError, nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
return { cb_data, uint8_t( cb_num ), symloc ? symloc : "[unknown]" };
|
return { cb_data, uint8_t( cb_num ), imageName ? imageName : "[unknown]" };
|
||||||
}
|
}
|
||||||
#ifdef __linux
|
#ifdef __linux
|
||||||
else if( s_kernelSym )
|
else if( s_kernelSym )
|
||||||
|
@ -4251,6 +4251,19 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dwarf_fileline_dwarf_lookup_pc_in_all_entries(struct backtrace_state *state, uintptr_t pc,
|
||||||
|
backtrace_full_callback callback, backtrace_error_callback error_callback, void *data,
|
||||||
|
int& found, int ret)
|
||||||
|
{
|
||||||
|
for (struct dwarf_data* ddata = (struct dwarf_data *)state->fileline_data;
|
||||||
|
ddata != NULL;
|
||||||
|
ddata = ddata->next)
|
||||||
|
{
|
||||||
|
ret = dwarf_lookup_pc(state, ddata, pc, callback, error_callback, data, &found);
|
||||||
|
if (ret != 0 || found) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the file/line information for a PC using the DWARF mapping
|
/* Return the file/line information for a PC using the DWARF mapping
|
||||||
we built earlier. */
|
we built earlier. */
|
||||||
@ -4262,20 +4275,30 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
|||||||
{
|
{
|
||||||
struct dwarf_data *ddata;
|
struct dwarf_data *ddata;
|
||||||
int found;
|
int found;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (!state->threaded)
|
if (!state->threaded)
|
||||||
|
{
|
||||||
|
if (dwarf_fileline_dwarf_lookup_pc_in_all_entries(state, pc, callback, error_callback, data, found, ret))
|
||||||
{
|
{
|
||||||
for (ddata = (struct dwarf_data *) state->fileline_data;
|
return ret;
|
||||||
ddata != NULL;
|
|
||||||
ddata = ddata->next)
|
|
||||||
{
|
|
||||||
ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
|
|
||||||
data, &found);
|
|
||||||
if (ret != 0 || found)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we failed to obtain an entry in range, it can mean that the address map has been changed and new entries
|
||||||
|
// have been loaded in the meantime. Request a refresh and try again.
|
||||||
|
if (state->request_known_address_ranges_refresh_fn)
|
||||||
|
{
|
||||||
|
int new_range_count = state->request_known_address_ranges_refresh_fn(state, pc);
|
||||||
|
if (new_range_count > 0)
|
||||||
|
{
|
||||||
|
if (dwarf_fileline_dwarf_lookup_pc_in_all_entries(state, pc, callback, error_callback, data, found, ret))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct dwarf_data **pp;
|
struct dwarf_data **pp;
|
||||||
|
@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. */
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#ifdef HAVE_DL_ITERATE_PHDR
|
#ifdef HAVE_DL_ITERATE_PHDR
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
@ -7350,13 +7351,37 @@ struct PhdrIterate
|
|||||||
{
|
{
|
||||||
char* dlpi_name;
|
char* dlpi_name;
|
||||||
ElfW(Addr) dlpi_addr;
|
ElfW(Addr) dlpi_addr;
|
||||||
|
ElfW(Addr) dlpi_end_addr;
|
||||||
};
|
};
|
||||||
FastVector<PhdrIterate> s_phdrData(16);
|
FastVector<PhdrIterate> s_phdrData(16);
|
||||||
|
|
||||||
|
struct ElfAddrRange
|
||||||
|
{
|
||||||
|
ElfW(Addr) dlpi_addr;
|
||||||
|
ElfW(Addr) dlpi_end_addr;
|
||||||
|
};
|
||||||
|
FastVector<ElfAddrRange> s_sortedKnownElfRanges(16);
|
||||||
|
|
||||||
|
static int address_in_known_elf_ranges(uintptr_t pc)
|
||||||
|
{
|
||||||
|
auto it = std::lower_bound( s_sortedKnownElfRanges.begin(), s_sortedKnownElfRanges.end(), pc,
|
||||||
|
[]( const ElfAddrRange& lhs, const uintptr_t rhs ) { return uintptr_t(lhs.dlpi_addr) > rhs; } );
|
||||||
|
if( it != s_sortedKnownElfRanges.end() && pc <= it->dlpi_end_addr )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
phdr_callback_mock (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
|
phdr_callback_mock (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
|
||||||
void *pdata)
|
void *pdata)
|
||||||
{
|
{
|
||||||
|
if( address_in_known_elf_ranges(info->dlpi_addr) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
auto ptr = s_phdrData.push_next();
|
auto ptr = s_phdrData.push_next();
|
||||||
if (info->dlpi_name)
|
if (info->dlpi_name)
|
||||||
{
|
{
|
||||||
@ -7366,6 +7391,12 @@ phdr_callback_mock (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
|
|||||||
}
|
}
|
||||||
else ptr->dlpi_name = nullptr;
|
else ptr->dlpi_name = nullptr;
|
||||||
ptr->dlpi_addr = info->dlpi_addr;
|
ptr->dlpi_addr = info->dlpi_addr;
|
||||||
|
|
||||||
|
// calculate the end address as well, so we can quickly determine if a PC is within the range of this image
|
||||||
|
ptr->dlpi_end_addr = uintptr_t(info->dlpi_addr) + (info->dlpi_phnum ? uintptr_t(
|
||||||
|
info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr +
|
||||||
|
info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz) : 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7422,6 +7453,66 @@ phdr_callback (struct PhdrIterate *info, void *pdata)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int elf_iterate_phdr_and_add_new_files(phdr_data *pd)
|
||||||
|
{
|
||||||
|
assert(s_phdrData.empty());
|
||||||
|
// dl_iterate_phdr, will only add entries for elf files loaded in a previouly unseen range
|
||||||
|
dl_iterate_phdr(phdr_callback_mock, nullptr);
|
||||||
|
|
||||||
|
if(s_phdrData.size() == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t headersAdded = 0;
|
||||||
|
for (auto &v : s_phdrData)
|
||||||
|
{
|
||||||
|
phdr_callback(&v, (void *)pd);
|
||||||
|
|
||||||
|
auto newEntry = s_sortedKnownElfRanges.push_next();
|
||||||
|
newEntry->dlpi_addr = v.dlpi_addr;
|
||||||
|
newEntry->dlpi_end_addr = v.dlpi_end_addr;
|
||||||
|
|
||||||
|
tracy_free(v.dlpi_name);
|
||||||
|
|
||||||
|
headersAdded++;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_phdrData.clear();
|
||||||
|
|
||||||
|
std::sort( s_sortedKnownElfRanges.begin(), s_sortedKnownElfRanges.end(),
|
||||||
|
[]( const ElfAddrRange& lhs, const ElfAddrRange& rhs ) { return lhs.dlpi_addr > rhs.dlpi_addr; } );
|
||||||
|
|
||||||
|
return headersAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT
|
||||||
|
/* Request an elf entry update if the pc passed in is not in any of the known elf ranges.
|
||||||
|
This could mean that new images were dlopened and we need to add those new elf entries */
|
||||||
|
static int elf_refresh_address_ranges_if_needed(struct backtrace_state *state, uintptr_t pc)
|
||||||
|
{
|
||||||
|
if ( address_in_known_elf_ranges(pc) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct phdr_data pd;
|
||||||
|
int found_sym = 0;
|
||||||
|
int found_dwarf = 0;
|
||||||
|
fileline fileline_fn = nullptr;
|
||||||
|
pd.state = state;
|
||||||
|
pd.error_callback = nullptr;
|
||||||
|
pd.data = nullptr;
|
||||||
|
pd.fileline_fn = &fileline_fn;
|
||||||
|
pd.found_sym = &found_sym;
|
||||||
|
pd.found_dwarf = &found_dwarf;
|
||||||
|
pd.exe_filename = nullptr;
|
||||||
|
pd.exe_descriptor = -1;
|
||||||
|
|
||||||
|
return elf_iterate_phdr_and_add_new_files(&pd);
|
||||||
|
}
|
||||||
|
#endif //#ifdef TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT
|
||||||
|
|
||||||
/* Initialize the backtrace data we need from an ELF executable. At
|
/* Initialize the backtrace data we need from an ELF executable. At
|
||||||
the ELF level, all we need to do is find the debug info
|
the ELF level, all we need to do is find the debug info
|
||||||
sections. */
|
sections. */
|
||||||
@ -7452,14 +7543,7 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
|
|||||||
pd.exe_filename = filename;
|
pd.exe_filename = filename;
|
||||||
pd.exe_descriptor = ret < 0 ? descriptor : -1;
|
pd.exe_descriptor = ret < 0 ? descriptor : -1;
|
||||||
|
|
||||||
assert (s_phdrData.empty());
|
elf_iterate_phdr_and_add_new_files(&pd);
|
||||||
dl_iterate_phdr (phdr_callback_mock, nullptr);
|
|
||||||
for (auto& v : s_phdrData)
|
|
||||||
{
|
|
||||||
phdr_callback (&v, (void *) &pd);
|
|
||||||
tracy_free (v.dlpi_name);
|
|
||||||
}
|
|
||||||
s_phdrData.clear();
|
|
||||||
|
|
||||||
if (!state->threaded)
|
if (!state->threaded)
|
||||||
{
|
{
|
||||||
@ -7485,6 +7569,13 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
|
|||||||
if (*fileline_fn == NULL || *fileline_fn == elf_nodebug)
|
if (*fileline_fn == NULL || *fileline_fn == elf_nodebug)
|
||||||
*fileline_fn = elf_fileline_fn;
|
*fileline_fn = elf_fileline_fn;
|
||||||
|
|
||||||
|
// install an address range refresh callback so we can cope with dynamically loaded elf files
|
||||||
|
#ifdef TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT
|
||||||
|
state->request_known_address_ranges_refresh_fn = elf_refresh_address_ranges_if_needed;
|
||||||
|
#else
|
||||||
|
state->request_known_address_ranges_refresh_fn = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,11 @@ typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc,
|
|||||||
backtrace_syminfo_callback callback,
|
backtrace_syminfo_callback callback,
|
||||||
backtrace_error_callback error_callback, void *data);
|
backtrace_error_callback error_callback, void *data);
|
||||||
|
|
||||||
|
/* The type of the function that will trigger an known address range refresh
|
||||||
|
(if pc passed in is for an address whichs lies ourtisde of known ranges) */
|
||||||
|
typedef int (*request_known_address_ranges_refresh)(struct backtrace_state *state,
|
||||||
|
uintptr_t pc);
|
||||||
|
|
||||||
/* What the backtrace state pointer points to. */
|
/* What the backtrace state pointer points to. */
|
||||||
|
|
||||||
struct backtrace_state
|
struct backtrace_state
|
||||||
@ -159,6 +164,8 @@ struct backtrace_state
|
|||||||
int lock_alloc;
|
int lock_alloc;
|
||||||
/* The freelist when using mmap. */
|
/* The freelist when using mmap. */
|
||||||
struct backtrace_freelist_struct *freelist;
|
struct backtrace_freelist_struct *freelist;
|
||||||
|
/* Trigger an known address range refresh */
|
||||||
|
request_known_address_ranges_refresh request_known_address_ranges_refresh_fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST
|
/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST
|
||||||
|
Loading…
Reference in New Issue
Block a user