Files
RedBear-OS/local/recipes/dev/libclc/source/lldb/tools/lldb-dap/LLDBUtils.cpp
T
vasilito cb424d7448 build: static patch-sanity linter (shift-left the malformed-patch class)
verify-patch-sanity.py validates every active recipe .patch has internally-
consistent hunk line counts — catching the 'malformed patch at line N' failure
at commit/CI/preflight time instead of hours into a cook. This cycle hit that
class three times (qtwaylandscanner, sddm, xwayland), each only discovered when
cookbook tried to apply the patch.

Running it across the repo found 29 latent malformed patches (validated against
GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22').
They were harmless only because they sit in vendored recipes (baked, not re-
applied) — but would fail on any version-bump re-derivation. --fix recounts the
hunk headers (body untouched) and repaired all 29.

Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test
(test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats
(empty placeholders, bare-@@ git hunks).
2026-08-01 05:13:02 +03:00

263 lines
8.4 KiB
C++

//===-- LLDBUtils.cpp -------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "LLDBUtils.h"
#include "JSONUtils.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBFrame.h"
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBThread.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <mutex>
#include <system_error>
namespace lldb_dap {
bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
llvm::raw_ostream &strm, bool parse_command_directives,
bool echo_commands) {
if (commands.empty())
return true;
bool did_print_prefix = false;
// We only need the prompt when echoing commands.
std::string prompt_string;
if (echo_commands) {
prompt_string = "(lldb) ";
// Get the current prompt from settings.
if (const lldb::SBStructuredData prompt = debugger.GetSetting("prompt")) {
const size_t prompt_length = prompt.GetStringValue(nullptr, 0);
if (prompt_length != 0) {
prompt_string.resize(prompt_length + 1);
prompt.GetStringValue(prompt_string.data(), prompt_string.length());
}
}
}
lldb::SBCommandInterpreter interp = debugger.GetCommandInterpreter();
for (llvm::StringRef command : commands) {
lldb::SBCommandReturnObject result;
bool quiet_on_success = false;
bool check_error = false;
while (parse_command_directives) {
if (command.starts_with("?")) {
command = command.drop_front();
quiet_on_success = true;
} else if (command.starts_with("!")) {
command = command.drop_front();
check_error = true;
} else {
break;
}
}
{
// Prevent simultaneous calls to HandleCommand, e.g. EventThreadFunction
// may asynchronously call RunExitCommands when we are already calling
// RunTerminateCommands.
static std::mutex handle_command_mutex;
std::lock_guard<std::mutex> locker(handle_command_mutex);
interp.HandleCommand(command.str().c_str(), result,
/*add_to_history=*/true);
}
const bool got_error = !result.Succeeded();
// The if statement below is assuming we always print out `!` prefixed
// lines. The only time we don't print is when we have `quiet_on_success ==
// true` and we don't have an error.
if (quiet_on_success ? got_error : true) {
if (!did_print_prefix && !prefix.empty()) {
strm << prefix << "\n";
did_print_prefix = true;
}
if (echo_commands)
strm << prompt_string.c_str() << command << '\n';
auto output_len = result.GetOutputSize();
if (output_len) {
const char *output = result.GetOutput();
strm << output;
}
auto error_len = result.GetErrorSize();
if (error_len) {
const char *error = result.GetError();
strm << error;
}
}
if (check_error && got_error)
return false; // Stop running commands.
}
return true;
}
std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
bool &required_command_failed,
bool parse_command_directives, bool echo_commands) {
required_command_failed = false;
std::string s;
llvm::raw_string_ostream strm(s);
required_command_failed =
!RunLLDBCommands(debugger, prefix, commands, strm,
parse_command_directives, echo_commands);
return s;
}
bool ThreadHasStopReason(lldb::SBThread &thread) {
switch (thread.GetStopReason()) {
case lldb::eStopReasonTrace:
case lldb::eStopReasonPlanComplete:
case lldb::eStopReasonBreakpoint:
case lldb::eStopReasonWatchpoint:
case lldb::eStopReasonInstrumentation:
case lldb::eStopReasonSignal:
case lldb::eStopReasonException:
case lldb::eStopReasonExec:
case lldb::eStopReasonProcessorTrace:
case lldb::eStopReasonFork:
case lldb::eStopReasonVFork:
case lldb::eStopReasonVForkDone:
case lldb::eStopReasonInterrupt:
case lldb::eStopReasonHistoryBoundary:
return true;
case lldb::eStopReasonThreadExiting:
case lldb::eStopReasonInvalid:
case lldb::eStopReasonNone:
break;
}
return false;
}
static uint32_t constexpr THREAD_INDEX_SHIFT = 19;
uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id) {
return dap_frame_id >> THREAD_INDEX_SHIFT;
}
uint32_t GetLLDBFrameID(uint64_t dap_frame_id) {
return dap_frame_id & ((1u << THREAD_INDEX_SHIFT) - 1);
}
int64_t MakeDAPFrameID(lldb::SBFrame &frame) {
return ((int64_t)frame.GetThread().GetIndexID() << THREAD_INDEX_SHIFT) |
frame.GetFrameID();
}
lldb::SBEnvironment
GetEnvironmentFromArguments(const llvm::json::Object &arguments) {
lldb::SBEnvironment envs{};
constexpr llvm::StringRef env_key = "env";
const llvm::json::Value *raw_json_env = arguments.get(env_key);
if (!raw_json_env)
return envs;
if (raw_json_env->kind() == llvm::json::Value::Object) {
auto env_map = GetStringMap(arguments, env_key);
for (const auto &[key, value] : env_map)
envs.Set(key.c_str(), value.c_str(), true);
} else if (raw_json_env->kind() == llvm::json::Value::Array) {
const auto envs_strings = GetStrings(&arguments, env_key);
lldb::SBStringList entries{};
for (const auto &env : envs_strings)
entries.AppendString(env.c_str());
envs.SetEntries(entries, true);
}
return envs;
}
lldb::StopDisassemblyType
GetStopDisassemblyDisplay(lldb::SBDebugger &debugger) {
lldb::StopDisassemblyType result =
lldb::StopDisassemblyType::eStopDisassemblyTypeNoDebugInfo;
lldb::SBStructuredData string_result =
debugger.GetSetting("stop-disassembly-display");
const size_t result_length = string_result.GetStringValue(nullptr, 0);
if (result_length > 0) {
std::string result_string(result_length, '\0');
string_result.GetStringValue(result_string.data(), result_length + 1);
result =
llvm::StringSwitch<lldb::StopDisassemblyType>(result_string)
.Case("never", lldb::StopDisassemblyType::eStopDisassemblyTypeNever)
.Case("always",
lldb::StopDisassemblyType::eStopDisassemblyTypeAlways)
.Case("no-source",
lldb::StopDisassemblyType::eStopDisassemblyTypeNoSource)
.Case("no-debuginfo",
lldb::StopDisassemblyType::eStopDisassemblyTypeNoDebugInfo)
.Default(
lldb::StopDisassemblyType::eStopDisassemblyTypeNoDebugInfo);
}
return result;
}
llvm::Error ToError(const lldb::SBError &error) {
if (error.Success())
return llvm::Error::success();
return llvm::createStringError(
std::error_code(error.GetError(), std::generic_category()),
error.GetCString());
}
std::string GetStringValue(const lldb::SBStructuredData &data) {
if (!data.IsValid())
return "";
const size_t str_length = data.GetStringValue(nullptr, 0);
if (!str_length)
return "";
std::string str(str_length, 0);
data.GetStringValue(str.data(), str_length + 1);
return str;
}
ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger)
: m_debugger(debugger), m_async(m_debugger.GetAsync()) {
m_debugger.SetAsync(false);
}
ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); }
std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) {
const auto directory_length = ::strlen(file_spec.GetDirectory());
const auto file_name_length = ::strlen(file_spec.GetFilename());
std::string path(directory_length + file_name_length + 1, '\0');
file_spec.GetPath(path.data(), path.length() + 1);
return path;
}
lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target,
const lldb::SBAddress &address) {
lldb::SBSymbolContext sc = target.ResolveSymbolContextForAddress(
address, lldb::eSymbolContextLineEntry);
return sc.GetLineEntry();
}
} // namespace lldb_dap