re-apply diff

This commit is contained in:
Tiago Rodrigues 2023-12-06 12:39:52 -05:00
parent 38559172bb
commit 8dfc5fe41f

View File

@ -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,14 +7351,39 @@ 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)
{
size_t range_count = s_sortedKnownElfRanges.size();
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)
{ {
auto ptr = s_phdrData.push_next(); if( address_in_known_elf_ranges(info->dlpi_addr) )
{
return 0;
}
if (info->dlpi_name) if (info->dlpi_name)
{ {
size_t sz = strlen (info->dlpi_name) + 1; size_t sz = strlen (info->dlpi_name) + 1;
@ -7366,6 +7392,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 address range so we can quickly determine is a PC is within the range of this image
ptr->dlpi_end_addr = info->dlpi_phnum ? uintptr_t( info->dlpi_addr +
info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr +
info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz ) : 0x0;
return 0; return 0;
} }
@ -7422,6 +7454,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 +7544,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 +7570,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;
} }