Skip to content

Commit c5ec837

Browse files
committed
[SharedCache] Fix some bugs
1 parent 8d62224 commit c5ec837

16 files changed

+157
-75
lines changed

objectivec/objc.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ void ObjCProcessor::LoadCategories(ObjCReader* reader, Ref<Section> classPtrSect
592592
}
593593
if (categoryBaseClassName.empty())
594594
{
595-
m_logger->LogError(
595+
m_logger->LogWarn(
596596
"Failed to determine base classname for category at 0x%llx. Using base address as stand-in classname",
597597
catLocation);
598598
categoryBaseClassName = std::to_string(catLocation);
@@ -604,7 +604,7 @@ void ObjCProcessor::LoadCategories(ObjCReader* reader, Ref<Section> classPtrSect
604604
}
605605
catch (...)
606606
{
607-
m_logger->LogError(
607+
m_logger->LogWarn(
608608
"Failed to read category name for category at 0x%llx. Using base address as stand-in category name",
609609
catLocation);
610610
categoryAdditionsName = std::to_string(catLocation);

view/sharedcache/api/sharedcache.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ using namespace SharedCacheAPI;
99

1010
BNSharedCacheImage ImageToApi(CacheImage image)
1111
{
12-
BNSharedCacheImage apiImage;
12+
BNSharedCacheImage apiImage {};
1313
apiImage.name = BNAllocString(image.name.c_str());
1414
apiImage.headerAddress = image.headerAddress;
1515
apiImage.regionStartCount = image.regionStarts.size();
16-
// TODO: If we alloc then core cannot delete
1716
uint64_t *regionStarts = new uint64_t[image.regionStarts.size()];
1817
for (size_t i = 0; i < image.regionStarts.size(); i++)
1918
regionStarts[i] = image.regionStarts[i];
20-
apiImage.regionStarts = regionStarts;
19+
apiImage.regionStarts = BNSharedCacheAllocRegionList(regionStarts, image.regionStarts.size());
20+
delete[] regionStarts;
2121
return apiImage;
2222
}
2323

2424
CacheImage ImageFromApi(BNSharedCacheImage image)
2525
{
26-
CacheImage apiImage;
26+
CacheImage apiImage {};
2727
apiImage.name = image.name;
2828
apiImage.headerAddress = image.headerAddress;
2929
apiImage.regionStarts.reserve(image.regionStartCount);
@@ -34,7 +34,7 @@ CacheImage ImageFromApi(BNSharedCacheImage image)
3434

3535
BNSharedCacheRegion RegionToApi(const CacheRegion &region)
3636
{
37-
BNSharedCacheRegion apiRegion;
37+
BNSharedCacheRegion apiRegion {};
3838
apiRegion.vmAddress = region.start;
3939
apiRegion.name = BNAllocString(region.name.c_str());
4040
apiRegion.size = region.size;
@@ -47,7 +47,7 @@ BNSharedCacheRegion RegionToApi(const CacheRegion &region)
4747

4848
CacheRegion RegionFromApi(BNSharedCacheRegion apiRegion)
4949
{
50-
CacheRegion region;
50+
CacheRegion region {};
5151
region.start = apiRegion.vmAddress;
5252
region.name = apiRegion.name;
5353
region.size = apiRegion.size;
@@ -58,7 +58,7 @@ CacheRegion RegionFromApi(BNSharedCacheRegion apiRegion)
5858

5959
BNSharedCacheMappingInfo MappingToApi(const CacheMappingInfo &mapping)
6060
{
61-
BNSharedCacheMappingInfo apiMapping;
61+
BNSharedCacheMappingInfo apiMapping {};
6262
apiMapping.vmAddress = mapping.vmAddress;
6363
apiMapping.size = mapping.size;
6464
apiMapping.fileOffset = mapping.fileOffset;
@@ -67,7 +67,7 @@ BNSharedCacheMappingInfo MappingToApi(const CacheMappingInfo &mapping)
6767

6868
CacheMappingInfo MappingFromApi(BNSharedCacheMappingInfo apiMapping)
6969
{
70-
CacheMappingInfo mapping;
70+
CacheMappingInfo mapping {};
7171
mapping.vmAddress = apiMapping.vmAddress;
7272
mapping.size = apiMapping.size;
7373
mapping.fileOffset = apiMapping.fileOffset;
@@ -76,7 +76,7 @@ CacheMappingInfo MappingFromApi(BNSharedCacheMappingInfo apiMapping)
7676

7777
BNSharedCacheEntry EntryToApi(const CacheEntry &entry)
7878
{
79-
BNSharedCacheEntry apiEntry;
79+
BNSharedCacheEntry apiEntry {};
8080
apiEntry.path = BNAllocString(entry.path.c_str());
8181
apiEntry.entryType = entry.entryType;
8282
const auto &mappings = entry.mappings;
@@ -90,7 +90,7 @@ BNSharedCacheEntry EntryToApi(const CacheEntry &entry)
9090

9191
CacheEntry EntryFromApi(BNSharedCacheEntry apiEntry)
9292
{
93-
CacheEntry entry;
93+
CacheEntry entry {};
9494
entry.path = apiEntry.path;
9595
entry.entryType = apiEntry.entryType;
9696
entry.mappings.reserve(apiEntry.mappingCount);
@@ -125,6 +125,21 @@ std::string SharedCacheAPI::GetRegionTypeAsString(const BNSharedCacheRegionType
125125
}
126126
}
127127

128+
std::string SharedCacheAPI::GetSymbolTypeAsString(const BNSymbolType &type)
129+
{
130+
// NOTE: We currently only use the function and data symbol for cache symbols.
131+
// update this if that changes.
132+
switch (type)
133+
{
134+
case FunctionSymbol:
135+
return "Function";
136+
case DataSymbol:
137+
return "Data";
138+
default:
139+
return "Unknown";
140+
}
141+
}
142+
128143
SharedCacheController::SharedCacheController(BNSharedCacheController *controller)
129144
{
130145
m_object = controller;

view/sharedcache/api/sharedcacheapi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ namespace SharedCacheAPI {
289289
std::string name;
290290
};
291291

292+
std::string GetSymbolTypeAsString(const BNSymbolType& type);
293+
292294
class SharedCacheController : public DSCCoreRefCountObject<BNSharedCacheController, BNNewSharedCacheControllerReference, BNFreeSharedCacheControllerReference> {
293295
public:
294296
explicit SharedCacheController(BNSharedCacheController* controller);

view/sharedcache/core/MachOProcessor.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,7 @@ void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header)
3535
auto targetPlatform = m_view->GetDefaultPlatform();
3636
auto functions = header.ReadFunctionTable(*m_vm);
3737
for (const auto& func : functions)
38-
{
39-
// TODO: Check to make sure the func exists in a loaded region?
40-
// TODO: ^ this check existed prior so we should add it back.
41-
m_view->AddFunctionForAnalysis(targetPlatform, func);
42-
}
38+
m_view->AddFunctionForAnalysis(targetPlatform, func, true);
4339
}
4440

4541
auto typeLib = m_view->GetTypeLibrary(header.installName);
@@ -52,10 +48,9 @@ void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header)
5248
// Mach-O View symtab processing with
5349
// a ton of stuff cut out so it can work
5450
// NOTE: This table is read relative to the link edit segment file base.
55-
// TODO: Remove this and use the m_symbols in the cache?
5651
const auto symbols = header.ReadSymbolTable(*m_view, *m_vm);
5752
for (const auto& sym : symbols)
58-
ApplySymbol(m_view, typeLib, sym.ToBNSymbol());
53+
ApplySymbol(m_view, typeLib, sym.ToBNSymbol(*m_view));
5954
}
6055

6156
// Apply symbols from export trie.
@@ -65,7 +60,7 @@ void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header)
6560
// TODO: Remove this and use the m_symbols in the cache?
6661
const auto exportSymbols = header.ReadExportSymbolTrie(*m_vm);
6762
for (const auto& sym : exportSymbols)
68-
ApplySymbol(m_view, typeLib, sym.ToBNSymbol());
63+
ApplySymbol(m_view, typeLib, sym.ToBNSymbol(*m_view));
6964
}
7065
m_view->EndBulkModifySymbols();
7166
}

view/sharedcache/core/SharedCache.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ using namespace BinaryNinja;
1111
// The next id to use when calling Cache::AddEntry
1212
static CacheEntryId nextId = 1;
1313

14-
Ref<Symbol> CacheSymbol::ToBNSymbol() const
14+
Ref<Symbol> CacheSymbol::ToBNSymbol(BinaryView& view) const
1515
{
1616
QualifiedName qname;
17+
Ref<Type> outType;
1718
std::string shortName = name;
18-
if (DemangleLLVM(name, qname, true))
19+
if (DemangleGeneric(view.GetDefaultArchitecture(), name, outType, qname, &view, true))
1920
shortName = qname.GetString();
2021
return new Symbol(type, shortName, shortName, name, address, nullptr);
2122
}
@@ -458,7 +459,7 @@ std::optional<CacheImage> SharedCache::GetImageContaining(const uint64_t address
458459
{
459460
// TODO: What if we are using this on a shared region? Return a list of images?
460461
auto region = GetRegionContaining(address);
461-
if (region.has_value())
462+
if (region.has_value() && region->imageStart.has_value())
462463
return GetImageAt(*region->imageStart);
463464
return std::nullopt;
464465
}

view/sharedcache/core/SharedCache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct CacheSymbol
3232
CacheSymbol& operator=(CacheSymbol&& other) noexcept = default;
3333

3434
// NOTE: you should really only call this when adding the symbol to the view.
35-
BinaryNinja::Ref<BinaryNinja::Symbol> ToBNSymbol() const;
35+
BinaryNinja::Ref<BinaryNinja::Symbol> ToBNSymbol(BinaryNinja::BinaryView& view) const;
3636
};
3737

3838
enum class CacheRegionType

view/sharedcache/core/SharedCacheController.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ SharedCacheController::SharedCacheController(SharedCache cache, Ref<Logger> logg
6060
m_logger = std::move(logger);
6161
m_loadedRegions = {};
6262
m_loadedImages = {};
63+
m_processObjC = true;
64+
m_processCFStrings = true;
65+
m_regionFilter = std::regex(".*LINKEDIT.*");
6366
}
6467

6568
DSCRef<SharedCacheController> SharedCacheController::Initialize(BinaryView& view, SharedCache cache)
@@ -111,16 +114,16 @@ bool SharedCacheController::ApplyRegionAtAddress(BinaryView& view, const uint64_
111114

112115
bool SharedCacheController::ApplyRegion(BinaryView& view, const CacheRegion& region)
113116
{
114-
// TODO: Check m_loadedRegions? This seems redundant...
117+
std::unique_lock<std::shared_mutex> lock(m_loadMutex);
115118
// Loads the given region into the BinaryView and marks it as loaded.
116-
// First check to make sure there isn't already a segment at the address in the view.
117-
if (view.GetSegmentAt(region.start))
119+
// First check to make sure we haven't already loaded the region.
120+
if (m_loadedRegions.find(region.start) != m_loadedRegions.end())
118121
return false;
119122

120123
// Skip filtered regions, this defaults to just LINKEDIT regions.
121124
if (std::regex_match(region.name, m_regionFilter))
122125
{
123-
LogDebug("Skipping filtered region at %llx", region.start);
126+
m_logger->LogDebug("Skipping filtered region at %llx", region.start);
124127
return false;
125128
}
126129

@@ -161,24 +164,29 @@ bool SharedCacheController::ApplyRegion(BinaryView& view, const CacheRegion& reg
161164
return true;
162165
}
163166

164-
bool SharedCacheController::IsRegionLoaded(const CacheRegion& region) const
167+
bool SharedCacheController::IsRegionLoaded(const CacheRegion& region)
165168
{
169+
std::shared_lock<std::shared_mutex> lock(m_loadMutex);
166170
return std::any_of(m_loadedRegions.begin(), m_loadedRegions.end(), [&](const auto& loadedRegion) {
167171
return loadedRegion == region.start;
168172
});
169173
}
170174

171175
bool SharedCacheController::ApplyImage(BinaryView& view, const CacheImage& image)
172176
{
173-
// TODO: Check m_loadedImages? This seems redundant...
174177
// Load all regions of an image and mark the image as loaded.
178+
// NOTE: The regions lock m_loadMutex themselves, so we do not hold it up here.
175179
bool loadedRegion = false;
176180
for (const auto& regionStart : image.regionStarts)
177181
if (ApplyRegionAtAddress(view, regionStart))
178182
loadedRegion = true;
179183

184+
// The ApplyRegionAtAddress no longer holds the lock, we can take it now.
185+
std::unique_lock<std::shared_mutex> lock(m_loadMutex);
180186
// If there was no loaded regions than we just want to forgo loading the image.
181-
if (!loadedRegion)
187+
// We also skip if we already loaded the image itself. We do this after loading regions
188+
// as we regions have their own check.
189+
if (!loadedRegion || m_loadedImages.find(image.headerAddress) != m_loadedImages.end())
182190
return false;
183191

184192
if (image.header)
@@ -187,17 +195,16 @@ bool SharedCacheController::ApplyImage(BinaryView& view, const CacheImage& image
187195
auto machoProcessor = SharedCacheMachOProcessor(&view, m_cache.GetVirtualMemory());
188196
machoProcessor.ApplyHeader(*image.header);
189197

190-
// TODO: Make this optional.
191-
// Load objective-c information.
192-
auto objcProcessor = DSCObjC::SharedCacheObjCProcessor(&view, false);
193198
// TODO: Passing in an image name here is weird considering this is shared with the MACHO view.
194199
// TODO: We should abstract out the "image" into an objc image type that represents what is required, which ig is the name?
200+
// Load objective-c information.
201+
auto objcProcessor = DSCObjC::SharedCacheObjCProcessor(&view, false);
195202
try
196203
{
197204
if (m_processObjC)
198205
objcProcessor.ProcessObjCData(image.GetName());
199-
if (m_processObjC)
200-
objcProcessor.ProcessCFStrings(image.GetName());
206+
if (m_processCFStrings)
207+
objcProcessor.ProcessCFStrings(image.GetName());
201208
}
202209
catch (std::exception& e)
203210
{
@@ -216,8 +223,9 @@ bool SharedCacheController::ApplyImage(BinaryView& view, const CacheImage& image
216223
return true;
217224
}
218225

219-
bool SharedCacheController::IsImageLoaded(const CacheImage& image) const
226+
bool SharedCacheController::IsImageLoaded(const CacheImage& image)
220227
{
228+
std::shared_lock<std::shared_mutex> lock(m_loadMutex);
221229
return std::any_of(m_loadedImages.begin(), m_loadedImages.end(), [&](const auto& loadedImage) {
222230
return loadedImage == image.headerAddress;
223231
});

view/sharedcache/core/SharedCacheController.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ namespace BinaryNinja::DSC {
1818
{
1919
IMPLEMENT_DSC_API_OBJECT(BNSharedCacheController);
2020
Ref<Logger> m_logger;
21-
2221
SharedCache m_cache;
22+
23+
// Locks on load attempts (region or image).
24+
std::shared_mutex m_loadMutex;
25+
2326
// Store the open images.
2427
// Things other than the cache here will be serialized.
2528
std::unordered_set<uint64_t> m_loadedRegions;
@@ -49,13 +52,13 @@ namespace BinaryNinja::DSC {
4952

5053
bool ApplyRegion(BinaryView& view, const CacheRegion& region);
5154

52-
bool IsRegionLoaded(const CacheRegion& region) const;
55+
bool IsRegionLoaded(const CacheRegion& region);
5356

5457
// Loads the relevant image info into the view. This does not update analysis so if you
5558
// call this make sure at some point you update analysis and likely with linear sweep.
5659
bool ApplyImage(BinaryView& view, const CacheImage& image);
5760

58-
bool IsImageLoaded(const CacheImage& image) const;
61+
bool IsImageLoaded(const CacheImage& image);
5962

6063
// Get the metadata for saving the state of the shared cache.
6164
Ref<Metadata> GetMetadata() const;

view/sharedcache/core/SharedCacheView.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Ref<Settings> SharedCacheViewType::GetLoadSettingsForData(BinaryView* data)
8282
R"({
8383
"title" : "Region Regex Filter",
8484
"type" : "string",
85-
"default" : "LINKEDIT",
85+
"default" : ".*LINKEDIT.*",
8686
"description" : "Regex filter for region names to skip loading, by default this filters out the link edit region which is not necessary to be applied to the view."
8787
})");
8888

@@ -784,19 +784,22 @@ bool SharedCacheView::Init()
784784
// After this we should have all the mappings available as well.
785785
CacheProcessor cacheProcessor = CacheProcessor(this);
786786
auto startTime = std::chrono::high_resolution_clock::now();
787-
if (!cacheProcessor.ProcessCache(sharedCache))
787+
bool result = cacheProcessor.ProcessCache(sharedCache);
788+
auto endTime = std::chrono::high_resolution_clock::now();
789+
std::chrono::duration<double> elapsed = endTime - startTime;
790+
logger->LogInfo("Processing %zu entries took %.3f seconds", sharedCache.GetEntries().size(), elapsed.count());
791+
792+
if (!result)
788793
{
789-
// Oh no, we failed to process the cache, this likely means the primary on-disk file was not able to be
790-
// found.
791794
// TODO: Prompt the user to select the primary cache file? We can still recover from here.
795+
// Oh no, we failed to process the cache, this likely means the primary on-disk file was not able to be found.
792796
logger->LogError("Failed to process cache, likely missing cache files.");
793797
// NOTE: An interaction handler headlessly could select yes to this, however for the purposes of this we will just let them continue by defualt.
794798
if (IsUIEnabled() && ShowMessageBox("Continue opening", "This shared cache file was unable to be processed, would you like to open without shared cache information?", YesNoButtonSet, QuestionIcon) != YesButton)
795799
return false;
800+
// Skip all the other shared cache stuff.
801+
return true;
796802
}
797-
auto endTime = std::chrono::high_resolution_clock::now();
798-
std::chrono::duration<double> elapsed = endTime - startTime;
799-
logger->LogInfo("Processing %zu entries took %.3f seconds", sharedCache.GetEntries().size(), elapsed.count());
800803
}
801804

802805
{

view/sharedcache/core/Utility.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void ApplySymbol(Ref<BinaryView> view, Ref<TypeLibrary> typeLib, Ref<Symbol> sym
7474
if (symbol->GetType() == FunctionSymbol)
7575
{
7676
Ref<Platform> targetPlatform = view->GetDefaultPlatform();
77-
func = view->AddFunctionForAnalysis(targetPlatform, symbolAddress);
77+
func = view->AddFunctionForAnalysis(targetPlatform, symbolAddress, true);
7878
}
7979

8080
if (typeLib)

0 commit comments

Comments
 (0)