Files
llvm/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i
Jacob Lalonde 6a7f572ef9 [LLDB] Fix Memory64 BaseRVA, move all non-stack memory to Mem64. (#146777)
### Context

Over a year ago, I landed support for 64b Memory ranges in Minidump
(#95312). In this patch we added the Memory64 list stream, which is
effectively a Linked List on disk. The layout is a sixteen byte header
and then however many Memory descriptors.

### The Bug
This is a classic off-by one error, where I added 8 bytes instead of 16
for the header. This caused the first region to start 8 bytes before the
correct RVA, thus shifting all memory reads by 8 bytes. We are correctly
writing all the regions to disk correctly, with no physical corruption
but the RVA is defined wrong, meaning we were incorrectly reading memory


![image](https://github.com/user-attachments/assets/049ef55d-856c-4f3c-9376-aeaa3fe8c0e1)


### Why wasn't this caught?

One problem we've had is forcing Minidump to actually use the 64b mode,
it would be a massive waste of resources to have a test that actually
wrote >4.2gb of IO to validate the 64b regions, and so almost all
validation has been manual. As a weakness of manual testing, this issue
is psuedo non-deterministic, as what regions end up in 64b or 32b is
handled greedily and iterated in the order it's laid out in
/proc/pid/maps. We often validated 64b was written correctly by
hexdumping the Minidump itself, which was not corrupted (other than the
BaseRVA)


![image](https://github.com/user-attachments/assets/b599e3be-2d59-47e2-8a2d-75f182bb0b1d)

### Why is this showing up now?

During internal usage, we had a bug report that the Minidump wasn't
displaying values. I was unable to repro the issue, but during my
investigation I saw the variables were in the 64b regions which resulted
in me identifying the bug.

### How do we prevent future regressions?

To prevent regressions, and honestly to save my sanity for figuring out
where 8 bytes magically came from, I've added a new API to
SBSaveCoreOptions.

```SBSaveCoreOptions::GetMemoryRegionsToSave()```
The ability to get the memory regions that we intend to include in the Coredump. I added this so we can compare what we intended to include versus what was actually included. Traditionally we've always had issues comparing regions because Minidump includes `/proc/pid/maps` and it can be difficult to know what memoryregion read failure was a genuine error or just a page that wasn't meant to be included. 

We are also leveraging this API to choose the memory regions to be generated, as well as for testing what regions should be bytewise 1:1.

After much debate with @clayborg, I've moved all non-stack memory to the Memory64 List. This list doesn't incur us any meaningful overhead and Greg originally suggested doing this in the original 64b PR. This also means we're exercising the 64b path every single time we save a Minidump, preventing regressions on this feature from slipping through testing in the future.

Snippet produced by [minidump.py](https://github.com/clayborg/scripts) 
```
MINIDUMP_MEMORY_LIST:
NumberOfMemoryRanges = 0x00000002
MemoryRanges[0] = [0x00007f61085ff9f0 - 0x00007f6108601000) @ 0x0003f655
MemoryRanges[1] = [0x00007ffe47e50910 - 0x00007ffe47e52000) @ 0x00040c65

MINIDUMP_MEMORY64_LIST:
NumberOfMemoryRanges = 0x000000000000002e
BaseRva              = 0x0000000000042669
MemoryRanges[0]      = [0x00005584162d8000 - 0x00005584162d9000)
MemoryRanges[1]      = [0x00005584162d9000 - 0x00005584162db000)
MemoryRanges[2]      = [0x00005584162db000 - 0x00005584162dd000)
MemoryRanges[3]      = [0x00005584162dd000 - 0x00005584162ff000)
MemoryRanges[4]      = [0x00007f6100000000 - 0x00007f6100021000)
MemoryRanges[5]      = [0x00007f6108800000 - 0x00007f6108828000)
MemoryRanges[6]      = [0x00007f6108828000 - 0x00007f610899d000)
MemoryRanges[7]      = [0x00007f610899d000 - 0x00007f61089f9000)
MemoryRanges[8]      = [0x00007f61089f9000 - 0x00007f6108a08000)
MemoryRanges[9]      = [0x00007f6108bf5000 - 0x00007f6108bf7000)
```

### Misc
As a part of this fix I had to look at LLDB logs a lot, you'll notice I added `0x` to many of the PRIx64 `LLDB_LOGF`. This is so the user (or I) can directly copy paste the address in the logs instead of adding the hex prefix themselves.

Added some SBSaveCore tests for the new GetMemoryAPI, and Docstrings.

CC: @DavidSpickett, @da-viper @labath because we've been working together on save-core plugins, review it optional and I didn't tag you but figured you'd want to know
2025-07-18 13:05:15 -07:00

84 lines
3.8 KiB
OpenEdge ABL

%feature("docstring",
"A container to specify how to save a core file.
SBSaveCoreOptions includes API's to specify the memory regions and threads to include
when generating a core file. It extends the existing SaveCoreStyle option.
* eSaveCoreFull will save off all thread and memory regions, ignoring the memory regions and threads in the options object.
* eSaveCoreDirtyOnly pages will capture all threads and all rw- memory regions, in addition to the regions specified in the options object if they are not already captured.
* eSaveCoreStackOnly will capture all threads, but no memory regions unless specified.
* eSaveCoreCustomOnly Custom defers entirely to the SBSaveCoreOptions object and will only save what is specified. Picking custom and specifying nothing will result in an error being returned.
Note that currently ELF Core files are not supported."
) lldb::SBSaveCoreOptions;
%feature("docstring", "
Set the plugin name to save a Core file with. Only plugins registered with Plugin manager will be accepted
Examples are Minidump and Mach-O."
) lldb::SBSaveCoreOptions::SetPluginName;
%feature("docstring", "
Get the specified plugin name, or None if the name is not set."
) lldb::SBSaveCoreOptions::GetPluginName;
%feature("docstring", "
Set the lldb.SaveCoreStyle."
) lldb::SBSaveCoreOptions::SetStyle;
%feature("docstring", "
Get the specified lldb.SaveCoreStyle, or eSaveCoreUnspecified if not set."
) lldb::SBSaveCoreOptions::GetStyle;
%feature("docstring", "
Set the file path to save the Core file at."
) lldb::SBSaveCoreOptions::SetOutputFile;
%feature("docstring", "
Get an SBFileSpec corresponding to the specified output path, or none if not set."
) lldb::SBSaveCoreOptions::GetOutputFile;
%feature("docstring", "
Set the process to save, or unset a process by providing a default SBProcess.
Resetting will result in the reset of all process specific options, such as Threads to save."
) lldb::SBSaveCoreOptions::SetProcess;
%feature("docstring", "
Get the process to save. If a process is not defined, whether by calling clear or by not setting a process, an invalid process will be returned."
) lldb::SBSaveCoreOptions::GetProcess;
%feature("docstring", "
Add an SBThread to be saved, an error will be returned if an SBThread from a different process is specified.
The process is set either by the first SBThread added to the options container, or explicitly by the SetProcess call."
) lldb::SBSaveCoreOptions::AddThread;
%feature("docstring", "
Remove an SBthread if present in the container, returns true if a matching thread was found and removed."
) lldb::SBSaveCoreOptions::RemoveThread;
%feature("docstring", "
Add a memory region to save, an error will be returned in the region is invalid.
Ranges that overlap will be unioned into a single region."
) lldb::SBSaveCoreOptions::AddMemoryRegionToSave;
%feature("docstring", "
Get an SBThreadCollection of all threads marked to be saved. This collection is not sorted according to insertion order."
) lldb::SBSaveCoreOptions::GetThreadsToSave;
%feature("docstring", "
Get an SBMemoryRegionInfoList of all the Regions that LLDB will attempt to write into the Core. Note, reading from these
regions can fail, and it's not guaraunteed every region will be present in the resulting core. If called without a valid process or style set an empty
collection will be returned."
) lldb::SBSaveCoreOptions::GetMemoryRegionsToSave;
%feature("docstring", "
Get the current total number of bytes the core is expected to have, excluding the overhead of the core file format.
Requires both a Process and a Style to be specified. An error will be returned if the provided options would result in no data being saved."
) lldb::SBSaveCoreOptions::GetCurrentSizeInBytes;
%feature("docstring", "
Unset all options."
) lldb::SBSaveCoreOptions::Clear;