Repository: wolfpld/tracy
File: client/TracyProfiler.cpp (C++)

Code before:
            // The current mapping starts after the remainder of the address
            // range that we needs to cover, so some of that address range
            // isn't covered by any mapping.
            return false;
        }
        remainder_start_address = it->end_address;
        ++it;
    }
    // Some of the address range isn't covered by any mapping.
    if (remainder_start_address < end_address) return false;
    *end_iterator = it;
    if (*end_iterator < *start_iterator) {
        abort();
    }
    if (*end_iterator > (*start_iterator) + 1) {
        abort();
    }
    return true;
}
                      

// Attempts to make the specified `mapping` readable if it isn't already.
// Returns true if and only if the mapping is readable.
bool EnsureReadable( MappingInfo* mapping )
{
    if( mapping->perm_r )
    {
        // The mapping is already readable.
        return true;
    }
    if( mapping->mprotect_fails )
    {
        // We have already see mprotect failing on this mapping.
        return false;
    }
    int prot = PROT_READ;
    if( mapping->perm_w ) prot |= PROT_WRITE;
    if( mapping->perm_x ) prot |= PROT_EXEC;
    if( mprotect( reinterpret_cast<void*>( mapping->start_address ),
                 mapping->end_address - mapping->start_address, prot ) == -1 )
    {
        // Failed to make the mapping readable. Update `mapping`
        // so the next call will be fast.
        mapping->mprotect_fails = true;
        return false;
    }
    // The mapping is now readable. Update `mapping` so the next call will be fast.
    mapping->perm_r = true;
    return true;
}


Review comment (bug):
The function interface tells me that `mapping` may be `nullptr` here. Change it to a reference to ensure a valid object is always passed to the function.

Code after:
        return true;
    }
    int prot = PROT_READ;
    if( mapping.perm_w ) prot |= PROT_WRITE;
    if( mapping.perm_x ) prot |= PROT_EXEC;
    if( mprotect( reinterpret_cast<void*>( mapping.start_address ),
                  mapping.end_address - mapping.start_address, prot ) == -1 )
    {
        // Failed to make the mapping readable. Shouldn't happen, hasn't
        // been observed yet. If it happened in practice, we should consider
        // adding a bool to MappingInfo to track this to avoid retrying mprotect
        // everytime on such mappings.
        return false;
    }
    // The mapping is now readable. Update `mapping` so the next call will be fast.
    mapping.perm_r = true;
    return true;
}

// Attempts to set the read permission on the entire mapping containing the
// specified address.
bool EnsureReadable( uintptr_t address )
{
    MappingInfo* mapping = LookUpMapping(address);
    return mapping && EnsureReadable( *mapping );
}

}  // anonymous namespace
#endif  // defined __ANDROID__

void Profiler::HandleSymbolQuery( uint64_t symbol )
{
#ifdef TRACY_HAS_CALLSTACK
#ifdef __ANDROID__
    // On Android it's common for code to be in mappings that are only executable
    // but not readable.
    if( !EnsureReadable( symbol ) )
    {
        return;
    }
#endif
    const auto sym = DecodeSymbolAddress( symbol );

    SendSingleString( sym.file );

    QueueItem item;
    MemWrite( &item.hdr.type, QueueType::SymbolInformation );
    MemWrite( &item.symbolInformation.line, sym.line );
    MemWrite( &item.symbolInformation.symAddr, symbol );

    AppendData( &item, QueueDataSize[(int)QueueType::SymbolInformation] );