Skip to content

Fix saving minidump from lldb-dap #89113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/RegisterValue.h"

#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -154,8 +155,16 @@ Status WriteString(const std::string &to_write,

llvm::Expected<uint64_t> getModuleFileSize(Target &target,
const ModuleSP &mod) {
SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
// JIT module has the same vm and file size.
uint64_t SizeOfImage = 0;
if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) {
for (const auto &section : *mod->GetObjectFile()->GetSectionList()) {
SizeOfImage += section->GetByteSize();
}
return SizeOfImage;
}

SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();

if (!sect_sp) {
return llvm::createStringError(std::errc::operation_not_supported,
Expand Down Expand Up @@ -226,8 +235,13 @@ Status MinidumpFileBuilder::AddModuleList(Target &target) {
std::string module_name = mod->GetSpecificationDescription();
auto maybe_mod_size = getModuleFileSize(target, mod);
if (!maybe_mod_size) {
error.SetErrorStringWithFormat("Unable to get the size of module %s.",
module_name.c_str());
llvm::Error mod_size_err = maybe_mod_size.takeError();
llvm::handleAllErrors(std::move(mod_size_err),
[&](const llvm::ErrorInfoBase &E) {
error.SetErrorStringWithFormat(
"Unable to get the size of module %s: %s.",
module_name.c_str(), E.message().c_str());
});
return error;
}

Expand Down
18 changes: 14 additions & 4 deletions lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/LLDBLog.h"

#include "llvm/Support/FileSystem.h"

Expand Down Expand Up @@ -68,26 +69,35 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,

Target &target = process_sp->GetTarget();

Log *log = GetLog(LLDBLog::Object);
error = builder.AddSystemInfo(target.GetArchitecture().GetTriple());
if (error.Fail())
if (error.Fail()) {
LLDB_LOG(log, "AddSystemInfo failed: %s", error.AsCString());
return false;
}

error = builder.AddModuleList(target);
if (error.Fail())
if (error.Fail()) {
LLDB_LOG(log, "AddModuleList failed: %s", error.AsCString());
return false;
}

builder.AddMiscInfo(process_sp);

error = builder.AddThreadList(process_sp);
if (error.Fail())
if (error.Fail()) {
LLDB_LOG(log, "AddThreadList failed: %s", error.AsCString());
return false;
}

// Add any exceptions but only if there are any in any threads.
builder.AddExceptions(process_sp);

error = builder.AddMemoryList(process_sp, core_style);
if (error.Fail())
if (error.Fail()) {
LLDB_LOG(log, "AddMemoryList failed: %s", error.AsCString());
return false;
}

if (target.GetArchitecture().GetTriple().getOS() ==
llvm::Triple::OSType::Linux) {
Expand Down
5 changes: 5 additions & 0 deletions lldb/test/API/tools/lldb-dap/save-core/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ENABLE_THREADS := YES

CXX_SOURCES := main.cpp

include Makefile.rules
79 changes: 79 additions & 0 deletions lldb/test/API/tools/lldb-dap/save-core/TestDAP_save_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
Test saving core minidump from lldb-dap
"""

import dap_server
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
import lldbdap_testcase
from lldbsuite.test import lldbutil


class TestDAP_save_core(lldbdap_testcase.DAPTestCaseBase):
@skipUnlessArch("x86_64")
@skipUnlessPlatform(["linux"])
def test_save_core(self):
"""
Tests saving core minidump from lldb-dap.
"""
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
source = "main.cpp"
# source_path = os.path.join(os.getcwd(), source)
breakpoint1_line = line_number(source, "// breakpoint 1")
lines = [breakpoint1_line]
# Set breakpoint in the thread function so we can step the threads
breakpoint_ids = self.set_source_breakpoints(source, lines)
self.assertEqual(
len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
)
self.continue_to_breakpoints(breakpoint_ids)

# Getting dap stack trace may trigger __lldb_caller_function JIT module to be created.
self.get_stackFrames(startFrame=0)

# Evaluating an expression that cause "_$__lldb_valid_pointer_check" JIT module to be created.
expression = 'printf("this is a test")'
self.dap_server.request_evaluate(expression, context="watch")

# Verify "_$__lldb_valid_pointer_check" JIT module is created.
modules = self.dap_server.get_modules()
self.assertTrue(modules["_$__lldb_valid_pointer_check"])
thread_count = len(self.dap_server.get_threads())

core_stack = self.getBuildArtifact("core.stack.dmp")
core_dirty = self.getBuildArtifact("core.dirty.dmp")
core_full = self.getBuildArtifact("core.full.dmp")

base_command = "`process save-core --plugin-name=minidump "
self.dap_server.request_evaluate(
base_command + " --style=stack '%s'" % (core_stack), context="repl"
)

self.assertTrue(os.path.isfile(core_stack))
self.verify_core_file(core_stack, len(modules), thread_count)

self.dap_server.request_evaluate(
base_command + " --style=modified-memory '%s'" % (core_dirty),
context="repl",
)
self.assertTrue(os.path.isfile(core_dirty))
self.verify_core_file(core_dirty, len(modules), thread_count)

self.dap_server.request_evaluate(
base_command + " --style=full '%s'" % (core_full), context="repl"
)
self.assertTrue(os.path.isfile(core_full))
self.verify_core_file(core_full, len(modules), thread_count)

def verify_core_file(self, core_path, expected_module_count, expected_thread_count):
# To verify, we'll launch with the mini dump
target = self.dbg.CreateTarget(None)
process = target.LoadCore(core_path)

# check if the core is in desired state
self.assertTrue(process, PROCESS_IS_VALID)
self.assertTrue(process.GetProcessInfo().IsValid())
self.assertNotEqual(target.GetTriple().find("linux"), -1)
self.assertTrue(target.GetNumModules(), expected_module_count)
self.assertEqual(process.GetNumThreads(), expected_thread_count)
8 changes: 8 additions & 0 deletions lldb/test/API/tools/lldb-dap/save-core/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
int function(int x) {
if ((x % 2) == 0)
return function(x - 1) + x; // breakpoint 1
else
return x;
}

int main(int argc, char const *argv[]) { return function(2); }