@@ -969,12 +969,82 @@ Status MinidumpFileBuilder::DumpDirectories() const {
969969 return error;
970970}
971971
972- static uint64_t
973- GetLargestRangeSize (const std::vector<CoreFileMemoryRange> &ranges) {
974- uint64_t max_size = 0 ;
975- for (const auto &core_range : ranges)
976- max_size = std::max (max_size, core_range.range .size ());
977- return max_size;
972+ Status MinidumpFileBuilder::ReadWriteMemoryInChunks (
973+ const lldb_private::CoreFileMemoryRange &range, uint64_t *bytes_read) {
974+ Log *log = GetLog (LLDBLog::Object);
975+ lldb::addr_t addr = range.range .start ();
976+ lldb::addr_t size = range.range .size ();
977+ // First we set the byte tally to 0, so if we do exit gracefully
978+ // the caller doesn't think the random garbage on the stack is a
979+ // success.
980+ if (bytes_read)
981+ *bytes_read = 0 ;
982+
983+ uint64_t bytes_remaining = size;
984+ uint64_t total_bytes_read = 0 ;
985+ auto data_up = std::make_unique<DataBufferHeap>(
986+ std::min (bytes_remaining, MAX_WRITE_CHUNK_SIZE), 0 );
987+ Status error;
988+ while (bytes_remaining > 0 ) {
989+ // Get the next read chunk size as the minimum of the remaining bytes and
990+ // the write chunk max size.
991+ const size_t bytes_to_read =
992+ std::min (bytes_remaining, MAX_WRITE_CHUNK_SIZE);
993+ const size_t bytes_read_for_chunk =
994+ m_process_sp->ReadMemory (range.range .start () + total_bytes_read,
995+ data_up->GetBytes (), bytes_to_read, error);
996+ if (error.Fail () || bytes_read_for_chunk == 0 ) {
997+ LLDB_LOGF (log,
998+ " Failed to read memory region at: %" PRIx64
999+ " . Bytes read: %zu, error: %s" ,
1000+ addr, bytes_read_for_chunk, error.AsCString ());
1001+ // If we've only read one byte we can just give up and return
1002+ if (total_bytes_read == 0 )
1003+ return Status ();
1004+
1005+ // If we've read some bytes, we stop trying to read more and return
1006+ // this best effort attempt
1007+ bytes_remaining = 0 ;
1008+ } else if (bytes_read_for_chunk != bytes_to_read) {
1009+ LLDB_LOGF (
1010+ log, " Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes" ,
1011+ addr, size);
1012+
1013+ // If we've read some bytes, we stop trying to read more and return
1014+ // this best effort attempt
1015+ bytes_remaining = 0 ;
1016+ }
1017+
1018+ // Write to the minidump file with the chunk potentially flushing to disk.
1019+ // this is the only place we want to return a true error, so that we can
1020+ // fail. If we get an error writing to disk we can't easily gaurauntee
1021+ // that we won't corrupt the minidump.
1022+ error = AddData (data_up->GetBytes (), bytes_read_for_chunk);
1023+ if (error.Fail ())
1024+ return error;
1025+
1026+ // This check is so we don't overflow when the error code above sets the
1027+ // bytes to read to 0 (the graceful exit condition).
1028+ if (bytes_remaining > 0 )
1029+ bytes_remaining -= bytes_read_for_chunk;
1030+
1031+ total_bytes_read += bytes_read_for_chunk;
1032+ // If the caller wants a tally back of the bytes_read, update it as we
1033+ // write. We do this in the loop so if we encounter an error we can
1034+ // report the accurate total.
1035+ if (bytes_read)
1036+ *bytes_read += bytes_read_for_chunk;
1037+
1038+ // We clear the heap per loop, without checking if we
1039+ // read the expected bytes this is so we don't allocate
1040+ // more than the MAX_WRITE_CHUNK_SIZE. But we do check if
1041+ // this is even worth clearing before we return and
1042+ // destruct the heap.
1043+ if (bytes_remaining > 0 )
1044+ data_up->Clear ();
1045+ }
1046+
1047+ return error;
9781048}
9791049
9801050Status
@@ -987,8 +1057,6 @@ MinidumpFileBuilder::AddMemoryList_32(std::vector<CoreFileMemoryRange> &ranges,
9871057
9881058 Log *log = GetLog (LLDBLog::Object);
9891059 size_t region_index = 0 ;
990- auto data_up =
991- std::make_unique<DataBufferHeap>(GetLargestRangeSize (ranges), 0 );
9921060 for (const auto &core_range : ranges) {
9931061 // Take the offset before we write.
9941062 const offset_t offset_for_data = GetCurrentDataEndOffset ();
@@ -1003,18 +1071,15 @@ MinidumpFileBuilder::AddMemoryList_32(std::vector<CoreFileMemoryRange> &ranges,
10031071 ++region_index;
10041072
10051073 progress.Increment (1 , " Adding Memory Range " + core_range.Dump ());
1006- const size_t bytes_read =
1007- m_process_sp->ReadMemory (addr, data_up->GetBytes (), size, error);
1008- if (error.Fail () || bytes_read == 0 ) {
1009- LLDB_LOGF (log, " Failed to read memory region. Bytes read: %zu, error: %s" ,
1010- bytes_read, error.AsCString ());
1011- // Just skip sections with errors or zero bytes in 32b mode
1074+ uint64_t bytes_read;
1075+ error = ReadWriteMemoryInChunks (core_range, &bytes_read);
1076+ if (error.Fail ())
1077+ return error;
1078+
1079+ // If we completely failed to read this range
1080+ // we can just omit any of the book keeping.
1081+ if (bytes_read == 0 )
10121082 continue ;
1013- } else if (bytes_read != size) {
1014- LLDB_LOGF (
1015- log, " Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes" ,
1016- addr, size);
1017- }
10181083
10191084 MemoryDescriptor descriptor;
10201085 descriptor.StartOfMemoryRange =
@@ -1026,11 +1091,6 @@ MinidumpFileBuilder::AddMemoryList_32(std::vector<CoreFileMemoryRange> &ranges,
10261091 descriptors.push_back (descriptor);
10271092 if (m_thread_by_range_end.count (end) > 0 )
10281093 m_thread_by_range_end[end].Stack = descriptor;
1029-
1030- // Add the data to the buffer, flush as needed.
1031- error = AddData (data_up->GetBytes (), bytes_read);
1032- if (error.Fail ())
1033- return error;
10341094 }
10351095
10361096 // Add a directory that references this list
@@ -1106,8 +1166,6 @@ MinidumpFileBuilder::AddMemoryList_64(std::vector<CoreFileMemoryRange> &ranges,
11061166
11071167 Log *log = GetLog (LLDBLog::Object);
11081168 size_t region_index = 0 ;
1109- auto data_up =
1110- std::make_unique<DataBufferHeap>(GetLargestRangeSize (ranges), 0 );
11111169 for (const auto &core_range : ranges) {
11121170 const addr_t addr = core_range.range .start ();
11131171 const addr_t size = core_range.range .size ();
@@ -1120,27 +1178,19 @@ MinidumpFileBuilder::AddMemoryList_64(std::vector<CoreFileMemoryRange> &ranges,
11201178 ++region_index;
11211179
11221180 progress.Increment (1 , " Adding Memory Range " + core_range.Dump ());
1123- const size_t bytes_read =
1124- m_process_sp-> ReadMemory (addr, data_up-> GetBytes (), size, error );
1125- if (error.Fail ()) {
1126- LLDB_LOGF (log, " Failed to read memory region. Bytes read: %zu, error: %s " ,
1127- bytes_read, error. AsCString ());
1128- error. Clear ();
1181+ uint64_t bytes_read;
1182+ error = ReadWriteMemoryInChunks (core_range, &bytes_read );
1183+ if (error.Fail ())
1184+ return error;
1185+
1186+ if (bytes_read == 0 ) {
11291187 cleanup_required = true ;
11301188 descriptors[region_index].DataSize = 0 ;
11311189 }
11321190 if (bytes_read != size) {
1133- LLDB_LOGF (
1134- log, " Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes" ,
1135- addr, size);
11361191 cleanup_required = true ;
11371192 descriptors[region_index].DataSize = bytes_read;
11381193 }
1139-
1140- // Add the data to the buffer, flush as needed.
1141- error = AddData (data_up->GetBytes (), bytes_read);
1142- if (error.Fail ())
1143- return error;
11441194 }
11451195
11461196 // Early return if there is no cleanup needed.
0 commit comments