@@ -121,6 +121,72 @@ class PlaceholderObjectFile : public ObjectFile {
121
121
lldb::addr_t m_base;
122
122
lldb::addr_t m_size;
123
123
};
124
+
125
+ // / Duplicate the HashElfTextSection() from the breakpad sources.
126
+ // /
127
+ // / Breakpad, a Google crash log reporting tool suite, creates minidump files
128
+ // / for many different architectures. When using Breakpad to create ELF
129
+ // / minidumps, it will check for a GNU build ID when creating a minidump file
130
+ // / and if one doesn't exist in the file, it will say the UUID of the file is a
131
+ // / checksum of up to the first 4096 bytes of the .text section. Facebook also
132
+ // / uses breakpad and modified this hash to avoid collisions so we can
133
+ // / calculate and check for this as well.
134
+ // /
135
+ // / The breakpad code might end up hashing up to 15 bytes that immediately
136
+ // / follow the .text section in the file, so this code must do exactly what it
137
+ // / does so we can get an exact match for the UUID.
138
+ // /
139
+ // / \param[in] module_sp The module to grab the .text section from.
140
+ // /
141
+ // / \param[in/out] breakpad_uuid A vector that will receive the calculated
142
+ // / breakpad .text hash.
143
+ // /
144
+ // / \param[in/out] facebook_uuid A vector that will receive the calculated
145
+ // / facebook .text hash.
146
+ // /
147
+ void HashElfTextSection (ModuleSP module_sp, std::vector<uint8_t > &breakpad_uuid,
148
+ std::vector<uint8_t > &facebook_uuid) {
149
+ SectionList *sect_list = module_sp->GetSectionList ();
150
+ if (sect_list == nullptr )
151
+ return ;
152
+ SectionSP sect_sp = sect_list->FindSectionByName (ConstString (" .text" ));
153
+ if (!sect_sp)
154
+ return ;
155
+ constexpr size_t kMDGUIDSize = 16 ;
156
+ constexpr size_t kBreakpadPageSize = 4096 ;
157
+ // The breakpad code has a bug where it might access beyond the end of a
158
+ // .text section by up to 15 bytes, so we must ensure we round up to the
159
+ // next kMDGUIDSize byte boundary.
160
+ DataExtractor data;
161
+ const size_t text_size = sect_sp->GetFileSize ();
162
+ const size_t read_size = std::min<size_t >(
163
+ llvm::alignTo (text_size, kMDGUIDSize ), kBreakpadPageSize );
164
+ sect_sp->GetObjectFile ()->GetData (sect_sp->GetFileOffset (), read_size, data);
165
+
166
+ breakpad_uuid.assign (kMDGUIDSize , 0 );
167
+ facebook_uuid.assign (kMDGUIDSize , 0 );
168
+
169
+ // The only difference between the breakpad hash and the facebook hash is the
170
+ // hashing of the text section size into the hash prior to hashing the .text
171
+ // contents.
172
+ for (size_t i = 0 ; i < kMDGUIDSize ; i++)
173
+ facebook_uuid[i] ^= text_size % 255 ;
174
+
175
+ // This code carefully duplicates how the hash was created in Breakpad
176
+ // sources, including the error where it might has an extra 15 bytes past the
177
+ // end of the .text section if the .text section is less than a page size in
178
+ // length.
179
+ const uint8_t *ptr = data.GetDataStart ();
180
+ const uint8_t *ptr_end = data.GetDataEnd ();
181
+ while (ptr < ptr_end) {
182
+ for (unsigned i = 0 ; i < kMDGUIDSize ; i++) {
183
+ breakpad_uuid[i] ^= ptr[i];
184
+ facebook_uuid[i] ^= ptr[i];
185
+ }
186
+ ptr += kMDGUIDSize ;
187
+ }
188
+ }
189
+
124
190
} // namespace
125
191
126
192
ConstString ProcessMinidump::GetPluginNameStatic () {
@@ -494,10 +560,33 @@ void ProcessMinidump::ReadModuleList() {
494
560
const bool match = dmp_bytes.empty () || mod_bytes.empty () ||
495
561
mod_bytes.take_front (dmp_bytes.size ()) == dmp_bytes;
496
562
if (!match) {
563
+ // Breakpad generates minindump files, and if there is no GNU build
564
+ // ID in the binary, it will calculate a UUID by hashing first 4096
565
+ // bytes of the .text section and using that as the UUID for a module
566
+ // in the minidump. Facebook uses a modified breakpad client that
567
+ // uses a slightly modified this hash to avoid collisions. Check for
568
+ // UUIDs from the minindump that match these cases and accept the
569
+ // module we find if they do match.
570
+ std::vector<uint8_t > breakpad_uuid;
571
+ std::vector<uint8_t > facebook_uuid;
572
+ HashElfTextSection (module_sp, breakpad_uuid, facebook_uuid);
573
+ if (dmp_bytes == llvm::ArrayRef<uint8_t >(breakpad_uuid)) {
574
+ LLDB_LOG (log , " Breakpad .text hash match for {0}." , name);
575
+ } else if (dmp_bytes == llvm::ArrayRef<uint8_t >(facebook_uuid)) {
576
+ LLDB_LOG (log , " Facebook .text hash match for {0}." , name);
577
+ } else {
578
+ // The UUID wasn't a partial match and didn't match the .text hash
579
+ // so remove the module from the target, we will need to create a
580
+ // placeholder object file.
497
581
GetTarget ().GetImages ().Remove (module_sp);
498
582
module_sp.reset ();
583
+ }
584
+ } else {
585
+ LLDB_LOG (log , " Partial uuid match for {0}." , name);
499
586
}
500
587
}
588
+ } else {
589
+ LLDB_LOG (log , " Full uuid match for {0}." , name);
501
590
}
502
591
if (module_sp) {
503
592
// Watch out for place holder modules that have different paths, but the
0 commit comments