From 583ec69d80a1cb981111bf7a900f4afb35044138 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sat, 4 May 2024 20:24:52 +0200 Subject: [PATCH 01/26] Add initial implementation for labels --- Bit Slicer.xcodeproj/project.pbxproj | 16 +++ Bit Slicer/Base.lproj/Edit Size Dialog.xib | 23 ++-- Bit Slicer/Base.lproj/MainMenu.xib | 6 + .../Base.lproj/Search Document Window.xib | 6 + Bit Slicer/Edit Label Dialog.xib | 93 ++++++++++++++ Bit Slicer/ZGCalculator.h | 5 +- Bit Slicer/ZGCalculator.m | 78 ++++++++++-- Bit Slicer/ZGDocumentLabelController.h | 49 ++++++++ Bit Slicer/ZGDocumentLabelController.m | 64 ++++++++++ Bit Slicer/ZGDocumentTableController.m | 4 +- Bit Slicer/ZGDocumentWindowController.h | 2 + Bit Slicer/ZGDocumentWindowController.m | 27 +++++ Bit Slicer/ZGEditLabelWindowController.h | 48 ++++++++ Bit Slicer/ZGEditLabelWindowController.m | 114 ++++++++++++++++++ Bit Slicer/ZGPyDebugger.h | 4 +- Bit Slicer/ZGPyDebugger.m | 92 +++++++++++++- Bit Slicer/ZGScriptManager.m | 2 +- Bit Slicer/ZGVariable.h | 1 + Bit Slicer/ZGVariable.m | 15 +++ Bit Slicer/ZGVariableController.h | 1 + Bit Slicer/ZGVariableController.m | 84 ++++++++++--- 21 files changed, 696 insertions(+), 38 deletions(-) create mode 100644 Bit Slicer/Edit Label Dialog.xib create mode 100644 Bit Slicer/ZGDocumentLabelController.h create mode 100644 Bit Slicer/ZGDocumentLabelController.m create mode 100644 Bit Slicer/ZGEditLabelWindowController.h create mode 100644 Bit Slicer/ZGEditLabelWindowController.m diff --git a/Bit Slicer.xcodeproj/project.pbxproj b/Bit Slicer.xcodeproj/project.pbxproj index 555fead3b..2a61c8a13 100644 --- a/Bit Slicer.xcodeproj/project.pbxproj +++ b/Bit Slicer.xcodeproj/project.pbxproj @@ -15,6 +15,9 @@ 7208450624E084F400F3D449 /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7208450524E084F400F3D449 /* Python.framework */; }; 7208450724E0851000F3D449 /* Python.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 7208450524E084F400F3D449 /* Python.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 720C192C271B4F9700740C8E /* ZGSearchProtectionMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */; }; + 72130FC42BE67E2000691AED /* ZGDocumentLabelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 72130FC32BE67E2000691AED /* ZGDocumentLabelController.m */; }; + 72130FC82BE6836A00691AED /* ZGEditLabelWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */; }; + 72130FC92BE6836A00691AED /* Edit Label Dialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */; }; 721594FE24DF36360027F600 /* HexFiend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 721594FD24DF36360027F600 /* HexFiend.framework */; }; 7215950024DF36520027F600 /* HexFiend.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 721594FD24DF36360027F600 /* HexFiend.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 721B3C4D2AED913200F85660 /* ZGSearchProtectionMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */; }; @@ -319,6 +322,11 @@ 720C1929271B46B600740C8E /* ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = ""; }; 720C192A271B4F9700740C8E /* ZGSearchProtectionMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGSearchProtectionMode.h; path = "Bit Slicer/ZGSearchProtectionMode.h"; sourceTree = ""; }; 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGSearchProtectionMode.m; path = "Bit Slicer/ZGSearchProtectionMode.m"; sourceTree = ""; }; + 72130FC22BE67E2000691AED /* ZGDocumentLabelController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGDocumentLabelController.h; path = "Bit Slicer/ZGDocumentLabelController.h"; sourceTree = ""; }; + 72130FC32BE67E2000691AED /* ZGDocumentLabelController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGDocumentLabelController.m; path = "Bit Slicer/ZGDocumentLabelController.m"; sourceTree = ""; }; + 72130FC52BE6836A00691AED /* ZGEditLabelWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGEditLabelWindowController.h; path = "Bit Slicer/ZGEditLabelWindowController.h"; sourceTree = ""; }; + 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGEditLabelWindowController.m; path = "Bit Slicer/ZGEditLabelWindowController.m"; sourceTree = ""; }; + 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "Edit Label Dialog.xib"; path = "Bit Slicer/Edit Label Dialog.xib"; sourceTree = ""; }; 721594FD24DF36360027F600 /* HexFiend.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HexFiend.framework; path = deps/HexFiend/HexFiend.framework; sourceTree = ""; }; 721594FF24DF36460027F600 /* HFLineCountingView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HFLineCountingView.h; path = deps/HexFiend/HFLineCountingView.h; sourceTree = ""; }; 722CAA5519AD4AED009C6AAE /* hotkey.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = hotkey.png; path = "Bit Slicer/preficons/hotkey.png"; sourceTree = ""; }; @@ -993,6 +1001,7 @@ 726CA2B219606DA000A6AD40 /* Logs Window.xib */, 726CA2CA19606E1D00A6AD40 /* Edit Value Dialog.xib */, 726CA2CD19606E2200A6AD40 /* Edit Address Dialog.xib */, + 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */, 726CA2D019606E2600A6AD40 /* Edit Size Dialog.xib */, 726CA2D319606E2900A6AD40 /* Edit Description Dialog.xib */, 726CA2D619606E3100A6AD40 /* Search Options.xib */, @@ -1056,6 +1065,8 @@ 770FABAF18490DB400C176B7 /* ZGEditAddressWindowController.m */, 770FABB41849160200C176B7 /* ZGEditSizeWindowController.h */, 770FABB51849160200C176B7 /* ZGEditSizeWindowController.m */, + 72130FC52BE6836A00691AED /* ZGEditLabelWindowController.h */, + 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */, 77FFC14918711D2700122357 /* ZGEditDescriptionWindowController.h */, 77FFC14A18711D2700122357 /* ZGEditDescriptionWindowController.m */, ); @@ -1330,6 +1341,8 @@ 77F115F917D2EE6F009E002A /* ZGDocumentSearchController.m */, 77F115FB17D2EE7E009E002A /* ZGDocumentTableController.h */, 77F115FC17D2EE7E009E002A /* ZGDocumentTableController.m */, + 72130FC22BE67E2000691AED /* ZGDocumentLabelController.h */, + 72130FC32BE67E2000691AED /* ZGDocumentLabelController.m */, 77FFC104186BDA3600122357 /* ZGWatchVariableWindowController.h */, 77FFC105186BDA3600122357 /* ZGWatchVariableWindowController.m */, 7739728017D26A1600B958EE /* Scripting */, @@ -1580,6 +1593,7 @@ 724A9F2819A1657500E72C9D /* [Code] Script Preferences.strings in Resources */, 726CA2CB19606E2200A6AD40 /* Edit Address Dialog.xib in Resources */, 724A9F4E19A8EDD700E72C9D /* [Code] Logger Window.stringsdict in Resources */, + 72130FC92BE6836A00691AED /* Edit Label Dialog.xib in Resources */, 726CA2D719606E3800A6AD40 /* Watch Variable Dialog.xib in Resources */, 722CAA5919AD4AED009C6AAE /* hotkey.png in Resources */, 77F115AE17D2EAE4009E002A /* bitslicerdocicon.iconset in Resources */, @@ -1705,6 +1719,7 @@ 773972F217D2E6AE00B958EE /* mach_excUser.c in Sources */, 77FFC107186BDA3600122357 /* ZGWatchVariableWindowController.m in Sources */, 77F115A817D2E87E009E002A /* VDKQueue.m in Sources */, + 72130FC42BE67E2000691AED /* ZGDocumentLabelController.m in Sources */, 77F115CD17D2ED64009E002A /* ZGMemoryViewerController.m in Sources */, 77F115D017D2ED74009E002A /* ZGVerticalScrollerRepresenter.m in Sources */, 77282123189E769B0044E4BC /* ZGStoredData.m in Sources */, @@ -1743,6 +1758,7 @@ 722EE7871B1940EC00934EF3 /* ZGDeliverUserNotifications.m in Sources */, 77F1160C17D2EECA009E002A /* ZGPyScript.m in Sources */, 777DA25218CE97BE0092DEC9 /* ZGAppTerminationState.m in Sources */, + 72130FC82BE6836A00691AED /* ZGEditLabelWindowController.m in Sources */, 77F1160F17D2EED6009E002A /* ZGSearchData.m in Sources */, 72E07FDB2AA563AF00BBEED1 /* LEB128Type.m in Sources */, 77282120189B854D0044E4BC /* ZGFunctionTypes.m in Sources */, diff --git a/Bit Slicer/Base.lproj/Edit Size Dialog.xib b/Bit Slicer/Base.lproj/Edit Size Dialog.xib index f943b09ef..d7e069529 100644 --- a/Bit Slicer/Base.lproj/Edit Size Dialog.xib +++ b/Bit Slicer/Base.lproj/Edit Size Dialog.xib @@ -1,8 +1,9 @@ - - + + - + + @@ -13,28 +14,28 @@ - + - + - + - + - + - + @@ -42,7 +43,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Bit Slicer/ZGCalculator.h b/Bit Slicer/ZGCalculator.h index 45564c668..9b25867bc 100644 --- a/Bit Slicer/ZGCalculator.h +++ b/Bit Slicer/ZGCalculator.h @@ -34,9 +34,11 @@ #import "ZGVariable.h" @class ZGProcess; +@class ZGDocumentLabelController; #define ZGBaseAddressFunction @"base" #define ZGFindSymbolFunction @"symbol" +#define ZGFindLabelFunction @"label" NS_ASSUME_NONNULL_BEGIN @@ -45,6 +47,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) BOOL usesDynamicPointerAddress; @property (nonatomic, readonly) BOOL usesDynamicBaseAddress; @property (nonatomic, readonly) BOOL usesDynamicSymbolAddress; +@property (nonatomic, readonly) BOOL usesDynamicLabelAddress; - (NSUInteger)numberOfDynamicPointersInAddress; @@ -62,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN // Can evaluate [address] + [address2] + offset, [address + [address2 - [address3]]] + offset, etc... // And also has a base() function that takes in a string, and returns the first address to a region such that the passed string partially matches the end of the corresponding region's mapped path -+ (nullable NSString *)evaluateExpression:(NSString *)expression process:(ZGProcess *)process failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; ++ (nullable NSString *)evaluateExpression:(NSString *)expression labelController:(nullable ZGDocumentLabelController *)labelController process:(ZGProcess *)process failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; + (nullable NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess *)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(nullable BOOL *)didSymbolicate error:(NSError **)error; @end diff --git a/Bit Slicer/ZGCalculator.m b/Bit Slicer/ZGCalculator.m index 9e83e5047..6bb6383ac 100644 --- a/Bit Slicer/ZGCalculator.m +++ b/Bit Slicer/ZGCalculator.m @@ -37,6 +37,7 @@ #import "ZGMachBinaryInfo.h" #import "ZGRegion.h" #import "ZGProcess.h" +#import "ZGDocumentLabelController.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincomplete-umbrella" #import @@ -54,6 +55,7 @@ #define ZGSymbolicationRequiresExactMatch @"ZGSymbolicationRequiresExactMatch" #define ZGDidFindSymbol @"ZGDidFindSymbol" #define ZGLastSearchInfoVariable @"ZGLastSearchInfoVariable" +#define ZGLabelControllerVariable @"ZGLabelControllerVariable" @implementation ZGVariable (ZGCalculatorAdditions) @@ -100,6 +102,11 @@ - (BOOL)usesDynamicSymbolAddress return _addressFormula != nil && [_addressFormula rangeOfString:[ZGFindSymbolFunction stringByAppendingString:@"("]].location != NSNotFound; } +- (BOOL)usesDynamicLabelAddress +{ + return _addressFormula != nil && [_addressFormula rangeOfString:[ZGFindLabelFunction stringByAppendingString:@"("]].location != NSNotFound; +} + @end @implementation ZGCalculator @@ -270,6 +277,57 @@ + (DDMathFunction)registerFindSymbolFunctionWithEvaluator:(DDMathEvaluator *)eva return findSymbolFunction; } ++ (DDMathFunction)registerFindLabelFunctionWithEvaluator:(DDMathEvaluator *)evaluator +{ + DDMathFunction findLabelFunction = ^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator * __unused eval, NSError *__autoreleasing *error) { + ZGDocumentLabelController *labelController = [vars objectForKey:ZGLabelControllerVariable]; + + __block NSNumber *labelAddressNumber = @(0); + + if (args.count == 0 || args.count > 1) + { + if (error != NULL) + { + *error = [NSError errorWithDomain:DDMathParserErrorDomain code:DDErrorCodeInvalidNumberOfArguments userInfo:@{NSLocalizedDescriptionKey:ZGFindLabelFunction @" expects 1 argument"}]; + } + } + else if (labelController == nil) + { + if (error != NULL) + { + *error = [NSError errorWithDomain:DDMathParserErrorDomain code:DDErrorCodeUnresolvedVariable userInfo:@{NSLocalizedDescriptionKey:ZGFindLabelFunction @" expects a labels variable"}]; + } + } + else + { + DDExpression *labelExpression = [args objectAtIndex:0]; + + if (labelExpression.expressionType != DDExpressionTypeVariable) + { + if (error != NULL) + { + *error = [NSError errorWithDomain:DDMathParserErrorDomain code:DDErrorCodeUnresolvedVariable userInfo:@{NSLocalizedDescriptionKey:ZGFindLabelFunction @" expects a string variable"}]; + } + } + else + { + ZGVariable *variable = [labelController variableForLabel:labelExpression.variable]; + + if (variable != nil) + { + labelAddressNumber = @(variable.address); + } + } + } + + return [DDExpression numberExpressionWithNumber:labelAddressNumber]; + }; + + [evaluator registerFunction:findLabelFunction forName:ZGFindLabelFunction]; + + return findLabelFunction; +} + + (void)registerFunctionResolverWithEvaluator:(DDMathEvaluator *)evaluator findSymbolFunction:(DDMathFunction)findSymbolFunction { evaluator.functionResolver = (DDFunctionResolver)^(NSString *name) { @@ -297,6 +355,7 @@ + (void)initialize [self registerCalculatePointerFunctionWithEvaluator:evaluator]; [self registerBaseAddressFunctionWithEvaluator:evaluator]; DDMathFunction findSymbolFunction = [self registerFindSymbolFunctionWithEvaluator:evaluator]; + [self registerFindLabelFunctionWithEvaluator:evaluator]; [self registerFunctionResolverWithEvaluator:evaluator findSymbolFunction:findSymbolFunction]; }); } @@ -712,7 +771,7 @@ + (BOOL)_extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression else { // Found base() +- offset expression which we need to evaluate - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; NSError *evaluateError = nil; NSNumber *evaluatedBaseAddressNumber = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:expression withSubstitutions:substitutions error:&evaluateError]; @@ -844,7 +903,7 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt return [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; } -+ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress ++ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process labelController:(ZGDocumentLabelController *)labelController failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress { NSMutableDictionary *substitutions = [NSMutableDictionary dictionaryWithDictionary:@{ZGProcessVariable : process, ZGSymbolicatesVariable : @(symbolicates), ZGSymbolicationRequiresExactMatch : @(symbolicationRequiresExactMatch), ZGLastSearchInfoVariable : @(currentAddress), ZGDidFindSymbol : @(NO)}]; @@ -853,14 +912,19 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt [substitutions setObject:failedImages forKey:ZGFailedImagesVariable]; } + if (labelController != nil) + { + [substitutions setObject:labelController forKey:ZGLabelControllerVariable]; + } + return substitutions; } -+ (NSString *)evaluateExpression:(NSString *)expression process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error { NSString *newExpression = [self expressionBySubstitutingCalculatePointerFunctionInExpression:expression]; - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:labelController failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; NSString *evaluatedExpression = [self evaluateExpression:newExpression substitutions:substitutions error:error]; if (foundSymbol != NULL) @@ -873,12 +937,12 @@ + (NSString *)evaluateExpression:(NSString *)expression process:(ZGProcess * __u + (NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess * __unsafe_unretained)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(BOOL *)didSymbolicate error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression process:process failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; + return [self evaluateExpression:expression labelController:nil process:process failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; } -+ (NSString *)evaluateExpression:(NSString *)expression process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression process:process failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; + return [self evaluateExpression:expression labelController:labelController process:process failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; } @end diff --git a/Bit Slicer/ZGDocumentLabelController.h b/Bit Slicer/ZGDocumentLabelController.h new file mode 100644 index 000000000..859ff0dd6 --- /dev/null +++ b/Bit Slicer/ZGDocumentLabelController.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 Mayur Pawashe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the project's author nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "ZGMemoryTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@class ZGDocumentData; +@class ZGVariable; + +@interface ZGDocumentLabelController : NSObject + +- (instancetype)initWithDocumentData:(ZGDocumentData *)documentData; + +- (nullable ZGVariable *)variableForLabel:(NSString *)label; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Bit Slicer/ZGDocumentLabelController.m b/Bit Slicer/ZGDocumentLabelController.m new file mode 100644 index 000000000..12c38371b --- /dev/null +++ b/Bit Slicer/ZGDocumentLabelController.m @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Mayur Pawashe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the project's author nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "ZGDocumentLabelController.h" +#import "ZGDocumentData.h" +#import "ZGVariable.h" + +@implementation ZGDocumentLabelController +{ + ZGDocumentData *_documentData; +} + +- (instancetype)initWithDocumentData:(ZGDocumentData *)documentData +{ + self = [super init]; + if (self != nil) + { + _documentData = documentData; + } + return self; +} + +- (nullable ZGVariable *)variableForLabel:(NSString *)label +{ + for (ZGVariable *variable in _documentData.variables) + { + if ([variable.label isEqualToString:label]) + { + return variable; + } + } + return nil; +} + +@end diff --git a/Bit Slicer/ZGDocumentTableController.m b/Bit Slicer/ZGDocumentTableController.m index 55379080a..21c72ff95 100644 --- a/Bit Slicer/ZGDocumentTableController.m +++ b/Bit Slicer/ZGDocumentTableController.m @@ -207,6 +207,7 @@ - (BOOL)updateDynamicVariableAddress:(ZGVariable *)variable NSString *newAddressString = [ZGCalculator evaluateExpression:[NSMutableString stringWithString:variable.addressFormula] + labelController:windowController.labelController process:windowController.currentProcess failedImages:_failedExecutableImages error:&error]; @@ -218,7 +219,8 @@ - (BOOL)updateDynamicVariableAddress:(ZGVariable *)variable } // We don't have to evaluate it more than once if we're not doing any pointer calculations - if (error == nil && !variable.usesDynamicPointerAddress) + // and it's not using a label + if (error == nil && !variable.usesDynamicPointerAddress && !variable.usesDynamicLabelAddress) { variable.finishedEvaluatingDynamicAddress = YES; } diff --git a/Bit Slicer/ZGDocumentWindowController.h b/Bit Slicer/ZGDocumentWindowController.h index a60e87394..8ec5d9f35 100644 --- a/Bit Slicer/ZGDocumentWindowController.h +++ b/Bit Slicer/ZGDocumentWindowController.h @@ -55,6 +55,7 @@ @class ZGHotKeyCenter; @class ZGDocument; @class ZGAppTerminationState; +@class ZGDocumentLabelController; NS_ASSUME_NONNULL_BEGIN @@ -77,6 +78,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) ZGVariableController *variableController; @property (nonatomic, readonly) ZGDocumentSearchController *searchController; @property (nonatomic, readonly) ZGScriptManager *scriptManager; +@property (nonatomic, readonly) ZGDocumentLabelController *labelController; @property (nonatomic, readonly) ZGDocumentData *documentData; @property (nonatomic, readonly) ZGSearchData *searchData; diff --git a/Bit Slicer/ZGDocumentWindowController.m b/Bit Slicer/ZGDocumentWindowController.m index 9b0cdf481..31ad892b6 100644 --- a/Bit Slicer/ZGDocumentWindowController.m +++ b/Bit Slicer/ZGDocumentWindowController.m @@ -38,6 +38,7 @@ #import "ZGEditAddressWindowController.h" #import "ZGEditDescriptionWindowController.h" #import "ZGEditSizeWindowController.h" +#import "ZGEditLabelWindowController.h" #import "ZGScriptManager.h" #import "ZGProcessList.h" #import "ZGProcess.h" @@ -45,6 +46,7 @@ #import "ZGRunningProcess.h" #import "ZGPreferencesController.h" #import "ZGDocumentData.h" +#import "ZGDocumentLabelController.h" #import "ZGSearchData.h" #import "ZGSearchProgress.h" #import "ZGSearchResults.h" @@ -97,6 +99,7 @@ @implementation ZGDocumentWindowController ZGEditAddressWindowController * _Nullable _editAddressWindowController; ZGEditDescriptionWindowController * _Nullable _editDescriptionWindowController; ZGEditSizeWindowController * _Nullable _editSizeWindowController; + ZGEditLabelWindowController * _Nullable _editLabelWindowController; BOOL _loadedDocumentBefore; NSString * _Nullable _flagsLabelStringValue; @@ -306,6 +309,7 @@ - (void)windowDidLoad _variableController = [[ZGVariableController alloc] initWithWindowController:self]; _searchController = [[ZGDocumentSearchController alloc] initWithWindowController:self]; _scriptManager = [[ZGScriptManager alloc] initWithWindowController:self]; + _labelController = [[ZGDocumentLabelController alloc] initWithDocumentData:_documentData]; _searchValueTextField.target = self; _searchValueTextField.action = @selector(searchValue:); @@ -1392,6 +1396,19 @@ - (BOOL)validateUserInterfaceItem:(id )userInterfa return NO; } } + + else if (menuItem.action == @selector(requestEditingVariableLabel:)) + { + if ([_searchController canCancelTask] || [self selectedVariables].count < 1 || !self.currentProcess.valid) + { + return NO; + } + + if ([(ZGVariable *)[self selectedVariables][0] type] == ZGScript) + { + return NO; + } + } else if (menuItem.action == @selector(requestEditingVariablesSize:)) { @@ -1910,6 +1927,16 @@ - (IBAction)requestEditingVariablesSize:(id)__unused sender [_editSizeWindowController requestEditingSizesFromVariables:[self selectedVariables] attachedToWindow:ZGUnwrapNullableObject(self.window)]; } +- (IBAction)requestEditingVariableLabel:(id)sender +{ + if (_editLabelWindowController == nil) + { + _editLabelWindowController = [[ZGEditLabelWindowController alloc] initWithVariableController:_variableController]; + } + + [_editLabelWindowController requestEditingLabelsFromVariables:[self selectedVariables] attachedToWindow:ZGUnwrapNullableObject(self.window)]; +} + - (IBAction)relativizeVariablesAddress:(id)__unused sender { [_variableController relativizeVariables:[self selectedVariables]]; diff --git a/Bit Slicer/ZGEditLabelWindowController.h b/Bit Slicer/ZGEditLabelWindowController.h new file mode 100644 index 000000000..af0308de1 --- /dev/null +++ b/Bit Slicer/ZGEditLabelWindowController.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Mayur Pawashe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the project's author nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class ZGVariableController; +@class ZGVariable; + +@interface ZGEditLabelWindowController : NSWindowController + +- (instancetype)initWithVariableController:(ZGVariableController *)variableController; + +- (void)requestEditingLabelsFromVariables:(NSArray *)variables attachedToWindow:(NSWindow *)parentWindow; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m new file mode 100644 index 000000000..d1db60f4b --- /dev/null +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 Mayur Pawashe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the project's author nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "ZGEditLabelWindowController.h" +#import "ZGVariableController.h" +#import "ZGVariable.h" +#import "ZGNullability.h" + +@implementation ZGEditLabelWindowController +{ + ZGVariableController * _Nonnull _variableController; + NSArray * _Nullable _variables; + + IBOutlet NSTextField *_labelTextField; +} + +- (NSString *)windowNibName +{ + return @"Edit Label Dialog"; +} + +- (id)initWithVariableController:(ZGVariableController *)variableController +{ + self = [super init]; + if (self != nil) + { + _variableController = variableController; + } + return self; +} + +- (void)requestEditingLabelsFromVariables:(NSArray *)variables attachedToWindow:(NSWindow *)parentWindow +{ + NSWindow *window = ZGUnwrapNullableObject([self window]); // ensure window is loaded + + ZGVariable *firstVariable = [variables objectAtIndex:0]; + + _labelTextField.stringValue = firstVariable.label; + [_labelTextField selectText:nil]; + + _variables = variables; + + [parentWindow beginSheet:window completionHandler:^(NSModalResponse __unused returnCode) { + }]; +} + +- (IBAction)editVariablesLabels:(id)__unused sender +{ + NSWindow *window = ZGUnwrapNullableObject(self.window); + [NSApp endSheet:window]; + [window close]; + + NSMutableArray *requestedLabels = [[NSMutableArray alloc] init]; + + NSString *newLabel = _labelTextField.stringValue; + + NSUInteger variableIndex; + NSUInteger variableCount = _variables.count; + for (variableIndex = 0; variableIndex < variableCount; variableIndex++) + { + if (variableCount == 1) + { + [requestedLabels addObject:newLabel]; + } + else + { + [requestedLabels addObject:[NSString stringWithFormat:@"%@_%lu", newLabel, variableIndex]]; + } + } + + [_variableController editVariables:ZGUnwrapNullableObject(_variables) requestedLabels:requestedLabels]; + + _variables = nil; +} + +- (IBAction)cancelEditingVariablesLabels:(id)__unused sender +{ + NSWindow *window = ZGUnwrapNullableObject(self.window); + [NSApp endSheet:window]; + [window close]; + + _variables = nil; +} + +@end diff --git a/Bit Slicer/ZGPyDebugger.h b/Bit Slicer/ZGPyDebugger.h index 95d08ad83..bf7991518 100644 --- a/Bit Slicer/ZGPyDebugger.h +++ b/Bit Slicer/ZGPyDebugger.h @@ -43,6 +43,8 @@ @class ZGBreakPointController; @class ZGLoggerWindowController; @class ZGHotKeyCenter; +@class ZGDocumentLabelController; +@class ZGVariableController; NS_ASSUME_NONNULL_BEGIN @@ -50,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN + (nullable PyObject *)loadPythonClassInMainModule:(PyObject *)module; -- (nullable id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController; +- (nullable id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager labelController:(ZGDocumentLabelController *)labelController variableController:(ZGVariableController *)variableController breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController; - (void)cleanup; @property (nonatomic, weak, readonly) ZGScriptManager *scriptManager; diff --git a/Bit Slicer/ZGPyDebugger.m b/Bit Slicer/ZGPyDebugger.m index 4bb84b4fd..9a5f07355 100644 --- a/Bit Slicer/ZGPyDebugger.m +++ b/Bit Slicer/ZGPyDebugger.m @@ -56,6 +56,8 @@ #import "ZGHotKey.h" #import "ZGScriptPrompt.h" #import "ZGNullability.h" +#import "ZGDocumentLabelController.h" +#import "ZGVariableController.h" @class ZGPyDebugger; @@ -106,6 +108,8 @@ declareDebugPrototypeMethod(stepOut) declareDebugPrototypeMethod(backtrace) declareDebugPrototypeMethod(writeRegisters) +declareDebugPrototypeMethod(updateVariable) +declareDebugPrototypeMethod(variableAddress) #define declareDebugMethod2(name, argsType) {#name"", (PyCFunction)Debugger_##name, argsType, NULL}, #define declareDebugMethod(name) declareDebugMethod2(name, METH_VARARGS) @@ -142,6 +146,8 @@ declareDebugMethod(stepOut) declareDebugMethod(backtrace) declareDebugMethod(writeRegisters) + declareDebugMethod(updateVariable) + declareDebugMethod(variableAddress) {NULL, NULL, 0, NULL} }; @@ -195,6 +201,8 @@ @implementation ZGPyDebugger __weak ZGScriptManager * _Nullable _scriptManager; ZGBreakPointController * _Nonnull _breakPointController; ZGLoggerWindowController * _Nonnull _loggerWindowController; + ZGDocumentLabelController *_Nonnull _labelController; + ZGVariableController *_Nonnull _variableController; NSMutableDictionary * _Nonnull _cachedInstructionPointers; ZGHotKeyCenter * _Nonnull _hotKeyCenter; ZGProcess * _Nonnull _process; @@ -230,7 +238,7 @@ + (PyObject *)loadPythonClassInMainModule:(PyObject *)module return debuggerException; } -- (id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController +- (id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager labelController:(ZGDocumentLabelController *)labelController variableController:(ZGVariableController *)variableController breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController { self = [super init]; if (self != nil) @@ -245,6 +253,8 @@ - (id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInte _scriptManager = scriptManager; _scriptingInterpreter = scriptingInterpreter; _process = [[ZGProcess alloc] initWithProcess:process]; + _labelController = labelController; + _variableController = variableController; _breakPointController = breakPointController; _loggerWindowController = loggerWindowController; _hotKeyCenter = hotKeyCenter; @@ -1465,4 +1475,84 @@ static BOOL writeRegister(NSDictionary *registerOffsetsDi return success ? Py_BuildValue("") : NULL; } +static PyObject *Debugger_updateVariable(DebuggerClass *self, PyObject *args) +{ + PyObject *addressObject; + char *labelCString = NULL; + if (!PyArg_ParseTuple(args, "sO:updateVariable", &labelCString, &addressObject)) + { + return NULL; + } + + NSString *labelString = @(labelCString); + if (labelString == nil) + { + PyErr_SetString(PyExc_ValueError, "debug.updateVariable failed to interpret label"); + + return NULL; + } + + PyObject *addressStringObject = PyObject_Str(addressObject); + PyObject *unicodeObject = PyUnicode_AsUTF8String(addressStringObject); + char *addressCString = PyBytes_AsString(unicodeObject); + + NSString *addressString = @(addressCString); + + Py_XDECREF(unicodeObject); + Py_XDECREF(addressStringObject); + + if (addressString == nil) + { + PyErr_SetString(PyExc_ValueError, "debug.updateVariable failed to interpret address, which must be a number or a string"); + + return NULL; + } + + ZGDocumentLabelController *labelController = self->objcSelf->_labelController; + ZGVariableController *variableController = self->objcSelf->_variableController; + + dispatch_async(dispatch_get_main_queue(), ^{ + ZGVariable *variable = [labelController variableForLabel:labelString]; + + [variableController editVariable:variable addressFormula:addressString]; + }); + + return Py_BuildValue(""); +} + +static PyObject *Debugger_variableAddress(DebuggerClass *self, PyObject *args) +{ + char *labelCString = NULL; + if (!PyArg_ParseTuple(args, "s:variableAddress", &labelCString)) + { + return NULL; + } + + NSString *labelString = @(labelCString); + if (labelString == nil) + { + PyErr_SetString(PyExc_ValueError, "debug.variableAddress failed to interpret label"); + + return NULL; + } + + __block ZGMemoryAddress variableAddress; + __block BOOL foundAddress; + ZGDocumentLabelController *labelController = self->objcSelf->_labelController; + dispatch_sync(dispatch_get_main_queue(), ^{ + ZGVariable *variable = [labelController variableForLabel:labelString]; + foundAddress = (variable != nil); + variableAddress = variable.address; + }); + + if (!foundAddress) + { + PyErr_SetString(self->debuggerException, [[NSString stringWithFormat:@"debug.variableAddress failed because a variable with label %@ could not be found", labelString] UTF8String]); + + return NULL; + } + + return Py_BuildValue("K", variableAddress); +} + @end diff --git a/Bit Slicer/ZGScriptManager.m b/Bit Slicer/ZGScriptManager.m index c24511b07..ff604bb9d 100644 --- a/Bit Slicer/ZGScriptManager.m +++ b/Bit Slicer/ZGScriptManager.m @@ -585,7 +585,7 @@ - (void)runScriptForVariable:(ZGVariable *)variable ZGPyVirtualMemory *virtualMemoryInstance = [[ZGPyVirtualMemory alloc] initWithProcess:windowController.currentProcess virtualMemoryException:(PyObject * _Nonnull)self->_scriptingInterpreter.virtualMemoryException]; - ZGPyDebugger *debuggerInstance = [[ZGPyDebugger alloc] initWithProcess:windowController.currentProcess scriptingInterpreter:self->_scriptingInterpreter scriptManager:self breakPointController:windowController.breakPointController hotKeyCenter:windowController.hotKeyCenter loggerWindowController:windowController.loggerWindowController]; + ZGPyDebugger *debuggerInstance = [[ZGPyDebugger alloc] initWithProcess:windowController.currentProcess scriptingInterpreter:self->_scriptingInterpreter scriptManager:self labelController:windowController.labelController variableController:windowController.variableController breakPointController:windowController.breakPointController hotKeyCenter:windowController.hotKeyCenter loggerWindowController:windowController.loggerWindowController]; script.virtualMemoryInstance = virtualMemoryInstance; script.debuggerInstance = debuggerInstance; diff --git a/Bit Slicer/ZGVariable.h b/Bit Slicer/ZGVariable.h index 971cba549..e5dd7913d 100644 --- a/Bit Slicer/ZGVariable.h +++ b/Bit Slicer/ZGVariable.h @@ -80,6 +80,7 @@ extern NSString *ZGVariablePboardType; @property (copy, nonatomic) NSAttributedString *fullAttributedDescription; @property (nonatomic, readonly) NSString *shortDescription; @property (nonatomic, readonly) NSString *name; +@property (nonatomic, copy) NSString *label; - (id)initWithValue:(nullable const void *)value size:(ZGMemorySize)size address:(ZGMemoryAddress)address type:(ZGVariableType)type qualifier:(ZGVariableQualifier)qualifier pointerSize:(ZGMemorySize)pointerSize; diff --git a/Bit Slicer/ZGVariable.m b/Bit Slicer/ZGVariable.m index 30a04f4ce..33d2160b2 100644 --- a/Bit Slicer/ZGVariable.m +++ b/Bit Slicer/ZGVariable.m @@ -50,6 +50,7 @@ #define ZGNameKey @"ZGNameKey" // legacy #define ZGDynamicAddressKey @"ZGIsPointerKey" // value is for backwards compatibility #define ZGAddressFormulaKey @"ZGAddressFormulaKey" +#define ZGLabelKey @"ZGLabelKey" #define ZGScriptKey @"ZGScriptKey" #define ZGScriptCachePathKey @"ZGScriptCachePathKey" #define ZGScriptCacheUUIDKey @"ZGScriptCacheUUIDKey" @@ -114,6 +115,8 @@ - (void)encodeWithCoder:(NSCoder *)coder encodeObject:[self addressFormula] forKey:ZGAddressFormulaKey]; + [coder encodeObject:_label forKey:ZGLabelKey]; + if (_rawValue != nil) { [coder @@ -168,6 +171,16 @@ - (id)initWithCoder:(NSCoder *)coder _usesDynamicAddress = [coder decodeBoolForKey:ZGDynamicAddressKey]; _addressFormula = [coder decodeObjectOfClass:[NSString class] forKey:ZGAddressFormulaKey]; + + NSString *decodedLabel = [coder decodeObjectOfClass:[NSString class] forKey:ZGLabelKey]; + if (decodedLabel != nil) + { + _label = decodedLabel; + } + else + { + _label = @""; + } NSAttributedString *variableDescription = [coder decodeObjectOfClass:[NSAttributedString class] forKey:ZGDescriptionKey]; if (variableDescription == nil) @@ -312,6 +325,8 @@ - (id)initWithValue:(const void *)value size:(ZGMemorySize)size address:(ZGMemor { _fullAttributedDescription = [description copy]; } + + _label = @""; } return self; diff --git a/Bit Slicer/ZGVariableController.h b/Bit Slicer/ZGVariableController.h index 09488263b..99c60b760 100644 --- a/Bit Slicer/ZGVariableController.h +++ b/Bit Slicer/ZGVariableController.h @@ -89,6 +89,7 @@ typedef struct - (void)editVariables:(NSArray *)variables newValues:(NSArray *)newValues; - (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddressFormula; - (void)editVariables:(NSArray *)variables requestedSizes:(NSArray *)requestedSizes; +- (void)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels; @end diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index bd221b2a4..7d2e484fa 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -248,6 +248,11 @@ - (void)pasteVariables NSIndexSet *indexesToInsert = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(currentIndex, variablesToInsertArray.count)]; + for (ZGVariable *variable in variablesToInsertArray) + { + variable.label = @""; + } + [self addVariables:variablesToInsertArray atRowIndexes:indexesToInsert]; @@ -414,6 +419,8 @@ - (void)addVariables:(NSArray *)variables atRowIndexes:(NSIndexSet [windowController updateNumberOfValuesDisplayedStatus]; [windowController updateSearchAddressOptions]; + + [self annotateVariablesAutomatically:variables process:windowController.currentProcess]; } - (void)removeSelectedSearchValues @@ -930,7 +937,7 @@ - (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddres addressFormula:variable.addressFormula]; variable.addressFormula = newAddressFormula; - if (variable.usesDynamicPointerAddress || variable.usesDynamicBaseAddress || variable.usesDynamicSymbolAddress) + if (variable.usesDynamicPointerAddress || variable.usesDynamicBaseAddress || variable.usesDynamicSymbolAddress || variable.usesDynamicLabelAddress) { variable.usesDynamicAddress = YES; } @@ -948,6 +955,34 @@ - (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddres [windowController updateSearchAddressOptions]; } +#pragma mark Edit Variable Labels + +- (void)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels +{ + ZGDocumentWindowController *windowController = _windowController; + + NSMutableArray *oldLabels = [NSMutableArray array]; + for (ZGVariable *variable in variables) + { + [oldLabels addObject:variable.label]; + } + + windowController.undoManager.actionName = ZGLocalizedStringFromVariableActionsTable(@"undoLabelChange"); + [(ZGVariableController *)[windowController.undoManager prepareWithInvocationTarget:self] + editVariables:variables + requestedLabels:oldLabels]; + + NSUInteger labelIndex = 0; + for (ZGVariable *variable in variables) + { + variable.label = requestedLabels[labelIndex]; + labelIndex++; + } + + // Re-annotate the variables so the labels are in the descriptions + [self annotateVariablesAutomatically:variables process:windowController.currentProcess]; +} + #pragma mark Relativizing Variable Addresses - (void)unrelativizeVariables:(NSArray *)variables @@ -1016,7 +1051,7 @@ + (NSString *)relativizeVariable:(ZGVariable * __unsafe_unretained)variable with if (variableAddress >= totalSegmentRange.location && variableAddress < totalSegmentRange.location + totalSegmentRange.length) { NSString *partialPath = [machFilePath lastPathComponent]; - if (!variable.usesDynamicBaseAddress) + if (!variable.usesDynamicBaseAddress && !variable.usesDynamicSymbolAddress && !variable.usesDynamicLabelAddress) { NSString *pathToUse = nil; NSString *baseArgument = @""; @@ -1088,22 +1123,38 @@ + (NSString *)relativizeVariable:(ZGVariable * __unsafe_unretained)variable with return staticVariableDescription; } -- (void)annotateVariableAutomatically:(ZGVariable *)variable process:(ZGProcess *)process +- (void)annotateVariablesAutomatically:(NSArray *)variables process:(ZGProcess *)process { - if (!variable.userAnnotated) + ZGDocumentWindowController *windowController = _windowController; + ZGDocumentTableController *tableController = windowController.tableController; + + NSMutableArray *variablesToAnnotate = [NSMutableArray array]; + + for (ZGVariable *variable in variables) { - // Clear the description so we can automatically fill it again - variable.fullAttributedDescription = [[NSAttributedString alloc] initWithString:@"" attributes:@{NSForegroundColorAttributeName : [NSColor textColor]}]; - - // Update the variable's address - ZGDocumentWindowController *windowController = _windowController; - [windowController.tableController updateDynamicVariableAddress:variable]; - - // Re-annotate the variable - [[self class] annotateVariables:@[variable] process:process symbols:YES async:YES completionHandler:^{ - [windowController.variablesTableView reloadData]; - }]; + if (!variable.userAnnotated) + { + [variablesToAnnotate addObject:variable]; + + // Clear the description so we can automatically fill it again + variable.fullAttributedDescription = [[NSAttributedString alloc] initWithString:@"" attributes:@{NSForegroundColorAttributeName : [NSColor textColor]}]; + + // Update the variable's address + [tableController updateDynamicVariableAddress:variable]; + + [variablesToAnnotate addObject:variable]; + } } + + // Re-annotate the variables + [[self class] annotateVariables:variablesToAnnotate process:process symbols:YES async:YES completionHandler:^{ + [windowController.variablesTableView reloadData]; + }]; +} + +- (void)annotateVariableAutomatically:(ZGVariable *)variable process:(ZGProcess *)process +{ + [self annotateVariablesAutomatically:@[variable] process:process]; } + (ZGMachBinaryAnnotationInfo)machBinaryAnnotationInfoForProcess:(ZGProcess *)process @@ -1210,7 +1261,10 @@ + (void)annotateVariables:(NSArray *)variables annotationInfo:(ZGM protectionDescription = ZGProtectionDescription(cachedInfo.protection); } + NSString *label = variable.label; + NSMutableArray *validDescriptionComponents = [NSMutableArray array]; + if (label.length > 0) [validDescriptionComponents addObject:[NSString stringWithFormat:@"Label %@", label]]; if (symbol.length > 0) [validDescriptionComponents addObject:symbol]; if (staticDescription != nil) [validDescriptionComponents addObject:staticDescription]; if (userTagDescription != nil) [validDescriptionComponents addObject:userTagDescription]; From 13b781379af5a616a763fde5093e0da3f3c5a7d9 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sat, 4 May 2024 21:13:32 +0200 Subject: [PATCH 02/26] Don't allow re-using same labels --- Bit Slicer/ZGEditLabelWindowController.m | 19 +++++++++++--- Bit Slicer/ZGVariableController.h | 2 ++ Bit Slicer/ZGVariableController.m | 32 ++++++++++++++++++++---- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index d1db60f4b..a8cb32ed1 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -34,6 +34,9 @@ #import "ZGVariableController.h" #import "ZGVariable.h" #import "ZGNullability.h" +#import "ZGRunAlertPanel.h" + +#define ZGEditLabelLocalizableTable @"[Code] Edit Variable Label" @implementation ZGEditLabelWindowController { @@ -75,9 +78,7 @@ - (void)requestEditingLabelsFromVariables:(NSArray *)variables att - (IBAction)editVariablesLabels:(id)__unused sender { - NSWindow *window = ZGUnwrapNullableObject(self.window); - [NSApp endSheet:window]; - [window close]; + NSSet *usedLabels = _variableController.usedLabels; NSMutableArray *requestedLabels = [[NSMutableArray alloc] init]; @@ -97,6 +98,18 @@ - (IBAction)editVariablesLabels:(id)__unused sender } } + NSSet *requestedLabelsSet = [NSSet setWithArray:requestedLabels]; + if ([usedLabels intersectsSet:requestedLabelsSet]) + { + ZGRunAlertPanelWithOKButton(NSLocalizedStringFromTable(@"alreadyUsedLabelAlertTitle", ZGEditLabelLocalizableTable, nil), NSLocalizedStringFromTable(@"alreadyUsedLabelAlertMessage", ZGEditLabelLocalizableTable, nil)); + + return; + } + + NSWindow *window = ZGUnwrapNullableObject(self.window); + [NSApp endSheet:window]; + [window close]; + [_variableController editVariables:ZGUnwrapNullableObject(_variables) requestedLabels:requestedLabels]; _variables = nil; diff --git a/Bit Slicer/ZGVariableController.h b/Bit Slicer/ZGVariableController.h index 99c60b760..841722626 100644 --- a/Bit Slicer/ZGVariableController.h +++ b/Bit Slicer/ZGVariableController.h @@ -91,6 +91,8 @@ typedef struct - (void)editVariables:(NSArray *)variables requestedSizes:(NSArray *)requestedSizes; - (void)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels; +@property (nonatomic, readonly) NSSet *usedLabels; + @end NS_ASSUME_NONNULL_END diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index 7d2e484fa..17dfcd4e8 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -248,11 +248,6 @@ - (void)pasteVariables NSIndexSet *indexesToInsert = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(currentIndex, variablesToInsertArray.count)]; - for (ZGVariable *variable in variablesToInsertArray) - { - variable.label = @""; - } - [self addVariables:variablesToInsertArray atRowIndexes:indexesToInsert]; @@ -389,10 +384,37 @@ - (void)disableHarmfulVariables:(NSArray *)variables [self updateFrozenActivity]; } +- (NSSet *)usedLabels +{ + NSMutableSet *labels = [[NSMutableSet alloc] init]; + for (ZGVariable *variable in _documentData.variables) + { + NSString *label = variable.label; + if (label.length > 0) + { + [labels addObject:label]; + } + } + + return labels; +} + - (void)addVariables:(NSArray *)variables atRowIndexes:(NSIndexSet *)rowIndexes { ZGDocumentWindowController *windowController = _windowController; + // Make sure we do not end up with duplicate labels + // New variables that have a label that already exists have their labels removed + NSSet *oldLabels = [self usedLabels]; + for (ZGVariable *variable in variables) + { + NSString *label = variable.label; + if (label.length > 0 && [oldLabels containsObject:label]) + { + variable.label = @""; + } + } + NSMutableArray *temporaryArray = [[NSMutableArray alloc] initWithArray:_documentData.variables]; [temporaryArray insertObjects:variables atIndexes:rowIndexes]; From 108f1eabbc2d4e1cfea90cc5b76a74cf4b6383a3 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sat, 4 May 2024 21:30:49 +0200 Subject: [PATCH 03/26] Avoid computing cyclic addresses via labels --- Bit Slicer/ZGCalculator.h | 2 +- Bit Slicer/ZGCalculator.m | 38 ++++++++++++++++++++------ Bit Slicer/ZGDocumentTableController.m | 1 + 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Bit Slicer/ZGCalculator.h b/Bit Slicer/ZGCalculator.h index 9b25867bc..c4da2f710 100644 --- a/Bit Slicer/ZGCalculator.h +++ b/Bit Slicer/ZGCalculator.h @@ -65,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN // Can evaluate [address] + [address2] + offset, [address + [address2 - [address3]]] + offset, etc... // And also has a base() function that takes in a string, and returns the first address to a region such that the passed string partially matches the end of the corresponding region's mapped path -+ (nullable NSString *)evaluateExpression:(NSString *)expression labelController:(nullable ZGDocumentLabelController *)labelController process:(ZGProcess *)process failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; ++ (nullable NSString *)evaluateExpression:(NSString *)expression labelController:(nullable ZGDocumentLabelController *)labelController process:(ZGProcess *)process variable:(nullable ZGVariable *)variable failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; + (nullable NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess *)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(nullable BOOL *)didSymbolicate error:(NSError **)error; @end diff --git a/Bit Slicer/ZGCalculator.m b/Bit Slicer/ZGCalculator.m index 6bb6383ac..609da1e1b 100644 --- a/Bit Slicer/ZGCalculator.m +++ b/Bit Slicer/ZGCalculator.m @@ -56,6 +56,7 @@ #define ZGDidFindSymbol @"ZGDidFindSymbol" #define ZGLastSearchInfoVariable @"ZGLastSearchInfoVariable" #define ZGLabelControllerVariable @"ZGLabelControllerVariable" +#define ZGVariableVariable @"ZGVariableVariable" @implementation ZGVariable (ZGCalculatorAdditions) @@ -311,11 +312,25 @@ + (DDMathFunction)registerFindLabelFunctionWithEvaluator:(DDMathEvaluator *)eval } else { - ZGVariable *variable = [labelController variableForLabel:labelExpression.variable]; + NSString *label = labelExpression.variable; + ZGVariable *variable = [labelController variableForLabel:label]; if (variable != nil) { - labelAddressNumber = @(variable.address); + // Break out of a cycle if evaluating a label goes back to evaluating + // the label for the variable that was originally requesting the label + ZGVariable *originatingVariable = [vars objectForKey:ZGVariableVariable]; + if (originatingVariable == variable) + { + if (error != NULL) + { + *error = [NSError errorWithDomain:DDMathParserErrorDomain code:DDErrorCodeUnresolvedVariable userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"%@ encountered a cyclic traversal with label %@", ZGFindLabelFunction, label]}]; + } + } + else + { + labelAddressNumber = @(variable.address); + } } } } @@ -771,7 +786,7 @@ + (BOOL)_extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression else { // Found base() +- offset expression which we need to evaluate - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variable:nil labelController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; NSError *evaluateError = nil; NSNumber *evaluatedBaseAddressNumber = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:expression withSubstitutions:substitutions error:&evaluateError]; @@ -903,7 +918,7 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt return [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; } -+ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process labelController:(ZGDocumentLabelController *)labelController failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress ++ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process variable:(ZGVariable * __unsafe_unretained)variable labelController:(ZGDocumentLabelController *)labelController failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress { NSMutableDictionary *substitutions = [NSMutableDictionary dictionaryWithDictionary:@{ZGProcessVariable : process, ZGSymbolicatesVariable : @(symbolicates), ZGSymbolicationRequiresExactMatch : @(symbolicationRequiresExactMatch), ZGLastSearchInfoVariable : @(currentAddress), ZGDidFindSymbol : @(NO)}]; @@ -917,14 +932,19 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt [substitutions setObject:labelController forKey:ZGLabelControllerVariable]; } + if (variable != nil) + { + [substitutions setObject:variable forKey:ZGVariableVariable]; + } + return substitutions; } -+ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process variable:(ZGVariable * __unsafe_unretained)variable failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error { NSString *newExpression = [self expressionBySubstitutingCalculatePointerFunctionInExpression:expression]; - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:labelController failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variable:variable labelController:labelController failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; NSString *evaluatedExpression = [self evaluateExpression:newExpression substitutions:substitutions error:error]; if (foundSymbol != NULL) @@ -937,12 +957,12 @@ + (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocum + (NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess * __unsafe_unretained)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(BOOL *)didSymbolicate error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression labelController:nil process:process failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; + return [self evaluateExpression:expression labelController:nil process:process variable:nil failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; } -+ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process variable:(ZGVariable * __unsafe_unretained)variable failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression labelController:labelController process:process failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; + return [self evaluateExpression:expression labelController:labelController process:process variable:variable failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; } @end diff --git a/Bit Slicer/ZGDocumentTableController.m b/Bit Slicer/ZGDocumentTableController.m index 21c72ff95..f7ffc4244 100644 --- a/Bit Slicer/ZGDocumentTableController.m +++ b/Bit Slicer/ZGDocumentTableController.m @@ -209,6 +209,7 @@ - (BOOL)updateDynamicVariableAddress:(ZGVariable *)variable evaluateExpression:[NSMutableString stringWithString:variable.addressFormula] labelController:windowController.labelController process:windowController.currentProcess + variable:variable failedImages:_failedExecutableImages error:&error]; From 19f6cef2242cd0eea8f695fbdadf1806e37afd23 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sat, 4 May 2024 21:34:38 +0200 Subject: [PATCH 04/26] Revert "Avoid computing cyclic addresses via labels" This reverts commit 108f1eabbc2d4e1cfea90cc5b76a74cf4b6383a3. --- Bit Slicer/ZGCalculator.h | 2 +- Bit Slicer/ZGCalculator.m | 38 ++++++-------------------- Bit Slicer/ZGDocumentTableController.m | 1 - 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/Bit Slicer/ZGCalculator.h b/Bit Slicer/ZGCalculator.h index c4da2f710..9b25867bc 100644 --- a/Bit Slicer/ZGCalculator.h +++ b/Bit Slicer/ZGCalculator.h @@ -65,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN // Can evaluate [address] + [address2] + offset, [address + [address2 - [address3]]] + offset, etc... // And also has a base() function that takes in a string, and returns the first address to a region such that the passed string partially matches the end of the corresponding region's mapped path -+ (nullable NSString *)evaluateExpression:(NSString *)expression labelController:(nullable ZGDocumentLabelController *)labelController process:(ZGProcess *)process variable:(nullable ZGVariable *)variable failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; ++ (nullable NSString *)evaluateExpression:(NSString *)expression labelController:(nullable ZGDocumentLabelController *)labelController process:(ZGProcess *)process failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; + (nullable NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess *)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(nullable BOOL *)didSymbolicate error:(NSError **)error; @end diff --git a/Bit Slicer/ZGCalculator.m b/Bit Slicer/ZGCalculator.m index 609da1e1b..6bb6383ac 100644 --- a/Bit Slicer/ZGCalculator.m +++ b/Bit Slicer/ZGCalculator.m @@ -56,7 +56,6 @@ #define ZGDidFindSymbol @"ZGDidFindSymbol" #define ZGLastSearchInfoVariable @"ZGLastSearchInfoVariable" #define ZGLabelControllerVariable @"ZGLabelControllerVariable" -#define ZGVariableVariable @"ZGVariableVariable" @implementation ZGVariable (ZGCalculatorAdditions) @@ -312,25 +311,11 @@ + (DDMathFunction)registerFindLabelFunctionWithEvaluator:(DDMathEvaluator *)eval } else { - NSString *label = labelExpression.variable; - ZGVariable *variable = [labelController variableForLabel:label]; + ZGVariable *variable = [labelController variableForLabel:labelExpression.variable]; if (variable != nil) { - // Break out of a cycle if evaluating a label goes back to evaluating - // the label for the variable that was originally requesting the label - ZGVariable *originatingVariable = [vars objectForKey:ZGVariableVariable]; - if (originatingVariable == variable) - { - if (error != NULL) - { - *error = [NSError errorWithDomain:DDMathParserErrorDomain code:DDErrorCodeUnresolvedVariable userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"%@ encountered a cyclic traversal with label %@", ZGFindLabelFunction, label]}]; - } - } - else - { - labelAddressNumber = @(variable.address); - } + labelAddressNumber = @(variable.address); } } } @@ -786,7 +771,7 @@ + (BOOL)_extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression else { // Found base() +- offset expression which we need to evaluate - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variable:nil labelController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; NSError *evaluateError = nil; NSNumber *evaluatedBaseAddressNumber = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:expression withSubstitutions:substitutions error:&evaluateError]; @@ -918,7 +903,7 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt return [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; } -+ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process variable:(ZGVariable * __unsafe_unretained)variable labelController:(ZGDocumentLabelController *)labelController failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress ++ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process labelController:(ZGDocumentLabelController *)labelController failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress { NSMutableDictionary *substitutions = [NSMutableDictionary dictionaryWithDictionary:@{ZGProcessVariable : process, ZGSymbolicatesVariable : @(symbolicates), ZGSymbolicationRequiresExactMatch : @(symbolicationRequiresExactMatch), ZGLastSearchInfoVariable : @(currentAddress), ZGDidFindSymbol : @(NO)}]; @@ -932,19 +917,14 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt [substitutions setObject:labelController forKey:ZGLabelControllerVariable]; } - if (variable != nil) - { - [substitutions setObject:variable forKey:ZGVariableVariable]; - } - return substitutions; } -+ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process variable:(ZGVariable * __unsafe_unretained)variable failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error { NSString *newExpression = [self expressionBySubstitutingCalculatePointerFunctionInExpression:expression]; - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variable:variable labelController:labelController failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:labelController failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; NSString *evaluatedExpression = [self evaluateExpression:newExpression substitutions:substitutions error:error]; if (foundSymbol != NULL) @@ -957,12 +937,12 @@ + (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocum + (NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess * __unsafe_unretained)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(BOOL *)didSymbolicate error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression labelController:nil process:process variable:nil failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; + return [self evaluateExpression:expression labelController:nil process:process failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; } -+ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process variable:(ZGVariable * __unsafe_unretained)variable failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression labelController:labelController process:process variable:variable failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; + return [self evaluateExpression:expression labelController:labelController process:process failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; } @end diff --git a/Bit Slicer/ZGDocumentTableController.m b/Bit Slicer/ZGDocumentTableController.m index f7ffc4244..21c72ff95 100644 --- a/Bit Slicer/ZGDocumentTableController.m +++ b/Bit Slicer/ZGDocumentTableController.m @@ -209,7 +209,6 @@ - (BOOL)updateDynamicVariableAddress:(ZGVariable *)variable evaluateExpression:[NSMutableString stringWithString:variable.addressFormula] labelController:windowController.labelController process:windowController.currentProcess - variable:variable failedImages:_failedExecutableImages error:&error]; From d4d6ceba376c0ae4b98e45dd7c355e46429b0148 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sat, 4 May 2024 20:27:00 -0700 Subject: [PATCH 05/26] Replace $n with label index (or ordinal) --- Bit Slicer/ZGEditLabelWindowController.m | 47 +++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index a8cb32ed1..09e81b919 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -66,8 +66,43 @@ - (void)requestEditingLabelsFromVariables:(NSArray *)variables att NSWindow *window = ZGUnwrapNullableObject([self window]); // ensure window is loaded ZGVariable *firstVariable = [variables objectAtIndex:0]; + NSString *firstVariableLabel = firstVariable.label; + + NSString *labelStringValue; + NSString *labelPlaceholderStringValue; + + if (variables.count > 1) + { + if (firstVariableLabel.length == 0) + { + labelStringValue = @""; + labelPlaceholderStringValue = @"Foo_%n"; + } + else + { + NSRange digitsRange = [firstVariableLabel rangeOfCharacterFromSet:NSCharacterSet.decimalDigitCharacterSet options:NSBackwardsSearch | NSLiteralSearch]; + + if (digitsRange.location != NSNotFound) + { + labelStringValue = [NSString stringWithFormat:@"%@$n", [firstVariableLabel substringToIndex:digitsRange.location]]; + } + else + { + labelStringValue = [NSString stringWithFormat:@"%@_$n", firstVariableLabel]; + } + + labelPlaceholderStringValue = @""; + } + } + else + { + labelStringValue = firstVariableLabel; + labelPlaceholderStringValue = @""; + } + + _labelTextField.stringValue = labelStringValue; + _labelTextField.placeholderString = labelPlaceholderStringValue; - _labelTextField.stringValue = firstVariable.label; [_labelTextField selectText:nil]; _variables = variables; @@ -82,19 +117,21 @@ - (IBAction)editVariablesLabels:(id)__unused sender NSMutableArray *requestedLabels = [[NSMutableArray alloc] init]; - NSString *newLabel = _labelTextField.stringValue; + NSString *newRequestedLabel = _labelTextField.stringValue; + + NSRange ordinalRange = [newRequestedLabel rangeOfString:@"$n" options:NSBackwardsSearch | NSLiteralSearch]; NSUInteger variableIndex; NSUInteger variableCount = _variables.count; for (variableIndex = 0; variableIndex < variableCount; variableIndex++) { - if (variableCount == 1) + if (ordinalRange.location != NSNotFound) { - [requestedLabels addObject:newLabel]; + [requestedLabels addObject:[newRequestedLabel stringByReplacingCharactersInRange:ordinalRange withString:[NSString stringWithFormat:@"%lu", variableIndex]]]; } else { - [requestedLabels addObject:[NSString stringWithFormat:@"%@_%lu", newLabel, variableIndex]]; + [requestedLabels addObject:newRequestedLabel]; } } From bf495cc5807163ea43b6f2225ec99e96734b09e6 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sat, 4 May 2024 20:50:41 -0700 Subject: [PATCH 06/26] Remove label controller --- Bit Slicer.xcodeproj/project.pbxproj | 6 --- Bit Slicer/ZGCalculator.h | 4 +- Bit Slicer/ZGCalculator.m | 28 +++++------ Bit Slicer/ZGDocumentLabelController.h | 49 ------------------- Bit Slicer/ZGDocumentLabelController.m | 64 ------------------------- Bit Slicer/ZGDocumentTableController.m | 2 +- Bit Slicer/ZGDocumentWindowController.h | 2 - Bit Slicer/ZGDocumentWindowController.m | 2 - Bit Slicer/ZGPyDebugger.h | 3 +- Bit Slicer/ZGPyDebugger.m | 12 ++--- Bit Slicer/ZGScriptManager.m | 2 +- Bit Slicer/ZGVariableController.h | 2 + Bit Slicer/ZGVariableController.m | 12 +++++ 13 files changed, 37 insertions(+), 151 deletions(-) delete mode 100644 Bit Slicer/ZGDocumentLabelController.h delete mode 100644 Bit Slicer/ZGDocumentLabelController.m diff --git a/Bit Slicer.xcodeproj/project.pbxproj b/Bit Slicer.xcodeproj/project.pbxproj index 2a61c8a13..e2d39936b 100644 --- a/Bit Slicer.xcodeproj/project.pbxproj +++ b/Bit Slicer.xcodeproj/project.pbxproj @@ -15,7 +15,6 @@ 7208450624E084F400F3D449 /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7208450524E084F400F3D449 /* Python.framework */; }; 7208450724E0851000F3D449 /* Python.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 7208450524E084F400F3D449 /* Python.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 720C192C271B4F9700740C8E /* ZGSearchProtectionMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */; }; - 72130FC42BE67E2000691AED /* ZGDocumentLabelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 72130FC32BE67E2000691AED /* ZGDocumentLabelController.m */; }; 72130FC82BE6836A00691AED /* ZGEditLabelWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */; }; 72130FC92BE6836A00691AED /* Edit Label Dialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */; }; 721594FE24DF36360027F600 /* HexFiend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 721594FD24DF36360027F600 /* HexFiend.framework */; }; @@ -322,8 +321,6 @@ 720C1929271B46B600740C8E /* ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = ""; }; 720C192A271B4F9700740C8E /* ZGSearchProtectionMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGSearchProtectionMode.h; path = "Bit Slicer/ZGSearchProtectionMode.h"; sourceTree = ""; }; 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGSearchProtectionMode.m; path = "Bit Slicer/ZGSearchProtectionMode.m"; sourceTree = ""; }; - 72130FC22BE67E2000691AED /* ZGDocumentLabelController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGDocumentLabelController.h; path = "Bit Slicer/ZGDocumentLabelController.h"; sourceTree = ""; }; - 72130FC32BE67E2000691AED /* ZGDocumentLabelController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGDocumentLabelController.m; path = "Bit Slicer/ZGDocumentLabelController.m"; sourceTree = ""; }; 72130FC52BE6836A00691AED /* ZGEditLabelWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGEditLabelWindowController.h; path = "Bit Slicer/ZGEditLabelWindowController.h"; sourceTree = ""; }; 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGEditLabelWindowController.m; path = "Bit Slicer/ZGEditLabelWindowController.m"; sourceTree = ""; }; 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "Edit Label Dialog.xib"; path = "Bit Slicer/Edit Label Dialog.xib"; sourceTree = ""; }; @@ -1341,8 +1338,6 @@ 77F115F917D2EE6F009E002A /* ZGDocumentSearchController.m */, 77F115FB17D2EE7E009E002A /* ZGDocumentTableController.h */, 77F115FC17D2EE7E009E002A /* ZGDocumentTableController.m */, - 72130FC22BE67E2000691AED /* ZGDocumentLabelController.h */, - 72130FC32BE67E2000691AED /* ZGDocumentLabelController.m */, 77FFC104186BDA3600122357 /* ZGWatchVariableWindowController.h */, 77FFC105186BDA3600122357 /* ZGWatchVariableWindowController.m */, 7739728017D26A1600B958EE /* Scripting */, @@ -1719,7 +1714,6 @@ 773972F217D2E6AE00B958EE /* mach_excUser.c in Sources */, 77FFC107186BDA3600122357 /* ZGWatchVariableWindowController.m in Sources */, 77F115A817D2E87E009E002A /* VDKQueue.m in Sources */, - 72130FC42BE67E2000691AED /* ZGDocumentLabelController.m in Sources */, 77F115CD17D2ED64009E002A /* ZGMemoryViewerController.m in Sources */, 77F115D017D2ED74009E002A /* ZGVerticalScrollerRepresenter.m in Sources */, 77282123189E769B0044E4BC /* ZGStoredData.m in Sources */, diff --git a/Bit Slicer/ZGCalculator.h b/Bit Slicer/ZGCalculator.h index 9b25867bc..901875c28 100644 --- a/Bit Slicer/ZGCalculator.h +++ b/Bit Slicer/ZGCalculator.h @@ -34,7 +34,7 @@ #import "ZGVariable.h" @class ZGProcess; -@class ZGDocumentLabelController; +@class ZGVariableController; #define ZGBaseAddressFunction @"base" #define ZGFindSymbolFunction @"symbol" @@ -65,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN // Can evaluate [address] + [address2] + offset, [address + [address2 - [address3]]] + offset, etc... // And also has a base() function that takes in a string, and returns the first address to a region such that the passed string partially matches the end of the corresponding region's mapped path -+ (nullable NSString *)evaluateExpression:(NSString *)expression labelController:(nullable ZGDocumentLabelController *)labelController process:(ZGProcess *)process failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; ++ (nullable NSString *)evaluateExpression:(NSString *)expression variableController:(nullable ZGVariableController *)variableController process:(ZGProcess *)process failedImages:(nullable NSMutableArray *)failedImages error:(NSError **)error; + (nullable NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess *)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(nullable BOOL *)didSymbolicate error:(NSError **)error; @end diff --git a/Bit Slicer/ZGCalculator.m b/Bit Slicer/ZGCalculator.m index 6bb6383ac..559ad0f59 100644 --- a/Bit Slicer/ZGCalculator.m +++ b/Bit Slicer/ZGCalculator.m @@ -37,7 +37,7 @@ #import "ZGMachBinaryInfo.h" #import "ZGRegion.h" #import "ZGProcess.h" -#import "ZGDocumentLabelController.h" +#import "ZGVariableController.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincomplete-umbrella" #import @@ -55,7 +55,7 @@ #define ZGSymbolicationRequiresExactMatch @"ZGSymbolicationRequiresExactMatch" #define ZGDidFindSymbol @"ZGDidFindSymbol" #define ZGLastSearchInfoVariable @"ZGLastSearchInfoVariable" -#define ZGLabelControllerVariable @"ZGLabelControllerVariable" +#define ZGVariableControllerVariable @"ZGVariableControllerVariable" @implementation ZGVariable (ZGCalculatorAdditions) @@ -280,7 +280,7 @@ + (DDMathFunction)registerFindSymbolFunctionWithEvaluator:(DDMathEvaluator *)eva + (DDMathFunction)registerFindLabelFunctionWithEvaluator:(DDMathEvaluator *)evaluator { DDMathFunction findLabelFunction = ^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator * __unused eval, NSError *__autoreleasing *error) { - ZGDocumentLabelController *labelController = [vars objectForKey:ZGLabelControllerVariable]; + ZGVariableController *variableController = [vars objectForKey:ZGVariableControllerVariable]; __block NSNumber *labelAddressNumber = @(0); @@ -291,7 +291,7 @@ + (DDMathFunction)registerFindLabelFunctionWithEvaluator:(DDMathEvaluator *)eval *error = [NSError errorWithDomain:DDMathParserErrorDomain code:DDErrorCodeInvalidNumberOfArguments userInfo:@{NSLocalizedDescriptionKey:ZGFindLabelFunction @" expects 1 argument"}]; } } - else if (labelController == nil) + else if (variableController == nil) { if (error != NULL) { @@ -311,7 +311,7 @@ + (DDMathFunction)registerFindLabelFunctionWithEvaluator:(DDMathEvaluator *)eval } else { - ZGVariable *variable = [labelController variableForLabel:labelExpression.variable]; + ZGVariable *variable = [variableController variableForLabel:labelExpression.variable]; if (variable != nil) { @@ -771,7 +771,7 @@ + (BOOL)_extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression else { // Found base() +- offset expression which we need to evaluate - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variableController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; NSError *evaluateError = nil; NSNumber *evaluatedBaseAddressNumber = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:expression withSubstitutions:substitutions error:&evaluateError]; @@ -903,7 +903,7 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt return [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; } -+ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process labelController:(ZGDocumentLabelController *)labelController failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress ++ (NSDictionary *)_evaluatorSubstitutionsForProcess:(ZGProcess * __unsafe_unretained)process variableController:(ZGVariableController *)variableController failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch currentAddress:(ZGMemoryAddress)currentAddress { NSMutableDictionary *substitutions = [NSMutableDictionary dictionaryWithDictionary:@{ZGProcessVariable : process, ZGSymbolicatesVariable : @(symbolicates), ZGSymbolicationRequiresExactMatch : @(symbolicationRequiresExactMatch), ZGLastSearchInfoVariable : @(currentAddress), ZGDidFindSymbol : @(NO)}]; @@ -912,19 +912,19 @@ + (NSString *)expressionBySubstitutingCalculatePointerFunctionInExpression:(NSSt [substitutions setObject:failedImages forKey:ZGFailedImagesVariable]; } - if (labelController != nil) + if (variableController != nil) { - [substitutions setObject:labelController forKey:ZGLabelControllerVariable]; + [substitutions setObject:variableController forKey:ZGVariableControllerVariable]; } return substitutions; } -+ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression variableController:(ZGVariableController *)variableController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages symbolicates:(BOOL)symbolicates symbolicationRequiresExactMatch:(BOOL)symbolicationRequiresExactMatch foundSymbol:(BOOL *)foundSymbol currentAddress:(ZGMemoryAddress)currentAddress error:(NSError * __autoreleasing *)error { NSString *newExpression = [self expressionBySubstitutingCalculatePointerFunctionInExpression:expression]; - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process labelController:labelController failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variableController:variableController failedImages:failedImages symbolicates:symbolicates symbolicationRequiresExactMatch:symbolicationRequiresExactMatch currentAddress:currentAddress]; NSString *evaluatedExpression = [self evaluateExpression:newExpression substitutions:substitutions error:error]; if (foundSymbol != NULL) @@ -937,12 +937,12 @@ + (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocum + (NSString *)evaluateAndSymbolicateExpression:(NSString *)expression process:(ZGProcess * __unsafe_unretained)process currentAddress:(ZGMemoryAddress)currentAddress didSymbolicate:(BOOL *)didSymbolicate error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression labelController:nil process:process failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; + return [self evaluateExpression:expression variableController:nil process:process failedImages:nil symbolicates:YES symbolicationRequiresExactMatch:NO foundSymbol:didSymbolicate currentAddress:currentAddress error:error]; } -+ (NSString *)evaluateExpression:(NSString *)expression labelController:(ZGDocumentLabelController *)labelController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error ++ (NSString *)evaluateExpression:(NSString *)expression variableController:(ZGVariableController *)variableController process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages error:(NSError * __autoreleasing *)error { - return [self evaluateExpression:expression labelController:labelController process:process failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; + return [self evaluateExpression:expression variableController:variableController process:process failedImages:failedImages symbolicates:YES symbolicationRequiresExactMatch:YES foundSymbol:NULL currentAddress:0x0 error:error]; } @end diff --git a/Bit Slicer/ZGDocumentLabelController.h b/Bit Slicer/ZGDocumentLabelController.h deleted file mode 100644 index 859ff0dd6..000000000 --- a/Bit Slicer/ZGDocumentLabelController.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2024 Mayur Pawashe - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the project's author nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import -#import "ZGMemoryTypes.h" - -NS_ASSUME_NONNULL_BEGIN - -@class ZGDocumentData; -@class ZGVariable; - -@interface ZGDocumentLabelController : NSObject - -- (instancetype)initWithDocumentData:(ZGDocumentData *)documentData; - -- (nullable ZGVariable *)variableForLabel:(NSString *)label; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Bit Slicer/ZGDocumentLabelController.m b/Bit Slicer/ZGDocumentLabelController.m deleted file mode 100644 index 12c38371b..000000000 --- a/Bit Slicer/ZGDocumentLabelController.m +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2024 Mayur Pawashe - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the project's author nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "ZGDocumentLabelController.h" -#import "ZGDocumentData.h" -#import "ZGVariable.h" - -@implementation ZGDocumentLabelController -{ - ZGDocumentData *_documentData; -} - -- (instancetype)initWithDocumentData:(ZGDocumentData *)documentData -{ - self = [super init]; - if (self != nil) - { - _documentData = documentData; - } - return self; -} - -- (nullable ZGVariable *)variableForLabel:(NSString *)label -{ - for (ZGVariable *variable in _documentData.variables) - { - if ([variable.label isEqualToString:label]) - { - return variable; - } - } - return nil; -} - -@end diff --git a/Bit Slicer/ZGDocumentTableController.m b/Bit Slicer/ZGDocumentTableController.m index 21c72ff95..391f304f8 100644 --- a/Bit Slicer/ZGDocumentTableController.m +++ b/Bit Slicer/ZGDocumentTableController.m @@ -207,7 +207,7 @@ - (BOOL)updateDynamicVariableAddress:(ZGVariable *)variable NSString *newAddressString = [ZGCalculator evaluateExpression:[NSMutableString stringWithString:variable.addressFormula] - labelController:windowController.labelController + variableController:windowController.variableController process:windowController.currentProcess failedImages:_failedExecutableImages error:&error]; diff --git a/Bit Slicer/ZGDocumentWindowController.h b/Bit Slicer/ZGDocumentWindowController.h index 8ec5d9f35..a60e87394 100644 --- a/Bit Slicer/ZGDocumentWindowController.h +++ b/Bit Slicer/ZGDocumentWindowController.h @@ -55,7 +55,6 @@ @class ZGHotKeyCenter; @class ZGDocument; @class ZGAppTerminationState; -@class ZGDocumentLabelController; NS_ASSUME_NONNULL_BEGIN @@ -78,7 +77,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) ZGVariableController *variableController; @property (nonatomic, readonly) ZGDocumentSearchController *searchController; @property (nonatomic, readonly) ZGScriptManager *scriptManager; -@property (nonatomic, readonly) ZGDocumentLabelController *labelController; @property (nonatomic, readonly) ZGDocumentData *documentData; @property (nonatomic, readonly) ZGSearchData *searchData; diff --git a/Bit Slicer/ZGDocumentWindowController.m b/Bit Slicer/ZGDocumentWindowController.m index 31ad892b6..329184a13 100644 --- a/Bit Slicer/ZGDocumentWindowController.m +++ b/Bit Slicer/ZGDocumentWindowController.m @@ -46,7 +46,6 @@ #import "ZGRunningProcess.h" #import "ZGPreferencesController.h" #import "ZGDocumentData.h" -#import "ZGDocumentLabelController.h" #import "ZGSearchData.h" #import "ZGSearchProgress.h" #import "ZGSearchResults.h" @@ -309,7 +308,6 @@ - (void)windowDidLoad _variableController = [[ZGVariableController alloc] initWithWindowController:self]; _searchController = [[ZGDocumentSearchController alloc] initWithWindowController:self]; _scriptManager = [[ZGScriptManager alloc] initWithWindowController:self]; - _labelController = [[ZGDocumentLabelController alloc] initWithDocumentData:_documentData]; _searchValueTextField.target = self; _searchValueTextField.action = @selector(searchValue:); diff --git a/Bit Slicer/ZGPyDebugger.h b/Bit Slicer/ZGPyDebugger.h index bf7991518..8b805a5b5 100644 --- a/Bit Slicer/ZGPyDebugger.h +++ b/Bit Slicer/ZGPyDebugger.h @@ -43,7 +43,6 @@ @class ZGBreakPointController; @class ZGLoggerWindowController; @class ZGHotKeyCenter; -@class ZGDocumentLabelController; @class ZGVariableController; NS_ASSUME_NONNULL_BEGIN @@ -52,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN + (nullable PyObject *)loadPythonClassInMainModule:(PyObject *)module; -- (nullable id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager labelController:(ZGDocumentLabelController *)labelController variableController:(ZGVariableController *)variableController breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController; +- (nullable id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager variableController:(ZGVariableController *)variableController breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController; - (void)cleanup; @property (nonatomic, weak, readonly) ZGScriptManager *scriptManager; diff --git a/Bit Slicer/ZGPyDebugger.m b/Bit Slicer/ZGPyDebugger.m index 9a5f07355..d489ded82 100644 --- a/Bit Slicer/ZGPyDebugger.m +++ b/Bit Slicer/ZGPyDebugger.m @@ -56,7 +56,6 @@ #import "ZGHotKey.h" #import "ZGScriptPrompt.h" #import "ZGNullability.h" -#import "ZGDocumentLabelController.h" #import "ZGVariableController.h" @class ZGPyDebugger; @@ -201,7 +200,6 @@ @implementation ZGPyDebugger __weak ZGScriptManager * _Nullable _scriptManager; ZGBreakPointController * _Nonnull _breakPointController; ZGLoggerWindowController * _Nonnull _loggerWindowController; - ZGDocumentLabelController *_Nonnull _labelController; ZGVariableController *_Nonnull _variableController; NSMutableDictionary * _Nonnull _cachedInstructionPointers; ZGHotKeyCenter * _Nonnull _hotKeyCenter; @@ -238,7 +236,7 @@ + (PyObject *)loadPythonClassInMainModule:(PyObject *)module return debuggerException; } -- (id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager labelController:(ZGDocumentLabelController *)labelController variableController:(ZGVariableController *)variableController breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController +- (id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInterpreter *)scriptingInterpreter scriptManager:(ZGScriptManager *)scriptManager variableController:(ZGVariableController *)variableController breakPointController:(ZGBreakPointController *)breakPointController hotKeyCenter:(ZGHotKeyCenter *)hotKeyCenter loggerWindowController:(ZGLoggerWindowController *)loggerWindowController { self = [super init]; if (self != nil) @@ -253,7 +251,6 @@ - (id)initWithProcess:(ZGProcess *)process scriptingInterpreter:(ZGScriptingInte _scriptManager = scriptManager; _scriptingInterpreter = scriptingInterpreter; _process = [[ZGProcess alloc] initWithProcess:process]; - _labelController = labelController; _variableController = variableController; _breakPointController = breakPointController; _loggerWindowController = loggerWindowController; @@ -1508,11 +1505,10 @@ static BOOL writeRegister(NSDictionary *registerOffsetsDi return NULL; } - ZGDocumentLabelController *labelController = self->objcSelf->_labelController; ZGVariableController *variableController = self->objcSelf->_variableController; dispatch_async(dispatch_get_main_queue(), ^{ - ZGVariable *variable = [labelController variableForLabel:labelString]; + ZGVariable *variable = [variableController variableForLabel:labelString]; [variableController editVariable:variable addressFormula:addressString]; }); @@ -1538,9 +1534,9 @@ static BOOL writeRegister(NSDictionary *registerOffsetsDi __block ZGMemoryAddress variableAddress; __block BOOL foundAddress; - ZGDocumentLabelController *labelController = self->objcSelf->_labelController; + ZGVariableController *variableController = self->objcSelf->_variableController; dispatch_sync(dispatch_get_main_queue(), ^{ - ZGVariable *variable = [labelController variableForLabel:labelString]; + ZGVariable *variable = [variableController variableForLabel:labelString]; foundAddress = (variable != nil); variableAddress = variable.address; }); diff --git a/Bit Slicer/ZGScriptManager.m b/Bit Slicer/ZGScriptManager.m index ff604bb9d..cf1493d57 100644 --- a/Bit Slicer/ZGScriptManager.m +++ b/Bit Slicer/ZGScriptManager.m @@ -585,7 +585,7 @@ - (void)runScriptForVariable:(ZGVariable *)variable ZGPyVirtualMemory *virtualMemoryInstance = [[ZGPyVirtualMemory alloc] initWithProcess:windowController.currentProcess virtualMemoryException:(PyObject * _Nonnull)self->_scriptingInterpreter.virtualMemoryException]; - ZGPyDebugger *debuggerInstance = [[ZGPyDebugger alloc] initWithProcess:windowController.currentProcess scriptingInterpreter:self->_scriptingInterpreter scriptManager:self labelController:windowController.labelController variableController:windowController.variableController breakPointController:windowController.breakPointController hotKeyCenter:windowController.hotKeyCenter loggerWindowController:windowController.loggerWindowController]; + ZGPyDebugger *debuggerInstance = [[ZGPyDebugger alloc] initWithProcess:windowController.currentProcess scriptingInterpreter:self->_scriptingInterpreter scriptManager:self variableController:windowController.variableController breakPointController:windowController.breakPointController hotKeyCenter:windowController.hotKeyCenter loggerWindowController:windowController.loggerWindowController]; script.virtualMemoryInstance = virtualMemoryInstance; script.debuggerInstance = debuggerInstance; diff --git a/Bit Slicer/ZGVariableController.h b/Bit Slicer/ZGVariableController.h index 841722626..42491bf80 100644 --- a/Bit Slicer/ZGVariableController.h +++ b/Bit Slicer/ZGVariableController.h @@ -91,6 +91,8 @@ typedef struct - (void)editVariables:(NSArray *)variables requestedSizes:(NSArray *)requestedSizes; - (void)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels; +- (nullable ZGVariable *)variableForLabel:(NSString *)label; + @property (nonatomic, readonly) NSSet *usedLabels; @end diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index 17dfcd4e8..afcc96eca 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -399,6 +399,18 @@ - (void)disableHarmfulVariables:(NSArray *)variables return labels; } +- (nullable ZGVariable *)variableForLabel:(NSString *)label +{ + for (ZGVariable *variable in _documentData.variables) + { + if ([variable.label isEqualToString:label]) + { + return variable; + } + } + return nil; +} + - (void)addVariables:(NSArray *)variables atRowIndexes:(NSIndexSet *)rowIndexes { ZGDocumentWindowController *windowController = _windowController; From 91a83bd1c9042e60e4a79154bfb9eb529e285500 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 05:31:23 -0700 Subject: [PATCH 07/26] Disallow labeled variables or variables using labels to be narrowed --- Bit Slicer/ZGDocumentSearchController.m | 2 +- Bit Slicer/ZGDocumentWindowController.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Bit Slicer/ZGDocumentSearchController.m b/Bit Slicer/ZGDocumentSearchController.m index d27b0c5e8..2db67d543 100644 --- a/Bit Slicer/ZGDocumentSearchController.m +++ b/Bit Slicer/ZGDocumentSearchController.m @@ -159,7 +159,7 @@ - (BOOL)isVariableNarrowable:(ZGVariable *)variable dataType:(ZGVariableType)dat // If we are doing a pointer address search, the variable must have a dynamic pointer address // If we are doing a regular value search, variable could be a normal address or dynamic pointer address (as long as it's a 64-bit process) - return (variable.enabled && variable.type == dataType && !variable.isFrozen) && (!pointerAddressSearch || variable.usesDynamicPointerAddress) && !variable.usesDynamicSymbolAddress; + return (variable.enabled && variable.type == dataType && !variable.isFrozen) && (!pointerAddressSearch || variable.usesDynamicPointerAddress) && !variable.usesDynamicSymbolAddress && !variable.usesDynamicLabelAddress && variable.label.length == 0; } - (BOOL)canStartTask diff --git a/Bit Slicer/ZGDocumentWindowController.m b/Bit Slicer/ZGDocumentWindowController.m index 329184a13..105674f96 100644 --- a/Bit Slicer/ZGDocumentWindowController.m +++ b/Bit Slicer/ZGDocumentWindowController.m @@ -962,7 +962,7 @@ - (void)_changeSearchType:(ZGSearchType)newSearchType prepopulateAddress:(BOOL)p ZGVariable *foundDirectVariable = nil; for (ZGVariable *variable in _documentData.variables) { - if (variable.type == selectedDataType && !variable.usesDynamicSymbolAddress && variable.stringValue.length > 0) + if (variable.type == selectedDataType && !variable.usesDynamicSymbolAddress && !variable.usesDynamicLabelAddress && variable.label.length == 0 && variable.stringValue.length > 0) { if (variable.usesDynamicPointerAddress) { From cbd28db69dc7d7c3ed0c8e96b9e43148849f78c2 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 06:42:46 -0700 Subject: [PATCH 08/26] Annotate variables that use labels pointing to indirect variables --- Bit Slicer/ZGCalculator.h | 2 +- Bit Slicer/ZGCalculator.m | 110 +++++++++++++++++------- Bit Slicer/ZGDebuggerController.m | 2 +- Bit Slicer/ZGDocumentSearchController.m | 2 +- Bit Slicer/ZGDocumentTableController.m | 2 +- Bit Slicer/ZGDocumentWindowController.m | 7 +- Bit Slicer/ZGMemoryViewerController.m | 2 +- Bit Slicer/ZGVariableController.h | 4 +- Bit Slicer/ZGVariableController.m | 29 ++++--- 9 files changed, 108 insertions(+), 52 deletions(-) diff --git a/Bit Slicer/ZGCalculator.h b/Bit Slicer/ZGCalculator.h index 901875c28..14a57d391 100644 --- a/Bit Slicer/ZGCalculator.h +++ b/Bit Slicer/ZGCalculator.h @@ -57,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)extractIndirectAddressesAndOffsetsFromIntoBuffer:(void *)buffer expression:(NSString *)initialExpression filePaths:(NSArray *)filePaths filePathSuffixIndexCache:(NSMutableDictionary *)filePathSuffixIndexCache maxLevels:(uint16_t)maxLevels stride:(ZGMemorySize)stride; -+ (BOOL)extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression:(NSString *)initialExpression process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages; ++ (BOOL)extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression:(NSString *)initialExpression process:(ZGProcess * __unsafe_unretained)process variableController:(nullable ZGVariableController * __unsafe_unretained)variableController failedImages:(NSMutableArray * __unsafe_unretained)failedImages; + (BOOL)parseLinearExpression:(NSString *)linearExpression andGetAdditiveConstant:(NSString * _Nullable * _Nonnull)additiveConstantString multiplicateConstant:(NSString *_Nullable * _Nonnull)multiplicativeConstantString; diff --git a/Bit Slicer/ZGCalculator.m b/Bit Slicer/ZGCalculator.m index 559ad0f59..b26b155bd 100644 --- a/Bit Slicer/ZGCalculator.m +++ b/Bit Slicer/ZGCalculator.m @@ -740,61 +740,98 @@ + (BOOL)extractIndirectAddressesAndOffsetsFromIntoBuffer:(void *)buffer expressi return YES; } -+ (BOOL)_extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression:(DDExpression *)expression process:(ZGProcess *)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages ++ (BOOL)_extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress foundPointerFunction:(BOOL *)foundPointerFunction expression:(DDExpression *)expression process:(ZGProcess *)process variableController:(ZGVariableController *)variableController visitedLabels:(NSMutableSet *)visitedLabels failedImages:(NSMutableArray * __unsafe_unretained)failedImages { switch (expression.expressionType) { case DDExpressionTypeFunction: - if (([expression.function isEqualToString:@"add"] || [expression.function isEqualToString:@"subtract"]) && expression.arguments.count == 2) + if ([expression.function isEqualToString:ZGFindLabelFunction] && expression.arguments.count == 1) + { + DDExpression *argumentExpression = expression.arguments[0]; + if (argumentExpression.expressionType != DDExpressionTypeVariable) + { + return NO; + } + + NSString *label = argumentExpression.variable; + + if ([visitedLabels containsObject:label]) + { + // Prevent recursive/cyclic lookups + return NO; + } + + ZGVariable *labelVariable = [variableController variableForLabel:label]; + if (labelVariable == nil) + { + return NO; + } + + // Recurse into the labeled variable's address + NSString *addressFormula = labelVariable.addressFormula; + NSString *substitutedAddressFormulaExpression = [ZGCalculator expressionBySubstitutingCalculatePointerFunctionInExpression:addressFormula]; + + NSError *expressionError = NULL; + DDExpression *addressFormulaExpression = [DDExpression expressionFromString:substitutedAddressFormulaExpression error:&expressionError]; + if (addressFormulaExpression == nil) + { + return NO; + } + + [visitedLabels addObject:label]; + + return [self _extractIndirectBaseAddress:outBaseAddress foundPointerFunction:foundPointerFunction expression:addressFormulaExpression process:process variableController:variableController visitedLabels:visitedLabels failedImages:failedImages]; + } + else if (([expression.function isEqualToString:@"add"] || [expression.function isEqualToString:@"subtract"]) && expression.arguments.count == 2) { DDExpression *argumentExpression1 = expression.arguments[0]; DDExpression *argumentExpression2 = expression.arguments[1]; - DDExpression *pointerSubExpression; if (argumentExpression1.expressionType == DDExpressionTypeFunction && [argumentExpression1.function isEqualToString:ZGCalculatePointerFunction]) { - pointerSubExpression = argumentExpression1; + return [self _extractIndirectBaseAddress:outBaseAddress foundPointerFunction:foundPointerFunction expression:argumentExpression1 process:process variableController:variableController visitedLabels:visitedLabels failedImages:failedImages]; } else if (argumentExpression2.expressionType == DDExpressionTypeFunction && [argumentExpression2.function isEqualToString:ZGCalculatePointerFunction]) { - pointerSubExpression = argumentExpression2; + return [self _extractIndirectBaseAddress:outBaseAddress foundPointerFunction:foundPointerFunction expression:argumentExpression2 process:process variableController:variableController visitedLabels:visitedLabels failedImages:failedImages]; } - else + + if (argumentExpression1.expressionType == DDExpressionTypeFunction && [argumentExpression1.function isEqualToString:ZGFindLabelFunction]) { - pointerSubExpression = nil; + return [self _extractIndirectBaseAddress:outBaseAddress foundPointerFunction:foundPointerFunction expression:argumentExpression1 process:process variableController:variableController visitedLabels:visitedLabels failedImages:failedImages]; + } + else if (argumentExpression2.expressionType == DDExpressionTypeFunction && [argumentExpression2.function isEqualToString:ZGFindLabelFunction]) + { + return [self _extractIndirectBaseAddress:outBaseAddress foundPointerFunction:foundPointerFunction expression:argumentExpression2 process:process variableController:variableController visitedLabels:visitedLabels failedImages:failedImages]; } - if (pointerSubExpression != nil) + // Found base() +- offset expression which we need to evaluate + NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variableController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; + + NSError *evaluateError = nil; + NSNumber *evaluatedBaseAddressNumber = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:expression withSubstitutions:substitutions error:&evaluateError]; + + if (evaluatedBaseAddressNumber == nil) { - return [self _extractIndirectBaseAddress:outBaseAddress expression:pointerSubExpression process:process failedImages:failedImages]; + return NO; } - else + + ZGMemoryAddress baseAddress = (ZGMemoryAddress)evaluatedBaseAddressNumber.unsignedLongLongValue; + if (outBaseAddress != NULL) { - // Found base() +- offset expression which we need to evaluate - NSDictionary *substitutions = [self _evaluatorSubstitutionsForProcess:process variableController:nil failedImages:failedImages symbolicates:NO symbolicationRequiresExactMatch:YES currentAddress:0x0]; - - NSError *evaluateError = nil; - NSNumber *evaluatedBaseAddressNumber = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:expression withSubstitutions:substitutions error:&evaluateError]; - - if (evaluatedBaseAddressNumber == nil) - { - return NO; - } - else - { - ZGMemoryAddress baseAddress = (ZGMemoryAddress)evaluatedBaseAddressNumber.unsignedLongLongValue; - if (outBaseAddress != NULL) - { - *outBaseAddress = baseAddress; - } - - return YES; - } + *outBaseAddress = baseAddress; } + + return YES; } else if ([expression.function isEqualToString:ZGCalculatePointerFunction] && expression.arguments.count == 1) { - return [self _extractIndirectBaseAddress:outBaseAddress expression:expression.arguments[0] process:process failedImages:failedImages]; + if (foundPointerFunction != NULL) + { + *foundPointerFunction = YES; + } + + return [self _extractIndirectBaseAddress:outBaseAddress foundPointerFunction:foundPointerFunction expression:expression.arguments[0] process:process variableController:variableController visitedLabels:visitedLabels failedImages:failedImages]; } else { @@ -817,7 +854,7 @@ + (BOOL)_extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression } } -+ (BOOL)extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression:(NSString *)initialExpression process:(ZGProcess * __unsafe_unretained)process failedImages:(NSMutableArray * __unsafe_unretained)failedImages ++ (BOOL)extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression:(NSString *)initialExpression process:(ZGProcess * __unsafe_unretained)process variableController:(ZGVariableController * __unsafe_unretained)variableController failedImages:(NSMutableArray * __unsafe_unretained)failedImages { NSString *substitutedExpression = [ZGCalculator expressionBySubstitutingCalculatePointerFunctionInExpression:initialExpression]; @@ -828,7 +865,14 @@ + (BOOL)extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression: return NO; } - if (![self _extractIndirectBaseAddress:outBaseAddress expression:expression process:process failedImages:failedImages]) + NSMutableSet *visitedLabels = [NSMutableSet set]; + BOOL foundPointerFunction = NO; + if (![self _extractIndirectBaseAddress:outBaseAddress foundPointerFunction:&foundPointerFunction expression:expression process:process variableController:variableController visitedLabels:visitedLabels failedImages:failedImages]) + { + return NO; + } + + if (!foundPointerFunction) { return NO; } diff --git a/Bit Slicer/ZGDebuggerController.m b/Bit Slicer/ZGDebuggerController.m index e102c5f3b..6bdfd5b6c 100644 --- a/Bit Slicer/ZGDebuggerController.m +++ b/Bit Slicer/ZGDebuggerController.m @@ -1627,7 +1627,7 @@ - (void)annotateInstructions:(NSArray *)instructions symbols:(B return (BOOL)(!variable.usesDynamicAddress); }]; - [ZGVariableController annotateVariables:variablesToAnnotate process:self.currentProcess symbols:symbols async:async completionHandler:^{ + [ZGVariableController annotateVariables:variablesToAnnotate process:self.currentProcess variableController:nil symbols:symbols async:async completionHandler:^{ for (ZGInstruction *instruction in instructions) { if (instruction.variable.fullAttributedDescription.length == 0) diff --git a/Bit Slicer/ZGDocumentSearchController.m b/Bit Slicer/ZGDocumentSearchController.m index 2db67d543..918779a11 100644 --- a/Bit Slicer/ZGDocumentSearchController.m +++ b/Bit Slicer/ZGDocumentSearchController.m @@ -517,7 +517,7 @@ case sizeof(ZG32BitMemoryAddress): dispatch_async(dispatch_get_main_queue(), ^{ // Waiting for completion would lead to a bad user experience and there is no need to - [ZGVariableController annotateVariables:newVariables annotationInfo:annotationInfo process:currentProcess symbols:YES async:YES completionHandler:^{ + [ZGVariableController annotateVariables:newVariables annotationInfo:annotationInfo process:currentProcess variableController:nil symbols:YES async:YES completionHandler:^{ [windowController.variablesTableView reloadData]; }]; }); diff --git a/Bit Slicer/ZGDocumentTableController.m b/Bit Slicer/ZGDocumentTableController.m index 391f304f8..82c6b7634 100644 --- a/Bit Slicer/ZGDocumentTableController.m +++ b/Bit Slicer/ZGDocumentTableController.m @@ -232,7 +232,7 @@ - (BOOL)getBaseAddress:(ZGMemoryAddress *)outBaseAddress variable:(ZGVariable *) { ZGDocumentWindowController *windowController = _windowController; - return [ZGCalculator extractIndirectBaseAddress:outBaseAddress expression:variable.addressFormula process:windowController.currentProcess failedImages:_failedExecutableImages]; + return [ZGCalculator extractIndirectBaseAddress:outBaseAddress expression:variable.addressFormula process:windowController.currentProcess variableController:windowController.variableController failedImages:_failedExecutableImages]; } - (void)updateWatchVariablesTable:(NSTimer *)__unused timer diff --git a/Bit Slicer/ZGDocumentWindowController.m b/Bit Slicer/ZGDocumentWindowController.m index 105674f96..196ad2b29 100644 --- a/Bit Slicer/ZGDocumentWindowController.m +++ b/Bit Slicer/ZGDocumentWindowController.m @@ -1479,7 +1479,8 @@ - (BOOL)validateUserInterfaceItem:(id )userInterfa BOOL watchingBaseAccesses = (menuItem.action == @selector(watchVariableBaseAddress:)); if (watchingBaseAccesses) { - menuItem.hidden = !selectedVariable.usesDynamicPointerAddress; + // Hide menu item for now, but unhide if it we are able to retrieve a base address + menuItem.hidden = YES; } if (selectedVariable.type == ZGScript) @@ -1500,6 +1501,8 @@ - (BOOL)validateUserInterfaceItem:(id )userInterfa return NO; } + menuItem.hidden = NO; + targetMemoryAddress = baseAddress; targetMemorySize = self.currentProcess.pointerSize; } @@ -1955,7 +1958,7 @@ - (void)_watchVariable:(ZGVariable *)variable watchPointType:(ZGWatchPointType)w NSIndexSet *rowIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, foundVariables.count)]; [self->_variableController addVariables:foundVariables atRowIndexes:rowIndexes]; [self->_variablesTableView scrollRowToVisible:0]; - [ZGVariableController annotateVariables:foundVariables process:self.currentProcess symbols:YES async:YES completionHandler:^{ + [ZGVariableController annotateVariables:foundVariables process:self.currentProcess variableController:nil symbols:YES async:YES completionHandler:^{ [self->_variablesTableView reloadData]; }]; } diff --git a/Bit Slicer/ZGMemoryViewerController.m b/Bit Slicer/ZGMemoryViewerController.m index 945af2842..8494b1332 100644 --- a/Bit Slicer/ZGMemoryViewerController.m +++ b/Bit Slicer/ZGMemoryViewerController.m @@ -715,7 +715,7 @@ - (IBAction)copyAddress:(id)__unused sender { ZGVariable *variable = [self _variableFromSelectedAddressRange]; - [ZGVariableController annotateVariables:@[variable] process:self.currentProcess symbols:NO async:NO completionHandler:^{ + [ZGVariableController annotateVariables:@[variable] process:self.currentProcess variableController:nil symbols:NO async:NO completionHandler:^{ [[NSPasteboard generalPasteboard] declareTypes:@[NSPasteboardTypeString] owner:self]; [[NSPasteboard generalPasteboard] setString:variable.addressFormula forType:NSPasteboardTypeString]; }]; diff --git a/Bit Slicer/ZGVariableController.h b/Bit Slicer/ZGVariableController.h index 42491bf80..446a5dde7 100644 --- a/Bit Slicer/ZGVariableController.h +++ b/Bit Slicer/ZGVariableController.h @@ -83,8 +83,8 @@ typedef struct - (void)relativizeVariables:(NSArray *)variables; + (ZGMachBinaryAnnotationInfo)machBinaryAnnotationInfoForProcess:(ZGProcess *)process; -+ (void)annotateVariables:(NSArray *)variables annotationInfo:(ZGMachBinaryAnnotationInfo)annotationInfo process:(ZGProcess *)process symbols:(BOOL)symbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler; -+ (void)annotateVariables:(NSArray *)variables process:(ZGProcess *)process symbols:(BOOL)requiresSymbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler; ++ (void)annotateVariables:(NSArray *)variables annotationInfo:(ZGMachBinaryAnnotationInfo)annotationInfo process:(ZGProcess *)process variableController:(nullable ZGVariableController *)variableController symbols:(BOOL)symbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler; ++ (void)annotateVariables:(NSArray *)variables process:(ZGProcess *)process variableController:(nullable ZGVariableController *)variableController symbols:(BOOL)requiresSymbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler; - (void)editVariables:(NSArray *)variables newValues:(NSArray *)newValues; - (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddressFormula; diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index afcc96eca..b3e488e24 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -1038,7 +1038,7 @@ - (void)relativizeVariables:(NSArray *)variables { ZGDocumentWindowController *windowController = _windowController; - [[self class] annotateVariables:variables process:windowController.currentProcess symbols:YES async:YES completionHandler:^{ + [[self class] annotateVariables:variables process:windowController.currentProcess variableController:windowController.variableController symbols:YES async:YES completionHandler:^{ NSString *actionName = (variables.count == 1) ? ZGLocalizedStringFromVariableActionsTable(@"undoRelativizeSingleVariable") : ZGLocalizedStringFromVariableActionsTable(@"undoRelativizeMultipleVariables"); windowController.undoManager.actionName = actionName; @@ -1046,13 +1046,19 @@ - (void)relativizeVariables:(NSArray *)variables }]; } -+ (NSString *)relativizeVariable:(ZGVariable * __unsafe_unretained)variable withMachBinaries:(NSArray *)machBinaries filePathDictionary:(NSDictionary *)machFilePathDictionary process:(ZGProcess *)process failedImages:(NSMutableArray *)failedImages getAddress:(ZGMemoryAddress *)outVariableAddress ++ (NSString *)relativizeVariable:(ZGVariable * __unsafe_unretained)variable withMachBinaries:(NSArray *)machBinaries filePathDictionary:(NSDictionary *)machFilePathDictionary process:(ZGProcess *)process variableController:(ZGVariableController *)variableController failedImages:(NSMutableArray *)failedImages getAddress:(ZGMemoryAddress *)outVariableAddress { ZGMemoryAddress variableAddress; - BOOL isIndirectVariable = variable.usesDynamicPointerAddress; - if (isIndirectVariable) + BOOL isIndirectVariable; + if (variable.usesDynamicLabelAddress) { - if (![ZGCalculator extractIndirectBaseAddress:&variableAddress expression:variable.addressFormula process:process failedImages:failedImages]) + // It's not obvious if a variable that uses a label is indirect or not, so we will need + // to try computing the indirect base address to find out + isIndirectVariable = [ZGCalculator extractIndirectBaseAddress:&variableAddress expression:variable.addressFormula process:process variableController:variableController failedImages:failedImages]; + } + else if (variable.usesDynamicPointerAddress) + { + if (![ZGCalculator extractIndirectBaseAddress:&variableAddress expression:variable.addressFormula process:process variableController:variableController failedImages:failedImages]) { if (outVariableAddress != NULL) { @@ -1060,10 +1066,13 @@ + (NSString *)relativizeVariable:(ZGVariable * __unsafe_unretained)variable with } return nil; } + + isIndirectVariable = YES; } else { variableAddress = variable.address; + isIndirectVariable = NO; } if (outVariableAddress != NULL) @@ -1181,7 +1190,7 @@ - (void)annotateVariablesAutomatically:(NSArray *)variables proces } // Re-annotate the variables - [[self class] annotateVariables:variablesToAnnotate process:process symbols:YES async:YES completionHandler:^{ + [[self class] annotateVariables:variablesToAnnotate process:process variableController:self symbols:YES async:YES completionHandler:^{ [windowController.variablesTableView reloadData]; }]; } @@ -1211,14 +1220,14 @@ + (ZGMachBinaryAnnotationInfo)machBinaryAnnotationInfoForProcess:(ZGProcess *)pr return annotationInfo; } -+ (void)annotateVariables:(NSArray *)variables process:(ZGProcess *)process symbols:(BOOL)requiresSymbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler ++ (void)annotateVariables:(NSArray *)variables process:(ZGProcess *)process variableController:(ZGVariableController *)variableController symbols:(BOOL)requiresSymbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler { ZGMachBinaryAnnotationInfo annotationInfo = {0}; - [self annotateVariables:variables annotationInfo:annotationInfo process:process symbols:requiresSymbols async:async completionHandler:completionHandler]; + [self annotateVariables:variables annotationInfo:annotationInfo process:process variableController:variableController symbols:requiresSymbols async:async completionHandler:completionHandler]; } -+ (void)annotateVariables:(NSArray *)variables annotationInfo:(ZGMachBinaryAnnotationInfo)annotationInfo process:(ZGProcess *)process symbols:(BOOL)requiresSymbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler ++ (void)annotateVariables:(NSArray *)variables annotationInfo:(ZGMachBinaryAnnotationInfo)annotationInfo process:(ZGProcess *)process variableController:(ZGVariableController *)variableController symbols:(BOOL)requiresSymbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler { ZGMemoryMap processTask = process.processTask; NSUInteger capacity = variables.count; @@ -1232,7 +1241,7 @@ + (void)annotateVariables:(NSArray *)variables annotationInfo:(ZGM for (ZGVariable *variable in variables) { ZGMemoryAddress variableAddress; - NSString *staticDescription = [self relativizeVariable:variable withMachBinaries:machBinaries filePathDictionary:machFilePathDictionary process:process failedImages:failedImages getAddress:&variableAddress]; + NSString *staticDescription = [self relativizeVariable:variable withMachBinaries:machBinaries filePathDictionary:machFilePathDictionary process:process variableController:variableController failedImages:failedImages getAddress:&variableAddress]; [variableAddresses addObject:@(variableAddress)]; From 5229f56814f0381673aef4bcce1347397beb6ded Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 07:24:30 -0700 Subject: [PATCH 09/26] Show dependent labels in annotated variable description Dependent labels are only shown if there are no assigned labels. --- Bit Slicer/ZGCalculator.h | 2 + Bit Slicer/ZGCalculator.m | 74 +++++++++++++++++++++++++++++++ Bit Slicer/ZGVariableController.m | 15 ++++++- 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/Bit Slicer/ZGCalculator.h b/Bit Slicer/ZGCalculator.h index 14a57d391..51219479b 100644 --- a/Bit Slicer/ZGCalculator.h +++ b/Bit Slicer/ZGCalculator.h @@ -59,6 +59,8 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression:(NSString *)initialExpression process:(ZGProcess * __unsafe_unretained)process variableController:(nullable ZGVariableController * __unsafe_unretained)variableController failedImages:(NSMutableArray * __unsafe_unretained)failedImages; ++ (nullable NSString *)extractFirstDependentLabelFromExpression:(NSString *)expression; + + (BOOL)parseLinearExpression:(NSString *)linearExpression andGetAdditiveConstant:(NSString * _Nullable * _Nonnull)additiveConstantString multiplicateConstant:(NSString *_Nullable * _Nonnull)multiplicativeConstantString; + (nullable NSString *)evaluateExpression:(NSString *)expression; diff --git a/Bit Slicer/ZGCalculator.m b/Bit Slicer/ZGCalculator.m index b26b155bd..5f29f517d 100644 --- a/Bit Slicer/ZGCalculator.m +++ b/Bit Slicer/ZGCalculator.m @@ -880,6 +880,80 @@ + (BOOL)extractIndirectBaseAddress:(ZGMemoryAddress *)outBaseAddress expression: return YES; } ++ (nullable NSString *)_extractFirstDependentLabelFromExpression:(DDExpression *)expression +{ + switch (expression.expressionType) + { + case DDExpressionTypeFunction: + { + if ([expression.function isEqualToString:ZGFindLabelFunction]) + { + if (expression.arguments.count != 1) + { + return nil; + } + + DDExpression *argumentExpression1 = expression.arguments[0]; + if (argumentExpression1.expressionType != DDExpressionTypeVariable) + { + return nil; + } + + return argumentExpression1.variable; + } + + if (expression.arguments.count != 2) + { + return nil; + } + + DDExpression *argumentExpression1 = expression.arguments[0]; + DDExpression *argumentExpression2 = expression.arguments[1]; + + if (argumentExpression1.expressionType == DDExpressionTypeFunction && [argumentExpression1.function isEqualToString:ZGFindLabelFunction]) + { + return [self _extractFirstDependentLabelFromExpression:argumentExpression1]; + } + + if (argumentExpression2.expressionType == DDExpressionTypeFunction && [argumentExpression2.function isEqualToString:ZGFindLabelFunction]) + { + return [self _extractFirstDependentLabelFromExpression:argumentExpression2]; + } + + if (argumentExpression1.expressionType == DDExpressionTypeFunction) + { + NSString *dependentLabelCandidate1 = [self _extractFirstDependentLabelFromExpression:argumentExpression1]; + if (dependentLabelCandidate1 != nil) + { + return dependentLabelCandidate1; + } + } + + if (argumentExpression2.expressionType == DDExpressionTypeFunction) + { + return [self _extractFirstDependentLabelFromExpression:argumentExpression1]; + } + + return nil; + } + case DDExpressionTypeVariable: + case DDExpressionTypeNumber: + return nil; + } +} + ++ (nullable NSString *)extractFirstDependentLabelFromExpression:(NSString *)initialExpression +{ + NSError *expressionError = NULL; + DDExpression *expression = [DDExpression expressionFromString:initialExpression error:&expressionError]; + if (expression == nil) + { + return nil; + } + + return [self _extractFirstDependentLabelFromExpression:expression]; +} + + (BOOL)isValidExpression:(NSString *)expression { return [[expression stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] > 0; diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index b3e488e24..9b7d31393 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -1307,7 +1307,20 @@ + (void)annotateVariables:(NSArray *)variables annotationInfo:(ZGM NSString *label = variable.label; NSMutableArray *validDescriptionComponents = [NSMutableArray array]; - if (label.length > 0) [validDescriptionComponents addObject:[NSString stringWithFormat:@"Label %@", label]]; + if (label.length > 0) + { + [validDescriptionComponents addObject:[NSString stringWithFormat:@"Label %@", label]]; + } + else if (variable.usesDynamicLabelAddress) + { + NSString *dependentLabel = [ZGCalculator extractFirstDependentLabelFromExpression:variable.addressFormula]; + + if (dependentLabel != nil) + { + [validDescriptionComponents addObject:[NSString stringWithFormat:@"→ Label %@", dependentLabel]]; + } + } + if (symbol.length > 0) [validDescriptionComponents addObject:symbol]; if (staticDescription != nil) [validDescriptionComponents addObject:staticDescription]; if (userTagDescription != nil) [validDescriptionComponents addObject:userTagDescription]; From 4c23c06ecc6a7ec9901c2e62ae26e99b7cb505fb Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 09:05:29 -0700 Subject: [PATCH 10/26] Update other variable annotations when label/address changes --- Bit Slicer/ZGVariableController.m | 50 +++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index 9b7d31393..8cd0efc87 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -519,7 +519,7 @@ - (void)addVariable:(id)sender atRowIndexes:[NSIndexSet indexSetWithIndex:0]]; if (variable.type != ZGScript) { - [self annotateVariableAutomatically:variable process:windowController.currentProcess]; + [self annotateVariablesAutomatically:@[variable] process:windowController.currentProcess]; } } @@ -984,7 +984,26 @@ - (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddres } variable.finishedEvaluatingDynamicAddress = NO; - [self annotateVariableAutomatically:variable process:windowController.currentProcess]; + NSMutableArray *variablesToAnnotate = [NSMutableArray arrayWithObject:variable]; + if (variable.label.length > 0) + { + // Other variables may be referencing this variable + // We will want to update their annotations too + for (ZGVariable *otherVariable in _documentData.variables) + { + if (otherVariable == variable) + { + continue; + } + + if (otherVariable.usesDynamicLabelAddress) + { + [variablesToAnnotate addObject:otherVariable]; + } + } + } + + [self annotateVariablesAutomatically:variablesToAnnotate process:windowController.currentProcess]; [windowController updateSearchAddressOptions]; } @@ -1014,7 +1033,22 @@ - (void)editVariables:(NSArray *)variables requestedLabels:(NSArra } // Re-annotate the variables so the labels are in the descriptions - [self annotateVariablesAutomatically:variables process:windowController.currentProcess]; + // Also annotate other variables that may be referencing these edited variables + NSMutableOrderedSet *variablesToAnnotate = [NSMutableOrderedSet orderedSetWithArray:variables]; + for (ZGVariable *otherVariable in _documentData.variables) + { + if ([variablesToAnnotate containsObject:otherVariable]) + { + continue; + } + + if (otherVariable.usesDynamicLabelAddress) + { + [variablesToAnnotate addObject:otherVariable]; + } + } + + [self annotateVariablesAutomatically:variablesToAnnotate.array process:windowController.currentProcess]; } #pragma mark Relativizing Variable Addresses @@ -1054,7 +1088,10 @@ + (NSString *)relativizeVariable:(ZGVariable * __unsafe_unretained)variable with { // It's not obvious if a variable that uses a label is indirect or not, so we will need // to try computing the indirect base address to find out - isIndirectVariable = [ZGCalculator extractIndirectBaseAddress:&variableAddress expression:variable.addressFormula process:process variableController:variableController failedImages:failedImages]; + ZGMemoryAddress baseAddress = 0x0; + isIndirectVariable = [ZGCalculator extractIndirectBaseAddress:&baseAddress expression:variable.addressFormula process:process variableController:variableController failedImages:failedImages]; + + variableAddress = baseAddress; } else if (variable.usesDynamicPointerAddress) { @@ -1195,11 +1232,6 @@ - (void)annotateVariablesAutomatically:(NSArray *)variables proces }]; } -- (void)annotateVariableAutomatically:(ZGVariable *)variable process:(ZGProcess *)process -{ - [self annotateVariablesAutomatically:@[variable] process:process]; -} - + (ZGMachBinaryAnnotationInfo)machBinaryAnnotationInfoForProcess:(ZGProcess *)process { NSArray *machBinaries = [ZGMachBinary machBinariesInProcess:process]; From cb78ef50d264216fa01050628196c98ee268e406 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 14:10:07 -0700 Subject: [PATCH 11/26] Fix logic for retrieving variable address for relativization --- Bit Slicer/ZGVariableController.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index 8cd0efc87..556b4851b 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -1091,7 +1091,14 @@ + (NSString *)relativizeVariable:(ZGVariable * __unsafe_unretained)variable with ZGMemoryAddress baseAddress = 0x0; isIndirectVariable = [ZGCalculator extractIndirectBaseAddress:&baseAddress expression:variable.addressFormula process:process variableController:variableController failedImages:failedImages]; - variableAddress = baseAddress; + if (isIndirectVariable) + { + variableAddress = baseAddress; + } + else + { + variableAddress = variable.address; + } } else if (variable.usesDynamicPointerAddress) { From f25af6ea660b681b85e238422521451fc10f063c Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 14:15:54 -0700 Subject: [PATCH 12/26] Handle not changing variable labels --- Bit Slicer/ZGEditLabelWindowController.m | 28 ++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index 09e81b919..21bed9491 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -121,18 +121,38 @@ - (IBAction)editVariablesLabels:(id)__unused sender NSRange ordinalRange = [newRequestedLabel rangeOfString:@"$n" options:NSBackwardsSearch | NSLiteralSearch]; - NSUInteger variableIndex; + BOOL changedVariables = NO; NSUInteger variableCount = _variables.count; - for (variableIndex = 0; variableIndex < variableCount; variableIndex++) + for (NSUInteger variableIndex = 0; variableIndex < variableCount; variableIndex++) { + NSString *newLabel; if (ordinalRange.location != NSNotFound) { - [requestedLabels addObject:[newRequestedLabel stringByReplacingCharactersInRange:ordinalRange withString:[NSString stringWithFormat:@"%lu", variableIndex]]]; + newLabel = [newRequestedLabel stringByReplacingCharactersInRange:ordinalRange withString:[NSString stringWithFormat:@"%lu", variableIndex]]; + + [requestedLabels addObject:newLabel]; } else { - [requestedLabels addObject:newRequestedLabel]; + newLabel = newRequestedLabel; } + + if (![_variables[variableIndex].label isEqualToString:newLabel]) + { + changedVariables = YES; + } + + [requestedLabels addObject:newLabel]; + } + + if (!changedVariables) + { + // Nothing to change here + NSWindow *window = ZGUnwrapNullableObject(self.window); + [NSApp endSheet:window]; + [window close]; + + return; } NSSet *requestedLabelsSet = [NSSet setWithArray:requestedLabels]; From 7ea6bc9384b18d03a4dbc644b22cc02ea7d1b1e2 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 14:36:21 -0700 Subject: [PATCH 13/26] Add title for editing variable label(s) --- Bit Slicer/ZGDocumentWindowController.m | 9 +++++++-- .../en.lproj/[Code] Search Document.strings | 6 ++++++ .../es.lproj/[Code] Search Document.strings | Bin 15872 -> 16314 bytes .../ru.lproj/[Code] Search Document.strings | 6 ++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Bit Slicer/ZGDocumentWindowController.m b/Bit Slicer/ZGDocumentWindowController.m index 196ad2b29..a4a0559bf 100644 --- a/Bit Slicer/ZGDocumentWindowController.m +++ b/Bit Slicer/ZGDocumentWindowController.m @@ -1397,14 +1397,19 @@ - (BOOL)validateUserInterfaceItem:(id )userInterfa else if (menuItem.action == @selector(requestEditingVariableLabel:)) { + menuItem.title = ([self selectedVariables].count != 1) ? ZGLocalizableSearchDocumentString(@"editMultipleVariableLabelsTitle") : ZGLocalizableSearchDocumentString(@"editSingleVariableLabelTitle"); + if ([_searchController canCancelTask] || [self selectedVariables].count < 1 || !self.currentProcess.valid) { return NO; } - if ([(ZGVariable *)[self selectedVariables][0] type] == ZGScript) + for (ZGVariable *variable in [self selectedVariables]) { - return NO; + if (variable.type == ZGScript) + { + return NO; + } } } diff --git a/Bit Slicer/en.lproj/[Code] Search Document.strings b/Bit Slicer/en.lproj/[Code] Search Document.strings index 0f2c9e253..e42cd276b 100644 --- a/Bit Slicer/en.lproj/[Code] Search Document.strings +++ b/Bit Slicer/en.lproj/[Code] Search Document.strings @@ -85,6 +85,12 @@ /* Edit multiple variable values menu item title */ "editMultipleVariableValuesTitle" = "Edit Variable Values…"; +/* Edit single variable label menu item title */ +"editSingleVariableLabelTitle" = "Edit Variable Label…"; + +/* Edit multiple variable labels menu item title */ +"editMultipleVariableLabelsTitle" = "Edit Variable Labels…"; + /* Edit single variable size menu item title */ "editSingleVariableSizeTitle" = "Edit Variable Size…"; diff --git a/Bit Slicer/es.lproj/[Code] Search Document.strings b/Bit Slicer/es.lproj/[Code] Search Document.strings index dbe1b6f232916ce752baa558a9d9a3f3054d7efe..e4d87e783e7daa471ad56a92f3d8375ba2736586 100644 GIT binary patch delta 124 zcmZpu*;T*6M3gg!A(0`8A(bI#a-y(5rw^PrQB-!a6Tc9*0s}(quBbgXTs=cEP>1p4 f1`!2rxC)>cHhmYxgeU6>YfY9B Date: Sun, 5 May 2024 14:43:00 -0700 Subject: [PATCH 14/26] Localize edit variable labels menu item title --- .../es.lproj/[Code] Search Document.strings | Bin 16314 -> 16348 bytes .../ru.lproj/[Code] Search Document.strings | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Bit Slicer/es.lproj/[Code] Search Document.strings b/Bit Slicer/es.lproj/[Code] Search Document.strings index e4d87e783e7daa471ad56a92f3d8375ba2736586..03398d060545f23606c60778e6effb310f7e990d 100644 GIT binary patch delta 94 zcmdm0f2V%KCQ->mh9U+9hE#?UhD?S+hEgyq5h#)}*-=<@@-Gpo$#NnplljEjq_L|k ThO6z75Ssizlxy=ju{Rn3$e$U+ delta 54 ycmcapzpH-3Ceg`G{6gFc3_c8r3`q>B3^|kUiyj4u@gj*a6az)2H-8X&qX7Wn1`$30 diff --git a/Bit Slicer/ru.lproj/[Code] Search Document.strings b/Bit Slicer/ru.lproj/[Code] Search Document.strings index b9225201d..f5ad51934 100644 --- a/Bit Slicer/ru.lproj/[Code] Search Document.strings +++ b/Bit Slicer/ru.lproj/[Code] Search Document.strings @@ -86,10 +86,10 @@ "editMultipleVariableValuesTitle" = "Изменить значения…"; /* Edit single variable label menu item title */ -"editSingleVariableLabelTitle" = "Edit Variable Label…"; +"editSingleVariableLabelTitle" = "Изменить метку переменной…"; /* Edit multiple variable labels menu item title */ -"editMultipleVariableLabelsTitle" = "Edit Variable Labels…"; +"editMultipleVariableLabelsTitle" = "Изменить метки переменных…"; /* Edit single variable size menu item title */ "editSingleVariableSizeTitle" = "Изменить размер переменной…"; From 2d7689d0946d7a3d699c1d34315044bbcab86202 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 14:56:57 -0700 Subject: [PATCH 15/26] Add label descriptions for editing variable address --- Bit Slicer/en.lproj/Edit Address Dialog.strings | 4 ++-- Bit Slicer/es.lproj/Edit Address Dialog.strings | 4 ++-- Bit Slicer/ru.lproj/Edit Address Dialog.strings | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Bit Slicer/en.lproj/Edit Address Dialog.strings b/Bit Slicer/en.lproj/Edit Address Dialog.strings index d34a5489a..b5978a07e 100644 --- a/Bit Slicer/en.lproj/Edit Address Dialog.strings +++ b/Bit Slicer/en.lproj/Edit Address Dialog.strings @@ -8,5 +8,5 @@ /* Class = "NSButtonCell"; title = "OK"; ObjectID = "Ln7-Xd-Cjr"; */ "Ln7-Xd-Cjr.title" = "OK"; -/* Class = "NSTextFieldCell"; title = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable\nsymbol(\"symbol\") will be substituted with the address of symbol."; ObjectID = "yr8-jR-NWj"; */ -"yr8-jR-NWj.title" = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable.\nsymbol(\"symbol\") will be substituted with the address of symbol."; +/* Class = "NSTextFieldCell"; title = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable.\nsymbol(\"symbol\") will be substituted with the address of symbol.\nlabel(\"label\") will be substituted with the address of label."; ObjectID = "yr8-jR-NWj"; */ +"yr8-jR-NWj.title" = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable.\nsymbol(\"symbol\") will be substituted with the address of symbol.\nlabel(\"label\") will be substituted with the address of label."; diff --git a/Bit Slicer/es.lproj/Edit Address Dialog.strings b/Bit Slicer/es.lproj/Edit Address Dialog.strings index aa6a0aef2..66a8b9037 100644 --- a/Bit Slicer/es.lproj/Edit Address Dialog.strings +++ b/Bit Slicer/es.lproj/Edit Address Dialog.strings @@ -8,5 +8,5 @@ /* Class = "NSButtonCell"; title = "OK"; ObjectID = "Ln7-Xd-Cjr"; */ "Ln7-Xd-Cjr.title" = "OK"; -/* Class = "NSTextFieldCell"; title = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable\nsymbol(\"symbol\") will be substituted with the address of symbol."; ObjectID = "yr8-jR-NWj"; */ -"yr8-jR-NWj.title" = "[Dirección] será sustituido con el valor del puntero leído en la dirección.\nbase(\"executable\") será sustituido con la dirección del ejecutable.\nbase(\"symbol\") será sustituido con la dirección del símbolo."; +/* Class = "NSTextFieldCell"; title = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable.\nsymbol(\"symbol\") will be substituted with the address of symbol.\nlabel(\"label\") will be substituted with the address of label."; ObjectID = "yr8-jR-NWj"; */ +"yr8-jR-NWj.title" = "[Dirección] será sustituido con el valor del puntero leído en la dirección.\nbase(\"executable\") será sustituido con la dirección del ejecutable.\nbase(\"symbol\") será sustituido con la dirección del símbolo.\nlabel(\"label\") será reemplazada por la dirección de la etiqueta."; diff --git a/Bit Slicer/ru.lproj/Edit Address Dialog.strings b/Bit Slicer/ru.lproj/Edit Address Dialog.strings index 2df6da41f..6ab1ec960 100644 --- a/Bit Slicer/ru.lproj/Edit Address Dialog.strings +++ b/Bit Slicer/ru.lproj/Edit Address Dialog.strings @@ -8,5 +8,5 @@ /* Class = "NSButtonCell"; title = "OK"; ObjectID = "Ln7-Xd-Cjr"; */ "Ln7-Xd-Cjr.title" = "OK"; -/* Class = "NSTextFieldCell"; title = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable\nsymbol(\"symbol\") will be substituted with the address of symbol."; ObjectID = "yr8-jR-NWj"; */ -"yr8-jR-NWj.title" = "[address] будет заменен на значение указателя чтения по адресу.\nbase(\"executable\") будет заменен на адрес исполняемого файла.\nbase(\"symbol\") будет заменен на адрес символ файла."; +/* Class = "NSTextFieldCell"; title = "[address] will be substituted with the pointer value read at address. \nbase(\"executable\") will be substituted with the address of executable.\nsymbol(\"symbol\") will be substituted with the address of symbol.\nlabel(\"label\") will be substituted with the address of label."; ObjectID = "yr8-jR-NWj"; */ +"yr8-jR-NWj.title" = "[address] будет заменен на значение указателя чтения по адресу.\nbase(\"executable\") будет заменен на адрес исполняемого файла.\nbase(\"symbol\") будет заменен на адрес символ файла.\nlabel(\"label\") будет заменен адресом метки."; From e9c9cf63e2b1474906bccdaf2fbef189b4881626 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 15:11:34 -0700 Subject: [PATCH 16/26] Add explanation for $n when editing label --- Bit Slicer/Edit Label Dialog.xib | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Bit Slicer/Edit Label Dialog.xib b/Bit Slicer/Edit Label Dialog.xib index 5a86f5f23..9082f0d60 100644 --- a/Bit Slicer/Edit Label Dialog.xib +++ b/Bit Slicer/Edit Label Dialog.xib @@ -17,14 +17,14 @@ - + - + - + @@ -35,7 +35,7 @@ - + @@ -43,7 +43,7 @@ + + + + + + + + - + + - + + - + From 2ae5273395e33aedd3b24864f8c8935a4ac2bd91 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 15:17:19 -0700 Subject: [PATCH 17/26] Add localizations for editing variable label --- Bit Slicer.xcodeproj/project.pbxproj | 23 +++++++++++++++---- .../{ => Base.lproj}/Edit Label Dialog.xib | 0 Bit Slicer/en.lproj/Edit Label Dialog.strings | 12 ++++++++++ Bit Slicer/es.lproj/Edit Label Dialog.strings | 12 ++++++++++ Bit Slicer/ru.lproj/Edit Label Dialog.strings | 12 ++++++++++ 5 files changed, 55 insertions(+), 4 deletions(-) rename Bit Slicer/{ => Base.lproj}/Edit Label Dialog.xib (100%) create mode 100644 Bit Slicer/en.lproj/Edit Label Dialog.strings create mode 100644 Bit Slicer/es.lproj/Edit Label Dialog.strings create mode 100644 Bit Slicer/ru.lproj/Edit Label Dialog.strings diff --git a/Bit Slicer.xcodeproj/project.pbxproj b/Bit Slicer.xcodeproj/project.pbxproj index e2d39936b..4ba3ec04c 100644 --- a/Bit Slicer.xcodeproj/project.pbxproj +++ b/Bit Slicer.xcodeproj/project.pbxproj @@ -16,7 +16,7 @@ 7208450724E0851000F3D449 /* Python.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 7208450524E084F400F3D449 /* Python.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 720C192C271B4F9700740C8E /* ZGSearchProtectionMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */; }; 72130FC82BE6836A00691AED /* ZGEditLabelWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */; }; - 72130FC92BE6836A00691AED /* Edit Label Dialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */; }; + 72130FCC2BE83BF400691AED /* Edit Label Dialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 72130FCB2BE83BF400691AED /* Edit Label Dialog.xib */; }; 721594FE24DF36360027F600 /* HexFiend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 721594FD24DF36360027F600 /* HexFiend.framework */; }; 7215950024DF36520027F600 /* HexFiend.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 721594FD24DF36360027F600 /* HexFiend.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 721B3C4D2AED913200F85660 /* ZGSearchProtectionMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */; }; @@ -323,7 +323,10 @@ 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGSearchProtectionMode.m; path = "Bit Slicer/ZGSearchProtectionMode.m"; sourceTree = ""; }; 72130FC52BE6836A00691AED /* ZGEditLabelWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGEditLabelWindowController.h; path = "Bit Slicer/ZGEditLabelWindowController.h"; sourceTree = ""; }; 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGEditLabelWindowController.m; path = "Bit Slicer/ZGEditLabelWindowController.m"; sourceTree = ""; }; - 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "Edit Label Dialog.xib"; path = "Bit Slicer/Edit Label Dialog.xib"; sourceTree = ""; }; + 72130FCA2BE83BF400691AED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Base.lproj/Edit Label Dialog.xib"; sourceTree = ""; }; + 72130FCE2BE83BF900691AED /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = "en.lproj/Edit Label Dialog.strings"; sourceTree = ""; }; + 72130FD02BE83BFB00691AED /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/Edit Label Dialog.strings"; sourceTree = ""; }; + 72130FD22BE83BFC00691AED /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = "es.lproj/Edit Label Dialog.strings"; sourceTree = ""; }; 721594FD24DF36360027F600 /* HexFiend.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HexFiend.framework; path = deps/HexFiend/HexFiend.framework; sourceTree = ""; }; 721594FF24DF36460027F600 /* HFLineCountingView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HFLineCountingView.h; path = deps/HexFiend/HFLineCountingView.h; sourceTree = ""; }; 722CAA5519AD4AED009C6AAE /* hotkey.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = hotkey.png; path = "Bit Slicer/preficons/hotkey.png"; sourceTree = ""; }; @@ -998,7 +1001,7 @@ 726CA2B219606DA000A6AD40 /* Logs Window.xib */, 726CA2CA19606E1D00A6AD40 /* Edit Value Dialog.xib */, 726CA2CD19606E2200A6AD40 /* Edit Address Dialog.xib */, - 72130FC72BE6836A00691AED /* Edit Label Dialog.xib */, + 72130FCB2BE83BF400691AED /* Edit Label Dialog.xib */, 726CA2D019606E2600A6AD40 /* Edit Size Dialog.xib */, 726CA2D319606E2900A6AD40 /* Edit Description Dialog.xib */, 726CA2D619606E3100A6AD40 /* Search Options.xib */, @@ -1588,7 +1591,7 @@ 724A9F2819A1657500E72C9D /* [Code] Script Preferences.strings in Resources */, 726CA2CB19606E2200A6AD40 /* Edit Address Dialog.xib in Resources */, 724A9F4E19A8EDD700E72C9D /* [Code] Logger Window.stringsdict in Resources */, - 72130FC92BE6836A00691AED /* Edit Label Dialog.xib in Resources */, + 72130FCC2BE83BF400691AED /* Edit Label Dialog.xib in Resources */, 726CA2D719606E3800A6AD40 /* Watch Variable Dialog.xib in Resources */, 722CAA5919AD4AED009C6AAE /* hotkey.png in Resources */, 77F115AE17D2EAE4009E002A /* bitslicerdocicon.iconset in Resources */, @@ -1834,6 +1837,18 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 72130FCB2BE83BF400691AED /* Edit Label Dialog.xib */ = { + isa = PBXVariantGroup; + children = ( + 72130FCA2BE83BF400691AED /* Base */, + 72130FCE2BE83BF900691AED /* en */, + 72130FD02BE83BFB00691AED /* ru */, + 72130FD22BE83BFC00691AED /* es */, + ); + name = "Edit Label Dialog.xib"; + path = "Bit Slicer"; + sourceTree = ""; + }; 7231440C19C6230F00FBE342 /* [Code] Watch Variable.stringsdict */ = { isa = PBXVariantGroup; children = ( diff --git a/Bit Slicer/Edit Label Dialog.xib b/Bit Slicer/Base.lproj/Edit Label Dialog.xib similarity index 100% rename from Bit Slicer/Edit Label Dialog.xib rename to Bit Slicer/Base.lproj/Edit Label Dialog.xib diff --git a/Bit Slicer/en.lproj/Edit Label Dialog.strings b/Bit Slicer/en.lproj/Edit Label Dialog.strings new file mode 100644 index 000000000..16e1d8a82 --- /dev/null +++ b/Bit Slicer/en.lproj/Edit Label Dialog.strings @@ -0,0 +1,12 @@ + +/* Class = "NSTextFieldCell"; title = "$n will be substituted with an incrementing number."; ObjectID = "DIb-kM-KCk"; */ +"DIb-kM-KCk.title" = "$n will be substituted with an incrementing number."; + +/* Class = "NSButtonCell"; title = "OK"; ObjectID = "UNH-Xz-JjJ"; */ +"UNH-Xz-JjJ.title" = "OK"; + +/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "Uwq-TR-2ZJ"; */ +"Uwq-TR-2ZJ.title" = "Cancel"; + +/* Class = "NSTextFieldCell"; title = "Label:"; ObjectID = "tdw-96-OLh"; */ +"tdw-96-OLh.title" = "Label:"; diff --git a/Bit Slicer/es.lproj/Edit Label Dialog.strings b/Bit Slicer/es.lproj/Edit Label Dialog.strings new file mode 100644 index 000000000..5cc97bfb0 --- /dev/null +++ b/Bit Slicer/es.lproj/Edit Label Dialog.strings @@ -0,0 +1,12 @@ + +/* Class = "NSTextFieldCell"; title = "$n will be substituted with an incrementing number."; ObjectID = "DIb-kM-KCk"; */ +"DIb-kM-KCk.title" = "$n se sustituirá por un número creciente."; + +/* Class = "NSButtonCell"; title = "OK"; ObjectID = "UNH-Xz-JjJ"; */ +"UNH-Xz-JjJ.title" = "OK"; + +/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "Uwq-TR-2ZJ"; */ +"Uwq-TR-2ZJ.title" = "Cancelar"; + +/* Class = "NSTextFieldCell"; title = "Label:"; ObjectID = "tdw-96-OLh"; */ +"tdw-96-OLh.title" = "Etiqueta:"; diff --git a/Bit Slicer/ru.lproj/Edit Label Dialog.strings b/Bit Slicer/ru.lproj/Edit Label Dialog.strings new file mode 100644 index 000000000..7956bef8e --- /dev/null +++ b/Bit Slicer/ru.lproj/Edit Label Dialog.strings @@ -0,0 +1,12 @@ + +/* Class = "NSTextFieldCell"; title = "$n will be substituted with an incrementing number."; ObjectID = "DIb-kM-KCk"; */ +"DIb-kM-KCk.title" = "$n будет заменен возрастающим числом."; + +/* Class = "NSButtonCell"; title = "OK"; ObjectID = "UNH-Xz-JjJ"; */ +"UNH-Xz-JjJ.title" = "OK"; + +/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "Uwq-TR-2ZJ"; */ +"Uwq-TR-2ZJ.title" = "Отмена"; + +/* Class = "NSTextFieldCell"; title = "Label:"; ObjectID = "tdw-96-OLh"; */ +"tdw-96-OLh.title" = "Этикетка:"; From cff4e595d2915cd8cfff8954a395bac6845f980d Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 15:33:11 -0700 Subject: [PATCH 18/26] Re-adjust edit variable label window based on multiple selection --- Bit Slicer/Base.lproj/Edit Label Dialog.xib | 2 ++ Bit Slicer/ZGDocumentWindowController.m | 8 +++---- Bit Slicer/ZGEditLabelWindowController.m | 26 +++++++++++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Bit Slicer/Base.lproj/Edit Label Dialog.xib b/Bit Slicer/Base.lproj/Edit Label Dialog.xib index 9082f0d60..d96b793b9 100644 --- a/Bit Slicer/Base.lproj/Edit Label Dialog.xib +++ b/Bit Slicer/Base.lproj/Edit Label Dialog.xib @@ -8,7 +8,9 @@ + + diff --git a/Bit Slicer/ZGDocumentWindowController.m b/Bit Slicer/ZGDocumentWindowController.m index a4a0559bf..ad042edc6 100644 --- a/Bit Slicer/ZGDocumentWindowController.m +++ b/Bit Slicer/ZGDocumentWindowController.m @@ -1935,10 +1935,10 @@ - (IBAction)requestEditingVariablesSize:(id)__unused sender - (IBAction)requestEditingVariableLabel:(id)sender { - if (_editLabelWindowController == nil) - { - _editLabelWindowController = [[ZGEditLabelWindowController alloc] initWithVariableController:_variableController]; - } + // We will always instantiate a new ZGEditLabelWindowController + // because its window view may differ based on if a single or + // multiple variable labels are being edited + _editLabelWindowController = [[ZGEditLabelWindowController alloc] initWithVariableController:_variableController]; [_editLabelWindowController requestEditingLabelsFromVariables:[self selectedVariables] attachedToWindow:ZGUnwrapNullableObject(self.window)]; } diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index 21bed9491..ae8019dfe 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -44,6 +44,8 @@ @implementation ZGEditLabelWindowController NSArray * _Nullable _variables; IBOutlet NSTextField *_labelTextField; + IBOutlet NSTextField *_multipleSelectionExplanationTextField; + IBOutlet NSButton *_cancelButton; } - (NSString *)windowNibName @@ -61,8 +63,30 @@ - (id)initWithVariableController:(ZGVariableController *)variableController return self; } +- (void)windowDidLoad +{ + if (_variables.count == 1) + { + [_multipleSelectionExplanationTextField removeFromSuperview]; + + NSLayoutConstraint *layoutConstraint = + [NSLayoutConstraint + constraintWithItem:_labelTextField + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationEqual + toItem:_cancelButton + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:-12.0]; + + [self.window.contentView addConstraint:layoutConstraint]; + } +} + - (void)requestEditingLabelsFromVariables:(NSArray *)variables attachedToWindow:(NSWindow *)parentWindow { + _variables = variables; + NSWindow *window = ZGUnwrapNullableObject([self window]); // ensure window is loaded ZGVariable *firstVariable = [variables objectAtIndex:0]; @@ -105,8 +129,6 @@ - (void)requestEditingLabelsFromVariables:(NSArray *)variables att [_labelTextField selectText:nil]; - _variables = variables; - [parentWindow beginSheet:window completionHandler:^(NSModalResponse __unused returnCode) { }]; } From 3f25ae4a2aec618db998c5a20b38d06e3b1bd92b Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 16:09:28 -0700 Subject: [PATCH 19/26] Fix issues with preventing duplicate variable labels --- Bit Slicer/ZGEditLabelWindowController.m | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index ae8019dfe..d49a8d3ac 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -135,7 +135,7 @@ - (void)requestEditingLabelsFromVariables:(NSArray *)variables att - (IBAction)editVariablesLabels:(id)__unused sender { - NSSet *usedLabels = _variableController.usedLabels; + NSMutableSet *usedLabels = [_variableController.usedLabels mutableCopy]; NSMutableArray *requestedLabels = [[NSMutableArray alloc] init]; @@ -151,8 +151,6 @@ - (IBAction)editVariablesLabels:(id)__unused sender if (ordinalRange.location != NSNotFound) { newLabel = [newRequestedLabel stringByReplacingCharactersInRange:ordinalRange withString:[NSString stringWithFormat:@"%lu", variableIndex]]; - - [requestedLabels addObject:newLabel]; } else { @@ -163,6 +161,12 @@ - (IBAction)editVariablesLabels:(id)__unused sender { changedVariables = YES; } + else + { + // If a label hasn't changed, we don't care about recording it + // usedLabels is later used to test we don't have duplicate labels + [usedLabels removeObject:newLabel]; + } [requestedLabels addObject:newLabel]; } From e9ec7e8f0fa65c722c223ccf6a862741684bdf4d Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 16:37:08 -0700 Subject: [PATCH 20/26] Add alert messages for invalid new labels --- Bit Slicer.xcodeproj/project.pbxproj | 16 ++++++++++++++++ Bit Slicer/ZGEditLabelWindowController.m | 17 ++++++++++++++++- .../en.lproj/[Code] Edit Variable Label.strings | 15 +++++++++++++++ .../es.lproj/[Code] Edit Variable Label.strings | 15 +++++++++++++++ .../ru.lproj/[Code] Edit Variable Label.strings | 15 +++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 Bit Slicer/en.lproj/[Code] Edit Variable Label.strings create mode 100644 Bit Slicer/es.lproj/[Code] Edit Variable Label.strings create mode 100644 Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings diff --git a/Bit Slicer.xcodeproj/project.pbxproj b/Bit Slicer.xcodeproj/project.pbxproj index 4ba3ec04c..ddbb6fd5a 100644 --- a/Bit Slicer.xcodeproj/project.pbxproj +++ b/Bit Slicer.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 720C192C271B4F9700740C8E /* ZGSearchProtectionMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */; }; 72130FC82BE6836A00691AED /* ZGEditLabelWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 72130FC62BE6836A00691AED /* ZGEditLabelWindowController.m */; }; 72130FCC2BE83BF400691AED /* Edit Label Dialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 72130FCB2BE83BF400691AED /* Edit Label Dialog.xib */; }; + 72130FD52BE84B4B00691AED /* [Code] Edit Variable Label.strings in Resources */ = {isa = PBXBuildFile; fileRef = 72130FD32BE84B4B00691AED /* [Code] Edit Variable Label.strings */; }; 721594FE24DF36360027F600 /* HexFiend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 721594FD24DF36360027F600 /* HexFiend.framework */; }; 7215950024DF36520027F600 /* HexFiend.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 721594FD24DF36360027F600 /* HexFiend.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 721B3C4D2AED913200F85660 /* ZGSearchProtectionMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 720C192B271B4F9700740C8E /* ZGSearchProtectionMode.m */; }; @@ -327,6 +328,9 @@ 72130FCE2BE83BF900691AED /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = "en.lproj/Edit Label Dialog.strings"; sourceTree = ""; }; 72130FD02BE83BFB00691AED /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/Edit Label Dialog.strings"; sourceTree = ""; }; 72130FD22BE83BFC00691AED /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = "es.lproj/Edit Label Dialog.strings"; sourceTree = ""; }; + 72130FD42BE84B4B00691AED /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = "Bit Slicer/en.lproj/[Code] Edit Variable Label.strings"; sourceTree = ""; }; + 72130FD62BE84B5B00691AED /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = "Bit Slicer/es.lproj/[Code] Edit Variable Label.strings"; sourceTree = ""; }; + 72130FD72BE84B6400691AED /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings"; sourceTree = ""; }; 721594FD24DF36360027F600 /* HexFiend.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HexFiend.framework; path = deps/HexFiend/HexFiend.framework; sourceTree = ""; }; 721594FF24DF36460027F600 /* HFLineCountingView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HFLineCountingView.h; path = deps/HexFiend/HFLineCountingView.h; sourceTree = ""; }; 722CAA5519AD4AED009C6AAE /* hotkey.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = hotkey.png; path = "Bit Slicer/preficons/hotkey.png"; sourceTree = ""; }; @@ -1034,6 +1038,7 @@ 724A9F1B19A1657500E72C9D /* [Code] Variable Actions.strings */, 724A9F3719A813D600E72C9D /* [Code] Edit Variable Value.strings */, 724A9F3A19A8173900E72C9D /* [Code] Edit Variable Size.strings */, + 72130FD32BE84B4B00691AED /* [Code] Edit Variable Label.strings */, 724A9F3D19A823C300E72C9D /* [Code] Search Document.strings */, 724A9F4F19A8F54600E72C9D /* [Code] Search Document.stringsdict */, 724A9F4019A85D3F00E72C9D /* [Code] Search Table.strings */, @@ -1616,6 +1621,7 @@ 722CAA5A19AD4AED009C6AAE /* hotkey@2x.png in Resources */, 726CA2B619606DD200A6AD40 /* Change Memory Protection Dialog.xib in Resources */, 724A9F3919A813D600E72C9D /* [Code] Edit Variable Value.strings in Resources */, + 72130FD52BE84B4B00691AED /* [Code] Edit Variable Label.strings in Resources */, 724A9F2919A1657500E72C9D /* [Code] Variable Actions.strings in Resources */, 724A9F1E19A1657500E72C9D /* [Code] Debugger Registers.strings in Resources */, 726CA2BF19606DF200A6AD40 /* Software Update View.xib in Resources */, @@ -1849,6 +1855,16 @@ path = "Bit Slicer"; sourceTree = ""; }; + 72130FD32BE84B4B00691AED /* [Code] Edit Variable Label.strings */ = { + isa = PBXVariantGroup; + children = ( + 72130FD42BE84B4B00691AED /* en */, + 72130FD62BE84B5B00691AED /* es */, + 72130FD72BE84B6400691AED /* ru */, + ); + name = "[Code] Edit Variable Label.strings"; + sourceTree = ""; + }; 7231440C19C6230F00FBE342 /* [Code] Watch Variable.stringsdict */ = { isa = PBXVariantGroup; children = ( diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index d49a8d3ac..d7c3b1313 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -145,6 +145,14 @@ - (IBAction)editVariablesLabels:(id)__unused sender BOOL changedVariables = NO; NSUInteger variableCount = _variables.count; + + if (ordinalRange.location == NSNotFound && variableCount > 1 && newRequestedLabel.length > 0) + { + ZGRunAlertPanelWithOKButton(NSLocalizedStringFromTable(@"requireUsingOrdinalAlertTitle", ZGEditLabelLocalizableTable, nil), NSLocalizedStringFromTable(@"requireUsingOrdinalAlertMessage", ZGEditLabelLocalizableTable, nil)); + + return; + } + for (NSUInteger variableIndex = 0; variableIndex < variableCount; variableIndex++) { NSString *newLabel; @@ -184,7 +192,14 @@ - (IBAction)editVariablesLabels:(id)__unused sender NSSet *requestedLabelsSet = [NSSet setWithArray:requestedLabels]; if ([usedLabels intersectsSet:requestedLabelsSet]) { - ZGRunAlertPanelWithOKButton(NSLocalizedStringFromTable(@"alreadyUsedLabelAlertTitle", ZGEditLabelLocalizableTable, nil), NSLocalizedStringFromTable(@"alreadyUsedLabelAlertMessage", ZGEditLabelLocalizableTable, nil)); + if (requestedLabels.count == 1) + { + ZGRunAlertPanelWithOKButton(NSLocalizedStringFromTable(@"alreadyUsedLabelAlertTitle", ZGEditLabelLocalizableTable, nil), [NSString stringWithFormat:NSLocalizedStringFromTable(@"alreadyUsedSingleLabelAlertMessageFormat", ZGEditLabelLocalizableTable, nil), requestedLabels.firstObject]); + } + else + { + ZGRunAlertPanelWithOKButton(NSLocalizedStringFromTable(@"alreadyUsedLabelAlertTitle", ZGEditLabelLocalizableTable, nil), NSLocalizedStringFromTable(@"alreadyUsedLabelAlertMessage", ZGEditLabelLocalizableTable, nil)); + } return; } diff --git a/Bit Slicer/en.lproj/[Code] Edit Variable Label.strings b/Bit Slicer/en.lproj/[Code] Edit Variable Label.strings new file mode 100644 index 000000000..f84e38a6d --- /dev/null +++ b/Bit Slicer/en.lproj/[Code] Edit Variable Label.strings @@ -0,0 +1,15 @@ + +/* Alert title indicating that the variable label is already in use */ +"alreadyUsedLabelAlertTitle" = "Label already in use"; + +/* Alert message indicating that a single variable label is already in use */ +"alreadyUsedSingleLabelAlertMessageFormat" = "The label %@ is already in use by another variable."; + +/* Alert message indicating that a single variable label is already in use */ +"alreadyUsedLabelAlertMessage" = "One of the supplied labels is already in use by another variable."; + +/* Alert title indicating that a label must use a number token */ +"requireUsingOrdinalAlertTitle" = "Label must include $n"; + +/* Alert message indicating that a label must use a number token */ +"requireUsingOrdinalAlertMessage" = "The label name must use $n when modifying multiple labels so each variable is assigned a different label."; diff --git a/Bit Slicer/es.lproj/[Code] Edit Variable Label.strings b/Bit Slicer/es.lproj/[Code] Edit Variable Label.strings new file mode 100644 index 000000000..f84e38a6d --- /dev/null +++ b/Bit Slicer/es.lproj/[Code] Edit Variable Label.strings @@ -0,0 +1,15 @@ + +/* Alert title indicating that the variable label is already in use */ +"alreadyUsedLabelAlertTitle" = "Label already in use"; + +/* Alert message indicating that a single variable label is already in use */ +"alreadyUsedSingleLabelAlertMessageFormat" = "The label %@ is already in use by another variable."; + +/* Alert message indicating that a single variable label is already in use */ +"alreadyUsedLabelAlertMessage" = "One of the supplied labels is already in use by another variable."; + +/* Alert title indicating that a label must use a number token */ +"requireUsingOrdinalAlertTitle" = "Label must include $n"; + +/* Alert message indicating that a label must use a number token */ +"requireUsingOrdinalAlertMessage" = "The label name must use $n when modifying multiple labels so each variable is assigned a different label."; diff --git a/Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings b/Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings new file mode 100644 index 000000000..f84e38a6d --- /dev/null +++ b/Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings @@ -0,0 +1,15 @@ + +/* Alert title indicating that the variable label is already in use */ +"alreadyUsedLabelAlertTitle" = "Label already in use"; + +/* Alert message indicating that a single variable label is already in use */ +"alreadyUsedSingleLabelAlertMessageFormat" = "The label %@ is already in use by another variable."; + +/* Alert message indicating that a single variable label is already in use */ +"alreadyUsedLabelAlertMessage" = "One of the supplied labels is already in use by another variable."; + +/* Alert title indicating that a label must use a number token */ +"requireUsingOrdinalAlertTitle" = "Label must include $n"; + +/* Alert message indicating that a label must use a number token */ +"requireUsingOrdinalAlertMessage" = "The label name must use $n when modifying multiple labels so each variable is assigned a different label."; From 9148432ff8d3875a5eae533891b58ad5c3c92c69 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 16:41:37 -0700 Subject: [PATCH 21/26] Remove logic to select text --- Bit Slicer/ZGEditLabelWindowController.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index d7c3b1313..fd19e9664 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -127,8 +127,6 @@ - (void)requestEditingLabelsFromVariables:(NSArray *)variables att _labelTextField.stringValue = labelStringValue; _labelTextField.placeholderString = labelPlaceholderStringValue; - [_labelTextField selectText:nil]; - [parentWindow beginSheet:window completionHandler:^(NSModalResponse __unused returnCode) { }]; } From 061741856ae7c0a07f09f12c429f08748ec53850 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 17:08:54 -0700 Subject: [PATCH 22/26] Add formatter to validate label text field against invalid characters --- Bit Slicer/ZGEditLabelWindowController.m | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index fd19e9664..dac95b546 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -38,6 +38,60 @@ #define ZGEditLabelLocalizableTable @"[Code] Edit Variable Label" +#define MAX_LABEL_LENGTH 50 + +@interface ZGLabelTextFormatter : NSFormatter +@end + +@implementation ZGLabelTextFormatter +{ + NSCharacterSet *_invalidCharacterSet; +} + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + NSCharacterSet *validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_$"]; + + _invalidCharacterSet = [validCharacterSet invertedSet]; + } + return self; +} + +- (NSString *)stringForObjectValue:(id)anObject +{ + if (![(NSObject *)anObject isKindOfClass:[NSString class]]) + { + return nil; + } + + return anObject; +} + +- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error +{ + return YES; +} + +- (BOOL)isPartialStringValid:(NSString * __autoreleasing *)partialStringPtr + proposedSelectedRange:(NSRangePointer)proposedSelRangePtr + originalString:(NSString *)origString + originalSelectedRange:(NSRange)origSelRange + errorDescription:(NSString * __autoreleasing *)error +{ + if ([*partialStringPtr length] > MAX_LABEL_LENGTH) + { + return NO; + } + + NSRange invalidRange = [*partialStringPtr rangeOfCharacterFromSet:_invalidCharacterSet]; + return (invalidRange.location == NSNotFound); +} + +@end + @implementation ZGEditLabelWindowController { ZGVariableController * _Nonnull _variableController; @@ -81,6 +135,9 @@ - (void)windowDidLoad [self.window.contentView addConstraint:layoutConstraint]; } + + ZGLabelTextFormatter *formatter = [[ZGLabelTextFormatter alloc] init]; + _labelTextField.formatter = formatter; } - (void)requestEditingLabelsFromVariables:(NSArray *)variables attachedToWindow:(NSWindow *)parentWindow From a0c5b9613dc930fce1bc9dc08a4484296b1886ad Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 17:58:40 -0700 Subject: [PATCH 23/26] Add justification for not using label hash table lookup --- Bit Slicer/ZGVariableController.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index 556b4851b..ed5faaccd 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -401,6 +401,9 @@ - (void)disableHarmfulVariables:(NSArray *)variables - (nullable ZGVariable *)variableForLabel:(NSString *)label { + // We could maintain a dictionary cache for label -> variable lookups + // However I don't believe the complexity of managing changes to this state is worth it + // and it should not be a bottleneck realistically for (ZGVariable *variable in _documentData.variables) { if ([variable.label isEqualToString:label]) From 97e6e1d0e2ce8e4ff41318b3b842c8b644ab7546 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 18:25:16 -0700 Subject: [PATCH 24/26] Update variable annotations when labeled variables are added/removed --- Bit Slicer/ZGVariableController.m | 59 +++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index ed5faaccd..fed497a0d 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -340,6 +340,7 @@ - (void)removeVariablesAtRowIndexes:(NSIndexSet *)rowIndexes addVariables:variablesToRemove atRowIndexes:rowIndexes]; + BOOL removedAnyLabelVariable = NO; for (ZGVariable *variable in variablesToRemove) { if (variable.enabled) @@ -354,6 +355,11 @@ - (void)removeVariablesAtRowIndexes:(NSIndexSet *)rowIndexes variable.isFrozen = NO; } } + + if (!removedAnyLabelVariable && variable.label.length > 0) + { + removedAnyLabelVariable = YES; + } } [temporaryArray addObjectsFromArray:_documentData.variables]; @@ -369,6 +375,21 @@ - (void)removeVariablesAtRowIndexes:(NSIndexSet *)rowIndexes [windowController.variablesTableView reloadData]; [windowController updateSearchAddressOptions]; + + if (removedAnyLabelVariable) + { + // Re-annotate other variables that may be referencing variables that were just removed + NSMutableArray *variablesToAnnotate = [NSMutableArray array]; + for (ZGVariable *variable in _documentData.variables) + { + if (variable.usesDynamicLabelAddress) + { + [variablesToAnnotate addObject:variable]; + } + } + + [self annotateVariablesAutomatically:variablesToAnnotate process:windowController.currentProcess]; + } } - (void)disableHarmfulVariables:(NSArray *)variables @@ -421,12 +442,20 @@ - (void)addVariables:(NSArray *)variables atRowIndexes:(NSIndexSet // Make sure we do not end up with duplicate labels // New variables that have a label that already exists have their labels removed NSSet *oldLabels = [self usedLabels]; + BOOL addedLabeledVariable = NO; for (ZGVariable *variable in variables) { NSString *label = variable.label; - if (label.length > 0 && [oldLabels containsObject:label]) + if (label.length > 0) { - variable.label = @""; + if ([oldLabels containsObject:label]) + { + variable.label = @""; + } + else + { + addedLabeledVariable = YES; + } } } @@ -457,7 +486,31 @@ - (void)addVariables:(NSArray *)variables atRowIndexes:(NSIndexSet [windowController updateNumberOfValuesDisplayedStatus]; [windowController updateSearchAddressOptions]; - [self annotateVariablesAutomatically:variables process:windowController.currentProcess]; + if (!addedLabeledVariable) + { + [self annotateVariablesAutomatically:variables process:windowController.currentProcess]; + } + else + { + // Update annotations for all variables that reference labels as well as the variables we just added + // It's possible any of these variables may be referencing a label to a variable we just added + NSMutableOrderedSet *variablesToAnnotate = [NSMutableOrderedSet orderedSetWithArray:variables]; + + for (ZGVariable *variable in _documentData.variables) + { + if ([variablesToAnnotate containsObject:variable]) + { + continue; + } + + if (variable.usesDynamicLabelAddress) + { + [variablesToAnnotate addObject:variable]; + } + } + + [self annotateVariablesAutomatically:variablesToAnnotate.array process:windowController.currentProcess]; + } } - (void)removeSelectedSearchValues From 0ccc9cb9a3ac7a7fae3c72b68ea99081e8e1106a Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 18:31:49 -0700 Subject: [PATCH 25/26] Use label placeholder when editing multiple labels always --- Bit Slicer/ZGEditLabelWindowController.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index dac95b546..d24b86385 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -154,10 +154,11 @@ - (void)requestEditingLabelsFromVariables:(NSArray *)variables att if (variables.count > 1) { + labelPlaceholderStringValue = @"Foo_%n"; + if (firstVariableLabel.length == 0) { labelStringValue = @""; - labelPlaceholderStringValue = @"Foo_%n"; } else { @@ -171,8 +172,6 @@ - (void)requestEditingLabelsFromVariables:(NSArray *)variables att { labelStringValue = [NSString stringWithFormat:@"%@_$n", firstVariableLabel]; } - - labelPlaceholderStringValue = @""; } } else From f43e98c39303efc378280d9891afef4165ff0be2 Mon Sep 17 00:00:00 2001 From: Zorg Date: Sun, 5 May 2024 18:40:33 -0700 Subject: [PATCH 26/26] Fix label validation formatter --- Bit Slicer/ZGEditLabelWindowController.m | 28 +++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index d24b86385..196f9cb33 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -45,6 +45,7 @@ @interface ZGLabelTextFormatter : NSFormatter @implementation ZGLabelTextFormatter { + NSCharacterSet *_validCharacterSet; NSCharacterSet *_invalidCharacterSet; } @@ -53,9 +54,9 @@ - (instancetype)init self = [super init]; if (self != nil) { - NSCharacterSet *validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_$"]; + _validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_$"]; - _invalidCharacterSet = [validCharacterSet invertedSet]; + _invalidCharacterSet = [_validCharacterSet invertedSet]; } return self; } @@ -72,6 +73,22 @@ - (NSString *)stringForObjectValue:(id)anObject - (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error { + if (obj != NULL) + { + NSUInteger stringLength = string.length; + NSMutableString *newString = [[NSMutableString alloc] initWithCapacity:stringLength]; + + for (NSUInteger characterIndex = 0; characterIndex < stringLength; characterIndex++) + { + unichar character = [string characterAtIndex:characterIndex]; + if ([_validCharacterSet characterIsMember:character]) + { + [newString appendFormat:@"%C", character]; + } + } + + *obj = [newString copy]; + } return YES; } @@ -87,7 +104,12 @@ - (BOOL)isPartialStringValid:(NSString * __autoreleasing *)partialStringPtr } NSRange invalidRange = [*partialStringPtr rangeOfCharacterFromSet:_invalidCharacterSet]; - return (invalidRange.location == NSNotFound); + if (invalidRange.location != NSNotFound) + { + return NO; + } + + return YES; } @end