Skip to content

Commit 25ff389

Browse files
committed
Fix test to validate we're reading beyond the end of the stack pointer | Fix the saivng stack logic in MinidumpFileBuilder | Save off stack's before all other styles and prevent double saving of that region
1 parent 5953f54 commit 25ff389

File tree

3 files changed

+75
-58
lines changed

3 files changed

+75
-58
lines changed

lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "lldb/Core/Module.h"
1515
#include "lldb/Core/ModuleList.h"
1616
#include "lldb/Core/Section.h"
17+
#include "lldb/Target/ABI.h"
1718
#include "lldb/Target/MemoryRegionInfo.h"
1819
#include "lldb/Target/Process.h"
1920
#include "lldb/Target/RegisterContext.h"
@@ -490,9 +491,12 @@ findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
490491
return llvm::createStringError(
491492
std::errc::not_supported,
492493
"unable to load stack segment of the process");
493-
494-
const addr_t addr = range_info.GetRange().GetRangeBase();
495-
const addr_t size = range_info.GetRange().GetByteSize();
494+
// This is a duplicate of the logic in Process::SaveOffRegionsWithStackPointers
495+
// but ultimately, we need to only save up from the start of `the stack down to the stack pointer.
496+
const addr_t range_end = range_info.GetRange().GetRangeEnd();
497+
const size_t red_zone = process_sp->GetABI()->GetRedZoneSize();
498+
const addr_t addr = rsp - red_zone;
499+
const addr_t size = range_end - addr;
496500

497501
if (size == 0)
498502
return llvm::createStringError(std::errc::not_supported,

lldb/source/Target/Process.cpp

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6335,16 +6335,51 @@ static void AddRegion(const MemoryRegionInfo &region, bool try_dirty_pages,
63356335
ranges.push_back(CreateCoreFileMemoryRange(region));
63366336
}
63376337

6338+
static void
6339+
SaveOffRegionsWithStackPointers(Process &process,
6340+
const MemoryRegionInfos &regions,
6341+
Process::CoreFileMemoryRanges &ranges,
6342+
std::set<addr_t> &stack_ends) {
6343+
const bool try_dirty_pages = true;
6344+
6345+
// Before we take any dump, we want to save off the used portions of the stacks
6346+
// and mark those memory regions as saved. This prevents us from saving the unused portion
6347+
// of the stack below the stack pointer. Saving space on the dump.
6348+
for (lldb::ThreadSP thread_sp : process.GetThreadList().Threads()) {
6349+
if (!thread_sp)
6350+
continue;
6351+
StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0);
6352+
if (!frame_sp)
6353+
continue;
6354+
RegisterContextSP reg_ctx_sp = frame_sp->GetRegisterContext();
6355+
if (!reg_ctx_sp)
6356+
continue;
6357+
const addr_t sp = reg_ctx_sp->GetSP();
6358+
const size_t red_zone = process.GetABI()->GetRedZoneSize();
6359+
lldb_private::MemoryRegionInfo sp_region;
6360+
if (process.GetMemoryRegionInfo(sp, sp_region).Success()) {
6361+
const size_t stack_head = (sp - red_zone);
6362+
const size_t stack_size = sp_region.GetRange().GetRangeEnd() - stack_head;
6363+
sp_region.GetRange().SetRangeBase(stack_head);
6364+
sp_region.GetRange().SetByteSize(stack_size);
6365+
stack_ends.insert(sp_region.GetRange().GetRangeEnd());
6366+
AddRegion(sp_region, try_dirty_pages, ranges);
6367+
}
6368+
}
6369+
}
6370+
63386371
// Save all memory regions that are not empty or have at least some permissions
63396372
// for a full core file style.
63406373
static void GetCoreFileSaveRangesFull(Process &process,
63416374
const MemoryRegionInfos &regions,
6342-
Process::CoreFileMemoryRanges &ranges) {
6375+
Process::CoreFileMemoryRanges &ranges,
6376+
std::set<addr_t> &stack_ends) {
63436377

63446378
// Don't add only dirty pages, add full regions.
63456379
const bool try_dirty_pages = false;
63466380
for (const auto &region : regions)
6347-
AddRegion(region, try_dirty_pages, ranges);
6381+
if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0)
6382+
AddRegion(region, try_dirty_pages, ranges);
63486383
}
63496384

63506385
// Save only the dirty pages to the core file. Make sure the process has at
@@ -6354,11 +6389,14 @@ const bool try_dirty_pages = false;
63546389
static void
63556390
GetCoreFileSaveRangesDirtyOnly(Process &process,
63566391
const MemoryRegionInfos &regions,
6357-
Process::CoreFileMemoryRanges &ranges) {
6392+
Process::CoreFileMemoryRanges &ranges,
6393+
std::set<addr_t> &stack_ends) {
6394+
63586395
// Iterate over the regions and find all dirty pages.
63596396
bool have_dirty_page_info = false;
63606397
for (const auto &region : regions) {
6361-
if (AddDirtyPages(region, ranges))
6398+
if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0
6399+
&& AddDirtyPages(region, ranges))
63626400
have_dirty_page_info = true;
63636401
}
63646402

@@ -6367,7 +6405,8 @@ GetCoreFileSaveRangesDirtyOnly(Process &process,
63676405
// plug-in so fall back to any region with write access permissions.
63686406
const bool try_dirty_pages = false;
63696407
for (const auto &region : regions)
6370-
if (region.GetWritable() == MemoryRegionInfo::eYes)
6408+
if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0
6409+
&& region.GetWritable() == MemoryRegionInfo::eYes)
63716410
AddRegion(region, try_dirty_pages, ranges);
63726411
}
63736412
}
@@ -6383,48 +6422,17 @@ GetCoreFileSaveRangesDirtyOnly(Process &process,
63836422
static void
63846423
GetCoreFileSaveRangesStackOnly(Process &process,
63856424
const MemoryRegionInfos &regions,
6386-
Process::CoreFileMemoryRanges &ranges) {
6425+
Process::CoreFileMemoryRanges &ranges,
6426+
std::set<addr_t> &stack_ends) {
6427+
const bool try_dirty_pages = true;
63876428
// Some platforms support annotating the region information that tell us that
63886429
// it comes from a thread stack. So look for those regions first.
63896430

6390-
// Keep track of which stack regions we have added
6391-
std::set<addr_t> stack_bases;
6392-
6393-
const bool try_dirty_pages = true;
63946431
for (const auto &region : regions) {
6395-
if (region.IsStackMemory() == MemoryRegionInfo::eYes) {
6396-
stack_bases.insert(region.GetRange().GetRangeBase());
6397-
AddRegion(region, try_dirty_pages, ranges);
6398-
}
6399-
}
6400-
6401-
// Also check with our threads and get the regions for their stack pointers
6402-
// and add those regions if not already added above.
6403-
for (lldb::ThreadSP thread_sp : process.GetThreadList().Threads()) {
6404-
if (!thread_sp)
6405-
continue;
6406-
StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0);
6407-
if (!frame_sp)
6408-
continue;
6409-
RegisterContextSP reg_ctx_sp = frame_sp->GetRegisterContext();
6410-
if (!reg_ctx_sp)
6411-
continue;
6412-
const addr_t sp = reg_ctx_sp->GetSP();
6413-
const size_t red_zone = process.GetABI()->GetRedZoneSize();
6414-
lldb_private::MemoryRegionInfo sp_region;
6415-
if (process.GetMemoryRegionInfo(sp, sp_region).Success()) {
6416-
// Only add this region if not already added above. If our stack pointer
6417-
// is pointing off in the weeds, we will want this range.
6418-
if (stack_bases.count(sp_region.GetRange().GetRangeBase()) == 0) {
6419-
// Take only the start of the stack to the stack pointer and include the redzone.
6420-
// Because stacks grow 'down' to include the red_zone we have to subtract it from the sp.
6421-
const size_t stack_head = (sp - red_zone);
6422-
const size_t stack_size = sp_region.GetRange().GetRangeEnd() - (stack_head);
6423-
sp_region.GetRange().SetRangeBase(stack_head);
6424-
sp_region.GetRange().SetByteSize(stack_size);
6425-
AddRegion(sp_region, try_dirty_pages, ranges);
6426-
}
6427-
}
6432+
// Save all the stack memory ranges not associated with a stack pointer.
6433+
if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0
6434+
&& region.IsStackMemory() == MemoryRegionInfo::eYes)
6435+
AddRegion(region, try_dirty_pages, ranges);
64286436
}
64296437
}
64306438

@@ -6436,23 +6444,27 @@ Status Process::CalculateCoreFileSaveRanges(lldb::SaveCoreStyle core_style,
64366444
return err;
64376445
if (regions.empty())
64386446
return Status("failed to get any valid memory regions from the process");
6447+
if (core_style == eSaveCoreUnspecified)
6448+
return Status("callers must set the core_style to something other than "
6449+
"eSaveCoreUnspecified");
6450+
6451+
std::set<addr_t> stack_ends;
6452+
SaveOffRegionsWithStackPointers(*this, regions, ranges, stack_ends);
64396453

64406454
switch (core_style) {
64416455
case eSaveCoreUnspecified:
6442-
err = Status("callers must set the core_style to something other than "
6443-
"eSaveCoreUnspecified");
64446456
break;
64456457

64466458
case eSaveCoreFull:
6447-
GetCoreFileSaveRangesFull(*this, regions, ranges);
6459+
GetCoreFileSaveRangesFull(*this, regions, ranges, stack_ends);
64486460
break;
64496461

64506462
case eSaveCoreDirtyOnly:
6451-
GetCoreFileSaveRangesDirtyOnly(*this, regions, ranges);
6463+
GetCoreFileSaveRangesDirtyOnly(*this, regions, ranges, stack_ends);
64526464
break;
64536465

64546466
case eSaveCoreStackOnly:
6455-
GetCoreFileSaveRangesStackOnly(*this, regions, ranges);
6467+
GetCoreFileSaveRangesStackOnly(*this, regions, ranges, stack_ends);
64566468
break;
64576469
}
64586470

lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ def verify_core_file(
4747
err = process.GetMemoryRegionInfo(sp, sp_region)
4848
self.assertTrue(err.Success(), err.GetCString())
4949
error = lldb.SBError()
50+
# Ensure thread_id is in the saved map
51+
self.assertIn(thread_id, stacks_to_sps_map)
52+
# Ensure the SP is correct
53+
self.assertEqual(stacks_to_sps_map[thread_id], sp)
5054
# Try to read at the end of the stack red zone and succeed
51-
process.ReadMemory(sp_region.GetRegionEnd() - 1, 1, error)
55+
process.ReadMemory(sp - red_zone, 1, error)
5256
self.assertTrue(error.Success(), error.GetCString())
5357
# Try to read just past the red zone and fail
54-
process.ReadMemory(sp_region.GetRegionEnd() + 1, 1, error)
55-
# Try to read from the base of the stack
56-
self.assertTrue(error.Fail(), error.GetCString())
57-
self.assertTrue(stacks_to_sps_map.__contains__(thread_id), "stacks_to_sps_map does not contain thread_idx: %d" % thread_idx)
58-
# Ensure the SP is correct
59-
self.assertEqual(stacks_to_sps_map[thread_id], sp)
58+
process.ReadMemory(sp - red_zone - 1, 1, error)
59+
self.assertTrue(error.Fail(), "No failure when reading past the red zone")
60+
6061

6162

6263
self.dbg.DeleteTarget(target)

0 commit comments

Comments
 (0)