Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sal/osl/unx/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 9 kB image not shown  

Quelle  backtraceapi.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <sal/config.h>

#include <cassert>
#include <cstdlib>
#include <limits>
#include <memory>
#include <mutex>

#include <o3tl/runtimetooustring.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/ustring.hxx>
#include <sal/types.h>
#include <sal/log.hxx>
#include <sal/backtrace.hxx>

#include "backtrace.h"
#include <backtraceasstring.hxx>

OUString osl::detail::backtraceAsString(sal_uInt32 maxDepth) {
    std::unique_ptr<sal::BacktraceState> backtrace = sal::backtrace_get( maxDepth );
    return sal::backtrace_to_string( backtrace.get());
}

std::unique_ptr<sal::BacktraceState> sal::backtrace_get(sal_uInt32 maxDepth)
{
    assert(maxDepth != 0);
    auto const maxInt = static_cast<unsigned int>(
        std::numeric_limits<int>::max());
    if (maxDepth > maxInt) {
        maxDepth = static_cast<sal_uInt32>(maxInt);
    }
    auto b1 = new void *[maxDepth];
    int n = backtrace(b1, static_cast<int>(maxDepth));
    return std::unique_ptr<BacktraceState>(new BacktraceState{ b1, n });
}

#if OSL_DEBUG_LEVEL > 0 && (defined LINUX || defined MACOSX || defined FREEBSD || defined NETBSD || defined OPENBSD || defined(DRAGONFLY))
// The backtrace_symbols() function is unreliable, it requires -rdynamic and even then it cannot resolve names
// of many functions, such as those with hidden ELF visibility. Libunwind doesn't resolve names for me either,
// boost::stacktrace doesn't work properly, the best result I've found is addr2line. Using addr2line is relatively
// slow, but I don't find that to be a big problem for printing of backtraces. Feel free to improve if needed
// (e.g. the calls could be grouped by the binary).
#include <dlfcn.h>
#include <unistd.h>
#include <vector>
#include <osl/process.h>
#include <rtl/strbuf.hxx>
#include <o3tl/lru_map.hxx>
#include "file_url.hxx"

namespace
{
struct FrameData
{
    const char* file = nullptr;
    void* addr;
    ptrdiff_t offset;
    OString info;
    bool handled = false;
};

typedef o3tl::lru_map<void*, OString> FrameCache;
std::mutex frameCacheMutex;
FrameCache frameCache( 256 );

void process_file_addr2line( const char* file, std::vector<FrameData>& frameData )
{
    if(access( file, R_OK ) != 0)
        return// cannot read info from the binary file anyway
    OUString binary(u"addr2line"_ustr);
    OUString dummy;
#if defined __clang__
    // llvm-addr2line is faster than addr2line
    if(osl::detail::find_in_PATH(u"llvm-addr2line"_ustr, dummy))
        binary = "llvm-addr2line";
#endif
    if(!osl::detail::find_in_PATH(binary, dummy))
        return// Will not work, avoid warnings from osl process code.
    OUString arg1(u"-Cfe"_ustr);
    OUString arg2 = OUString::fromUtf8(file);
    std::vector<OUString> addrs;
    std::vector<rtl_uString*> args;
    args.reserve(frameData.size() + 2);
    args.push_back( arg1.pData );
    args.push_back( arg2.pData );
    for( FrameData& frame : frameData )
    {
        if( frame.file != nullptr && strcmp( file, frame.file ) == 0 )
        {
            addrs.push_back("0x" + OUString::number(frame.offset, 16));
            args.push_back(addrs.back().pData);
            frame.handled = true;
        }
    }

    oslProcess aProcess;
    oslFileHandle pOut = nullptr;
    oslFileHandle pErr = nullptr;
    oslSecurity pSecurity = osl_getCurrentSecurity();
    oslProcessError eErr = osl_executeProcess_WithRedirectedIO(
        binary.pData, args.data(), args.size(), osl_Process_SEARCHPATH | osl_Process_HIDDEN, pSecurity, nullptr,
        nullptr, 0, &aProcess, nullptr, &pOut, &pErr);
    osl_freeSecurityHandle(pSecurity);

    if (eErr != osl_Process_E_None)
    {
        SAL_WARN("sal.osl", binary << " call to resolve " << file << " symbols failed");
        return;
    }

    OStringBuffer outputBuffer;
    if (pOut)
    {
        const sal_uInt64 BUF_SIZE = 1024;
        char buffer[BUF_SIZE];
        while (true)
        {
            sal_uInt64 bytesRead = 0;
            while(osl_readFile(pErr, buffer, BUF_SIZE, &bytesRead) == osl_File_E_None
                && bytesRead != 0)
                ; // discard possible stderr output
            oslFileError err = osl_readFile(pOut, buffer, BUF_SIZE, &bytesRead);
            if(bytesRead == 0 && err == osl_File_E_None)
                break;
            outputBuffer.append(buffer, bytesRead);
            if (err != osl_File_E_None && err != osl_File_E_AGAIN)
                break;
        }
        osl_closeFile(pOut);
    }
    if(pErr)
        osl_closeFile(pErr);
    eErr = osl_joinProcess(aProcess);
    osl_freeProcessHandle(aProcess);

    OString output = outputBuffer.makeStringAndClear();
    std::vector<OString> lines;
    sal_Int32 outputPos = 0;
    while(outputPos < output.getLength())
    {
        sal_Int32 end1 = output.indexOf('\n', outputPos);
        if(end1 < 0)
            break;
        sal_Int32 end2 = output.indexOf('\n', end1 + 1);
        if(end2 < 0)
            end2 = output.getLength();
        lines.push_back(output.copy( outputPos, end1 - outputPos ));
        lines.push_back(output.copy( end1 + 1, end2 - end1 - 1 ));
        outputPos = end2 + 1;
    }
    if(lines.size() != addrs.size() * 2)
    {
        SAL_WARN("sal.osl""failed to parse " << binary << " call output to resolve " << file << " symbols ");
        return// addr2line problem?
    }
    size_t linesPos = 0;
    for( FrameData& frame : frameData )
    {
        if( frame.file != nullptr && strcmp( file, frame.file ) == 0 )
        {
            // There should be two lines, first function name and second source file information.
            // If each of them starts with ??, it is invalid/unknown.
            const OString& function = lines[linesPos];
            const OString& source = lines[linesPos+1];
            linesPos += 2;
            if(function.isEmpty() || function.startsWith("??"))
            {
                // Cache that the address cannot be resolved.
                std::lock_guard guard(frameCacheMutex);
                frameCache.insert( { frame.addr, "" } );
            }
            else
            {
                if( source.startsWith("??"))
                    frame.info = function + " in " + file;
                else
                    frame.info = function + " at " + source;
                std::lock_guard guard(frameCacheMutex);
                frameCache.insert( { frame.addr, frame.info } );
            }
        }
    }
}

// namespace

OUString sal::backtrace_to_string(BacktraceState* backtraceState)
{
    // Collect frames for each binary and process each binary in one addr2line
    // call for better performance.
    std::vector< FrameData > frameData;
    frameData.resize(backtraceState->nDepth);
    for (int i = 0; i != backtraceState->nDepth; ++i)
    {
        Dl_info dli;
        void* addr = backtraceState->buffer[i];
        std::unique_lock guard(frameCacheMutex);
        auto it = frameCache.find(addr);
        bool found = it != frameCache.end();
        guard.unlock();
        if( found )
        {
            frameData[ i ].info = it->second;
            frameData[ i ].handled = true;
        }
        else if (dladdr(addr, &dli) != 0)
        {
            if (dli.dli_fname && dli.dli_fbase)
            {
                frameData[ i ].file = dli.dli_fname;
                frameData[ i ].addr = addr;
                frameData[ i ].offset = reinterpret_cast<ptrdiff_t>(addr) - reinterpret_cast<ptrdiff_t>(dli.dli_fbase);
            }
        }
    }
    for (int i = 0; i != backtraceState->nDepth; ++i)
    {
        if(frameData[ i ].file != nullptr && !frameData[ i ].handled)
            process_file_addr2line( frameData[ i ].file, frameData );
    }
    OUStringBuffer b3;
    std::unique_ptr<char*, decltype(free)*> b2{ nullptr, free };
    bool fallbackInitDone = false;
    for (int i = 0; i != backtraceState->nDepth; ++i)
    {
        if (i != 0)
            b3.append("\n");
        b3.append( "#" + OUString::number( i ) + " " );
        if(!frameData[i].info.isEmpty())
            b3.append(o3tl::runtimeToOUString(frameData[i].info.getStr()));
        else
        {
            if(!fallbackInitDone)
            {
                b2 = std::unique_ptr<char*, decltype(free)*>
                    {backtrace_symbols(backtraceState->buffer, backtraceState->nDepth), free};
                fallbackInitDone = true;
            }
            if(b2)
                b3.append(o3tl::runtimeToOUString(b2.get()[i]));
            else
                b3.append("??");
        }
    }
    return b3.makeStringAndClear();
}

#else

OUString sal::backtrace_to_string(BacktraceState* backtraceState)
{
    std::unique_ptr<char*, decltype(free)*> b2{backtrace_symbols(backtraceState->buffer, backtraceState->nDepth), free};
    if (!b2) {
        return OUString();
    }
    OUStringBuffer b3;
    for (int i = 0; i != backtraceState->nDepth; ++i) {
        if (i != 0) {
            b3.append("\n");
        }
        b3.append( "#" + OUString::number( i ) + " " );
        b3.append(o3tl::runtimeToOUString(b2.get()[i]));
    }
    return b3.makeStringAndClear();
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=76 G=84

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.