Commit 1a39f1b9 authored by Jan Kratochvil's avatar Jan Kratochvil
Browse files

[lldb] Fix+re-enable Assert StackFrame Recognizer on Linux

D73303 was failing on Fedora Linux and so it was disabled by Skip the
AssertFrameRecognizer test for Linux.

I find no easy way how to find out if it gets recognized as
`__assert_fail` or `__GI___assert_fail` as during `Process` ctor
libc.so.6 is not yet loaded by the debuggee.

DWARF symbol `__GI___assert_fail` overrides the ELF symbol `__assert_fail`.
While external debug info (=DWARF) gets disabled for testsuite (D55859)
that sure does not apply for real world usage.

Differential Revision: https://reviews.llvm.org/D74252
parent 6115bd9b
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -101,8 +101,8 @@ private:
class StackFrameRecognizerManager {
public:
  static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
                            ConstString module,
                            ConstString symbol,
                            ConstString module, ConstString symbol,
                            ConstString alternate_symbol,
                            bool first_instruction_only = true);

  static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
@@ -113,7 +113,8 @@ public:
  static void ForEach(
      std::function<void(uint32_t recognizer_id, std::string recognizer_name,
                         std::string module, std::string symbol,
                         bool regexp)> const &callback);
                         std::string alternate_symbol, bool regexp)> const
          &callback);

  static bool RemoveRecognizerWithID(uint32_t recognizer_id);

+5 −4
Original line number Diff line number Diff line
@@ -881,7 +881,7 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
  } else {
    auto module = ConstString(m_options.m_module);
    auto func = ConstString(m_options.m_function);
    StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
    StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func, {});
  }
#endif

@@ -960,12 +960,13 @@ protected:
    StackFrameRecognizerManager::ForEach(
        [&result, &any_printed](uint32_t recognizer_id, std::string name,
                                std::string function, std::string symbol,
                                bool regexp) {
                                std::string alternate_symbol, bool regexp) {
          if (name == "")
            name = "(internal)";
          result.GetOutputStream().Printf(
              "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
              function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
              "%d: %s, module %s, function %s{%s}%s\n", recognizer_id,
              name.c_str(), function.c_str(), symbol.c_str(),
              alternate_symbol.c_str(), regexp ? " (regexp)" : "");
          any_printed = true;
        });

+2 −1
Original line number Diff line number Diff line
@@ -2691,6 +2691,7 @@ static void RegisterObjCExceptionRecognizer() {
    std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation();
    StackFrameRecognizerManager::AddRecognizer(
        StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),
        module.GetFilename(), function, /*first_instruction_only*/ true);
        module.GetFilename(), function, /*alternate_symbol*/ {},
        /*first_instruction_only*/ true);
  });
}
+29 −42
Original line number Diff line number Diff line
@@ -16,26 +16,6 @@ using namespace lldb;
using namespace lldb_private;

namespace lldb_private {
/// Checkes if the module containing a symbol has debug info.
///
/// \param[in] target
///    The target containing the module.
/// \param[in] module_spec
///    The module spec that should contain the symbol.
/// \param[in] symbol_name
///    The symbol's name that should be contained in the debug info.
/// \return
///    If  \b true the symbol was found, \b false otherwise.
bool ModuleHasDebugInfo(Target &target, FileSpec &module_spec,
                        StringRef symbol_name) {
  ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec);

  if (!module_sp)
    return false;

  return module_sp->FindFirstSymbolWithNameAndType(ConstString(symbol_name));
}

/// Fetches the abort frame location depending on the current platform.
///
/// \param[in] process_sp
@@ -43,14 +23,15 @@ bool ModuleHasDebugInfo(Target &target, FileSpec &module_spec,
///    the target and the platform.
/// \return
///    If the platform is supported, returns an optional tuple containing
///    the abort module as a \a FileSpec and the symbol name as a \a StringRef.
///    the abort module as a \a FileSpec and two symbol names as two \a
///    StringRef. The second \a StringRef may be empty.
///    Otherwise, returns \a llvm::None.
llvm::Optional<std::tuple<FileSpec, StringRef>>
llvm::Optional<std::tuple<FileSpec, StringRef, StringRef>>
GetAbortLocation(Process *process) {
  Target &target = process->GetTarget();

  FileSpec module_spec;
  StringRef symbol_name;
  StringRef symbol_name, alternate_symbol_name;

  switch (target.GetArchitecture().GetTriple().getOS()) {
  case llvm::Triple::Darwin:
@@ -60,9 +41,8 @@ GetAbortLocation(Process *process) {
    break;
  case llvm::Triple::Linux:
    module_spec = FileSpec("libc.so.6");
    symbol_name = "__GI_raise";
    if (!ModuleHasDebugInfo(target, module_spec, symbol_name))
    symbol_name = "raise";
    alternate_symbol_name = "__GI_raise";
    break;
  default:
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
@@ -70,7 +50,7 @@ GetAbortLocation(Process *process) {
    return llvm::None;
  }

  return std::make_tuple(module_spec, symbol_name);
  return std::make_tuple(module_spec, symbol_name, alternate_symbol_name);
}

/// Fetches the assert frame location depending on the current platform.
@@ -80,15 +60,15 @@ GetAbortLocation(Process *process) {
///    the target and the platform.
/// \return
///    If the platform is supported, returns an optional tuple containing
///    the asserting frame module as  a \a FileSpec and the symbol name as a \a
///    StringRef.
///    the asserting frame module as a \a FileSpec and two possible symbol
///    names as two \a StringRef. The second \a StringRef may be empty.
///    Otherwise, returns \a llvm::None.
llvm::Optional<std::tuple<FileSpec, StringRef>>
llvm::Optional<std::tuple<FileSpec, StringRef, StringRef>>
GetAssertLocation(Process *process) {
  Target &target = process->GetTarget();

  FileSpec module_spec;
  StringRef symbol_name;
  StringRef symbol_name, alternate_symbol_name;

  switch (target.GetArchitecture().GetTriple().getOS()) {
  case llvm::Triple::Darwin:
@@ -98,9 +78,8 @@ GetAssertLocation(Process *process) {
    break;
  case llvm::Triple::Linux:
    module_spec = FileSpec("libc.so.6");
    symbol_name = "__GI___assert_fail";
    if (!ModuleHasDebugInfo(target, module_spec, symbol_name))
    symbol_name = "__assert_fail";
    alternate_symbol_name = "__GI___assert_fail";
    break;
  default:
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
@@ -108,7 +87,7 @@ GetAssertLocation(Process *process) {
    return llvm::None;
  }

  return std::make_tuple(module_spec, symbol_name);
  return std::make_tuple(module_spec, symbol_name, alternate_symbol_name);
}

void RegisterAssertFrameRecognizer(Process *process) {
@@ -120,12 +99,14 @@ void RegisterAssertFrameRecognizer(Process *process) {
      return;

    FileSpec module_spec;
    StringRef function_name;
    std::tie(module_spec, function_name) = *abort_location;
    StringRef function_name, alternate_function_name;
    std::tie(module_spec, function_name, alternate_function_name) =
        *abort_location;

    StackFrameRecognizerManager::AddRecognizer(
        StackFrameRecognizerSP(new AssertFrameRecognizer()),
        module_spec.GetFilename(), ConstString(function_name), false);
        module_spec.GetFilename(), ConstString(function_name),
        ConstString(alternate_function_name), /*first_instruction_only*/ false);
  });
}

@@ -142,8 +123,9 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
    return RecognizedStackFrameSP();

  FileSpec module_spec;
  StringRef function_name;
  std::tie(module_spec, function_name) = *assert_location;
  StringRef function_name, alternate_function_name;
  std::tie(module_spec, function_name, alternate_function_name) =
      *assert_location;

  const uint32_t frames_to_fetch = 5;
  const uint32_t last_frame_index = frames_to_fetch - 1;
@@ -163,8 +145,13 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
    SymbolContext sym_ctx =
        prev_frame_sp->GetSymbolContext(eSymbolContextEverything);

    if (sym_ctx.module_sp->GetFileSpec().FileEquals(module_spec) &&
        sym_ctx.GetFunctionName() == ConstString(function_name)) {
    if (!sym_ctx.module_sp->GetFileSpec().FileEquals(module_spec))
      continue;

    ConstString func_name = sym_ctx.GetFunctionName();
    if (func_name == ConstString(function_name) ||
        alternate_function_name.empty() ||
        func_name == ConstString(alternate_function_name)) {

      // We go a frame beyond the assert location because the most relevant
      // frame for the user is the one in which the assert function was called.
+28 −17
Original line number Diff line number Diff line
@@ -50,24 +50,28 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) {

class StackFrameRecognizerManagerImpl {
public:
  void AddRecognizer(StackFrameRecognizerSP recognizer,
                     ConstString module, ConstString symbol,
  void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString module,
                     ConstString symbol, ConstString alternate_symbol,
                     bool first_instruction_only) {
    m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, false, module, RegularExpressionSP(),
                              symbol, RegularExpressionSP(),
    m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer,
                              false, module, RegularExpressionSP(), symbol,
                              alternate_symbol, RegularExpressionSP(),
                              first_instruction_only});
  }

  void AddRecognizer(StackFrameRecognizerSP recognizer,
                     RegularExpressionSP module, RegularExpressionSP symbol,
                     bool first_instruction_only) {
    m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(), module,
    m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer,
                              true, ConstString(), module, ConstString(),
                              ConstString(), symbol, first_instruction_only});
  }

  void ForEach(
      std::function<void(uint32_t recognized_id, std::string recognizer_name, std::string module,
                         std::string symbol, bool regexp)> const &callback) {
      std::function<void(uint32_t recognized_id, std::string recognizer_name,
                         std::string module, std::string symbol,
                         std::string alternate_symbol, bool regexp)> const
          &callback) {
    for (auto entry : m_recognizers) {
      if (entry.is_regexp) {
        std::string module_name;
@@ -79,11 +83,12 @@ public:
          symbol_name = entry.symbol_regexp->GetText().str();

        callback(entry.recognizer_id, entry.recognizer->GetName(), module_name,
                 symbol_name, true);
                 symbol_name, {}, true);

      } else {
        callback(entry.recognizer_id, entry.recognizer->GetName(), entry.module.GetCString(),
                 entry.symbol.GetCString(), false);
        callback(entry.recognizer_id, entry.recognizer->GetName(),
                 entry.module.GetCString(), entry.symbol.GetCString(),
                 entry.alternate_symbol.GetCString(), false);
      }
    }
  }
@@ -120,7 +125,10 @@ public:
        if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue;

      if (entry.symbol)
        if (entry.symbol != function_name) continue;
        if (entry.symbol != function_name &&
            (!entry.alternate_symbol ||
             entry.alternate_symbol != function_name))
          continue;

      if (entry.symbol_regexp)
        if (!entry.symbol_regexp->Execute(function_name.GetStringRef()))
@@ -149,6 +157,7 @@ public:
    ConstString module;
    RegularExpressionSP module_regexp;
    ConstString symbol;
    ConstString alternate_symbol;
    RegularExpressionSP symbol_regexp;
    bool first_instruction_only;
  };
@@ -163,10 +172,10 @@ StackFrameRecognizerManagerImpl &GetStackFrameRecognizerManagerImpl() {
}

void StackFrameRecognizerManager::AddRecognizer(
    StackFrameRecognizerSP recognizer, ConstString module,
    ConstString symbol, bool first_instruction_only) {
  GetStackFrameRecognizerManagerImpl().AddRecognizer(recognizer, module, symbol,
                                                     first_instruction_only);
    StackFrameRecognizerSP recognizer, ConstString module, ConstString symbol,
    ConstString alternate_symbol, bool first_instruction_only) {
  GetStackFrameRecognizerManagerImpl().AddRecognizer(
      recognizer, module, symbol, alternate_symbol, first_instruction_only);
}

void StackFrameRecognizerManager::AddRecognizer(
@@ -177,8 +186,10 @@ void StackFrameRecognizerManager::AddRecognizer(
}

void StackFrameRecognizerManager::ForEach(
    std::function<void(uint32_t recognized_id, std::string recognizer_name, std::string module,
                       std::string symbol, bool regexp)> const &callback) {
    std::function<void(uint32_t recognized_id, std::string recognizer_name,
                       std::string module, std::string symbol,
                       std::string alternate_symbol, bool regexp)> const
        &callback) {
  GetStackFrameRecognizerManagerImpl().ForEach(callback);
}

Loading