diff --git a/Bit Slicer.xcodeproj/project.pbxproj b/Bit Slicer.xcodeproj/project.pbxproj index ddbb6fd5..1a1c622c 100644 --- a/Bit Slicer.xcodeproj/project.pbxproj +++ b/Bit Slicer.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 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 */; }; + 72130FF82BF00FAB00691AED /* [Code] Edit Variable Address.strings in Resources */ = {isa = PBXBuildFile; fileRef = 72130FF62BF00FAB00691AED /* [Code] Edit Variable Address.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 */; }; @@ -331,6 +332,9 @@ 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 = ""; }; + 72130FF72BF00FAB00691AED /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = "Bit Slicer/en.lproj/[Code] Edit Variable Address.strings"; sourceTree = ""; }; + 72130FF92BF00FB300691AED /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = "Bit Slicer/es.lproj/[Code] Edit Variable Address.strings"; sourceTree = ""; }; + 72130FFA2BF00FBD00691AED /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "Bit Slicer/ru.lproj/[Code] Edit Variable Address.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 = ""; }; @@ -1039,6 +1043,7 @@ 724A9F3719A813D600E72C9D /* [Code] Edit Variable Value.strings */, 724A9F3A19A8173900E72C9D /* [Code] Edit Variable Size.strings */, 72130FD32BE84B4B00691AED /* [Code] Edit Variable Label.strings */, + 72130FF62BF00FAB00691AED /* [Code] Edit Variable Address.strings */, 724A9F3D19A823C300E72C9D /* [Code] Search Document.strings */, 724A9F4F19A8F54600E72C9D /* [Code] Search Document.stringsdict */, 724A9F4019A85D3F00E72C9D /* [Code] Search Table.strings */, @@ -1600,6 +1605,7 @@ 726CA2D719606E3800A6AD40 /* Watch Variable Dialog.xib in Resources */, 722CAA5919AD4AED009C6AAE /* hotkey.png in Resources */, 77F115AE17D2EAE4009E002A /* bitslicerdocicon.iconset in Resources */, + 72130FF82BF00FAB00691AED /* [Code] Edit Variable Address.strings in Resources */, 7231440E19C6230F00FBE342 /* [Code] Watch Variable.stringsdict in Resources */, 724A9F2519A1657500E72C9D /* [Code] Memory Viewer Status Bar.strings in Resources */, 77F115AF17D2EAE4009E002A /* bitslicericon.iconset in Resources */, @@ -1865,6 +1871,16 @@ name = "[Code] Edit Variable Label.strings"; sourceTree = ""; }; + 72130FF62BF00FAB00691AED /* [Code] Edit Variable Address.strings */ = { + isa = PBXVariantGroup; + children = ( + 72130FF72BF00FAB00691AED /* en */, + 72130FF92BF00FB300691AED /* es */, + 72130FFA2BF00FBD00691AED /* ru */, + ); + name = "[Code] Edit Variable Address.strings"; + sourceTree = ""; + }; 7231440C19C6230F00FBE342 /* [Code] Watch Variable.stringsdict */ = { isa = PBXVariantGroup; children = ( diff --git a/Bit Slicer/ZGCalculator.h b/Bit Slicer/ZGCalculator.h index 51219479..872017ca 100644 --- a/Bit Slicer/ZGCalculator.h +++ b/Bit Slicer/ZGCalculator.h @@ -60,6 +60,7 @@ 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)getVariableCycle:(NSArray * _Nullable __autoreleasing *_Nullable)outCycle variable:(ZGVariable *)variable variableController:(ZGVariableController *)variableController; + (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 5f29f517..37d58cd9 100644 --- a/Bit Slicer/ZGCalculator.m +++ b/Bit Slicer/ZGCalculator.m @@ -945,7 +945,8 @@ + (nullable NSString *)_extractFirstDependentLabelFromExpression:(DDExpression * + (nullable NSString *)extractFirstDependentLabelFromExpression:(NSString *)initialExpression { NSError *expressionError = NULL; - DDExpression *expression = [DDExpression expressionFromString:initialExpression error:&expressionError]; + NSString *substitutedExpression = [self expressionBySubstitutingCalculatePointerFunctionInExpression:initialExpression]; + DDExpression *expression = [DDExpression expressionFromString:substitutedExpression error:&expressionError]; if (expression == nil) { return nil; @@ -954,6 +955,110 @@ + (nullable NSString *)extractFirstDependentLabelFromExpression:(NSString *)init return [self _extractFirstDependentLabelFromExpression:expression]; } ++ (BOOL)_expressionIsCyclic:(DDExpression *)expression cycle:(NSArray * __autoreleasing *)outCycle variableController:(ZGVariableController *)variableController visitedLabels:(NSMutableOrderedSet *)visitedLabels +{ + switch (expression.expressionType) + { + case DDExpressionTypeFunction: + { + if ([expression.function isEqualToString:ZGFindLabelFunction]) + { + if (expression.arguments.count != 1) + { + return NO; + } + + DDExpression *argumentExpression1 = expression.arguments[0]; + if (argumentExpression1.expressionType != DDExpressionTypeVariable) + { + return NO; + } + + NSString *label = argumentExpression1.variable; + if ([visitedLabels containsObject:label]) + { + if (outCycle != NULL) + { + *outCycle = [visitedLabels.array arrayByAddingObject:label]; + } + return YES; + } + + [visitedLabels addObject:label]; + + ZGVariable *newLabelVariable = [variableController variableForLabel:label]; + if (newLabelVariable == nil) + { + return NO; + } + + // Recurse into the new variable label + NSString *addressFormula = newLabelVariable.addressFormula; + NSString *substitutedAddressFormulaExpression = [self expressionBySubstitutingCalculatePointerFunctionInExpression:addressFormula]; + + NSError *expressionError = NULL; + DDExpression *addressFormulaExpression = [DDExpression expressionFromString:substitutedAddressFormulaExpression error:&expressionError]; + if (addressFormulaExpression == nil) + { + return NO; + } + + return [self _expressionIsCyclic:addressFormulaExpression cycle:outCycle variableController:variableController visitedLabels:visitedLabels]; + } + + if (expression.arguments.count != 2) + { + return NO; + } + + DDExpression *argumentExpression1 = expression.arguments[0]; + DDExpression *argumentExpression2 = expression.arguments[1]; + + BOOL hasCycleInExpression1 = NO; + if (argumentExpression1.expressionType == DDExpressionTypeFunction) + { + // If we have label("A") + label("B") we want to use two different copies of visitedLabels + hasCycleInExpression1 = [self _expressionIsCyclic:argumentExpression1 cycle:outCycle variableController:variableController visitedLabels:[visitedLabels mutableCopy]]; + if (hasCycleInExpression1) + { + return YES; + } + } + + if (argumentExpression2.expressionType == DDExpressionTypeFunction) + { + return [self _expressionIsCyclic:argumentExpression2 cycle:outCycle variableController:variableController visitedLabels:visitedLabels]; + } + + return NO; + } + case DDExpressionTypeVariable: + case DDExpressionTypeNumber: + return NO; + } +} + ++ (BOOL)getVariableCycle:(NSArray * __autoreleasing *)outCycle variable:(ZGVariable *)variable variableController:(ZGVariableController *)variableController +{ + NSString *label = variable.label; + if (label.length == 0 || !variable.usesDynamicLabelAddress) + { + return NO; + } + + NSString *initialExpression = [self expressionBySubstitutingCalculatePointerFunctionInExpression:variable.addressFormula]; + + NSError *expressionError = NULL; + DDExpression *expression = [DDExpression expressionFromString:initialExpression error:&expressionError]; + if (expression == nil) + { + return NO; + } + + NSMutableOrderedSet *visitedLabels = [NSMutableOrderedSet orderedSetWithObject:label]; + return [self _expressionIsCyclic:expression cycle:outCycle variableController:variableController visitedLabels:visitedLabels]; +} + + (BOOL)isValidExpression:(NSString *)expression { return [[expression stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] > 0; diff --git a/Bit Slicer/ZGEditAddressWindowController.m b/Bit Slicer/ZGEditAddressWindowController.m index a8a998a7..a14b9386 100644 --- a/Bit Slicer/ZGEditAddressWindowController.m +++ b/Bit Slicer/ZGEditAddressWindowController.m @@ -34,6 +34,9 @@ #import "ZGVariableController.h" #import "ZGVariable.h" #import "ZGNullability.h" +#import "ZGRunAlertPanel.h" + +#define ZGEditAddressLocalizableTable @"[Code] Edit Variable Address" @implementation ZGEditAddressWindowController { @@ -73,12 +76,18 @@ - (void)requestEditingAddressFromVariable:(ZGVariable *)variable attachedToWindo - (IBAction)editAddress:(id)__unused sender { + NSString *newAddressFormula = _addressTextField.stringValue; + NSString *cycleInfo = nil; + if (![_variableController editVariables:@[ZGUnwrapNullableObject(_variable)] addressFormulas:@[newAddressFormula] cycleInfo:&cycleInfo]) + { + ZGRunAlertPanelWithOKButton(NSLocalizedStringFromTable(@"addressCycleAlertTitle", ZGEditAddressLocalizableTable, nil), [NSString stringWithFormat:NSLocalizedStringFromTable(@"addressCycleAlertMessageFormat", ZGEditAddressLocalizableTable, nil), newAddressFormula, cycleInfo]); + return; + } + NSWindow *window = ZGUnwrapNullableObject([self window]); [NSApp endSheet:window]; [window close]; - [_variableController editVariables:@[ZGUnwrapNullableObject(_variable)] addressFormulas:@[_addressTextField.stringValue]]; - _variable = nil; } diff --git a/Bit Slicer/ZGEditLabelWindowController.m b/Bit Slicer/ZGEditLabelWindowController.m index 2677415c..dfe59d96 100644 --- a/Bit Slicer/ZGEditLabelWindowController.m +++ b/Bit Slicer/ZGEditLabelWindowController.m @@ -280,12 +280,17 @@ - (IBAction)editVariablesLabels:(id)__unused sender return; } + NSString *cycleInfo = nil; + if (![_variableController editVariables:ZGUnwrapNullableObject(_variables) requestedLabels:requestedLabels cycleInfo:&cycleInfo]) + { + ZGRunAlertPanelWithOKButton(NSLocalizedStringFromTable(@"labelCycleAlertTitle", ZGEditLabelLocalizableTable, nil), [NSString stringWithFormat:NSLocalizedStringFromTable(@"labelCycleAlertMessageFormat", ZGEditLabelLocalizableTable, nil), cycleInfo]); + return; + } + NSWindow *window = ZGUnwrapNullableObject(self.window); [NSApp endSheet:window]; [window close]; - [_variableController editVariables:ZGUnwrapNullableObject(_variables) requestedLabels:requestedLabels]; - _variables = nil; } diff --git a/Bit Slicer/ZGPyDebugger.m b/Bit Slicer/ZGPyDebugger.m index d0fee2d6..97784822 100644 --- a/Bit Slicer/ZGPyDebugger.m +++ b/Bit Slicer/ZGPyDebugger.m @@ -1507,10 +1507,21 @@ static BOOL writeRegister(NSDictionary *registerOffsetsDi ZGVariableController *variableController = self->objcSelf->_variableController; + ZGPyDebugger *debugger = self->objcSelf; dispatch_async(dispatch_get_main_queue(), ^{ ZGVariable *variable = [variableController variableForLabel:labelString]; - - [variableController editVariables:@[variable] addressFormulas:@[addressString]]; + if (variable == nil) + { + [debugger->_loggerWindowController writeLine:[NSString stringWithFormat:@"Error: updateVariable() failed to identify variable with label '%@'", labelString]]; + } + else + { + NSString *cycleInfo = nil; + if (![variableController editVariables:@[variable] addressFormulas:@[addressString] cycleInfo:&cycleInfo]) + { + [debugger->_loggerWindowController writeLine:[NSString stringWithFormat:@"Error: updateVariable() failed to update label '%@' with address '%@' due to cycle '%@'", labelString, addressString, cycleInfo]]; + } + } }); return Py_BuildValue(""); diff --git a/Bit Slicer/ZGVariableController.h b/Bit Slicer/ZGVariableController.h index 9e3752e0..640867b0 100644 --- a/Bit Slicer/ZGVariableController.h +++ b/Bit Slicer/ZGVariableController.h @@ -89,9 +89,9 @@ typedef struct + (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)editVariables:(NSArray *)variables addressFormulas:(NSArray *)newAddressFormulas; +- (BOOL)editVariables:(NSArray *)variables addressFormulas:(NSArray *)newAddressFormulas cycleInfo:(NSString * _Nullable __autoreleasing *_Nullable)outCycleInfo; - (void)editVariables:(NSArray *)variables requestedSizes:(NSArray *)requestedSizes; -- (void)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels; +- (BOOL)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels cycleInfo:(NSString * _Nullable __autoreleasing *_Nullable)outCycleInfo; - (nullable ZGVariable *)variableForLabel:(NSString *)label; diff --git a/Bit Slicer/ZGVariableController.m b/Bit Slicer/ZGVariableController.m index 45a6df59..633ca57e 100644 --- a/Bit Slicer/ZGVariableController.m +++ b/Bit Slicer/ZGVariableController.m @@ -449,7 +449,6 @@ - (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; @@ -459,6 +458,22 @@ - (void)addVariables:(NSArray *)variables atRowIndexes:(NSIndexSet { variable.label = @""; } + } + } + + // Also make sure we don't end up with new cycles caused by labels + BOOL addedLabeledVariable = NO; + for (ZGVariable *variable in variables) + { + NSString *label = variable.label; + if (label.length > 0) + { + NSArray *cycleInfo = nil; + if ([ZGCalculator getVariableCycle:&cycleInfo variable:variable variableController:self]) + { + NSLog(@"Error: failed to assign label '%@' to added variable ('%@') due to cycle '%@'", variable.label, variable.addressFormula, [cycleInfo componentsJoinedByString:@" → "]); + variable.label = @""; + } else { addedLabeledVariable = YES; @@ -1073,7 +1088,11 @@ - (void)relateVariables:(NSArray *)variables toLabeledVariable:(ZG } } - [self editVariables:variables addressFormulas:newAddressFormulas]; + NSString *cycleInfo = nil; + if (![self editVariables:variables addressFormulas:newAddressFormulas cycleInfo:&cycleInfo]) + { + ZGRunAlertPanelWithOKButton(ZGLocalizedStringFromVariableActionsTable(@"failedRelateVariablesAlertTitle"), [NSString stringWithFormat:ZGLocalizedStringFromVariableActionsTable(@"failedRelateVariablesAlertMessageFormat"), cycleInfo]); + } } #pragma mark Edit Variables Values @@ -1103,29 +1122,66 @@ - (void)editVariables:(NSArray *)variables newValues:(NSArray *)variables addressFormulas:(NSArray *)newAddressFormulas +- (BOOL)editVariables:(NSArray *)variables addressFormulas:(NSArray *)newAddressFormulas cycleInfo:(NSString * __autoreleasing *)outCycleInfo { - ZGDocumentWindowController *windowController = _windowController; - NSArray *oldAddressFormulas = [variables zgMapUsingBlock:^id _Nonnull(ZGVariable *variable) { return variable.addressFormula; }]; + // Detect if we have any cycles from usages of variable labels + BOOL foundCycle = NO; + { + NSUInteger variableIndex = 0; + for (ZGVariable *variable in variables) + { + NSString *newAddressFormula = newAddressFormulas[variableIndex]; + variable.addressFormula = newAddressFormula; + + variableIndex++; + } + + for (ZGVariable *variable in variables) + { + NSArray *cycleInfo = nil; + if ([ZGCalculator getVariableCycle:&cycleInfo variable:variable variableController:self]) + { + NSString *cycleInfoString = [cycleInfo componentsJoinedByString:@" → "]; + NSLog(@"Error: found cycle (%@) while editing address of %@", cycleInfoString, variable.addressFormula); + if (outCycleInfo != NULL) + { + *outCycleInfo = cycleInfoString; + } + foundCycle = YES; + break; + } + } + } + + if (foundCycle) + { + NSUInteger variableIndex = 0; + for (ZGVariable *variable in variables) + { + NSString *oldAddressFormula = oldAddressFormulas[variableIndex]; + variable.addressFormula = oldAddressFormula; + } + return NO; + } + + ZGDocumentWindowController *windowController = _windowController; + NSString *undoActionName = (variables.count == 1) ? ZGLocalizedStringFromVariableActionsTable(@"undoAddressChange") : ZGLocalizedStringFromVariableActionsTable(@"undoAddressChanges"); windowController.undoManager.actionName = undoActionName; [(ZGVariableController *)[windowController.undoManager prepareWithInvocationTarget:self] editVariables:variables - addressFormulas:oldAddressFormulas]; + addressFormulas:oldAddressFormulas + cycleInfo:NULL]; BOOL needsToReloadTable = NO; BOOL anyVariableHasLabel = NO; - NSUInteger variableIndex = 0; for (ZGVariable *variable in variables) { - NSString *newAddressFormula = newAddressFormulas[variableIndex]; - - variable.addressFormula = newAddressFormula; if (variable.usesDynamicPointerAddress || variable.usesDynamicBaseAddress || variable.usesDynamicSymbolAddress || variable.usesDynamicLabelAddress) { variable.usesDynamicAddress = YES; @@ -1133,7 +1189,7 @@ - (void)editVariables:(NSArray *)variables addressFormulas:(NSArra else { variable.usesDynamicAddress = NO; - variable.addressStringValue = [ZGCalculator evaluateExpression:newAddressFormula]; + variable.addressStringValue = [ZGCalculator evaluateExpression:variable.addressFormula]; needsToReloadTable = YES; } @@ -1143,8 +1199,6 @@ - (void)editVariables:(NSArray *)variables addressFormulas:(NSArra { anyVariableHasLabel = YES; } - - variableIndex++; } if (needsToReloadTable) @@ -1174,31 +1228,63 @@ - (void)editVariables:(NSArray *)variables addressFormulas:(NSArra [self annotateVariablesAutomatically:variablesToAnnotate.array process:windowController.currentProcess]; [windowController updateSearchAddressOptions]; + + return YES; } #pragma mark Edit Variable Labels -- (void)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels +- (BOOL)editVariables:(NSArray *)variables requestedLabels:(NSArray *)requestedLabels cycleInfo:(NSString * __autoreleasing *)outCycleInfo { ZGDocumentWindowController *windowController = _windowController; - NSMutableArray *oldLabels = [NSMutableArray array]; + NSArray *oldLabels = [variables zgMapUsingBlock:^(ZGVariable *variable) { + return variable.label; + }]; + + { + NSUInteger labelIndex = 0; + for (ZGVariable *variable in variables) + { + variable.label = requestedLabels[labelIndex]; + labelIndex++; + } + } + + BOOL foundCycle = NO; for (ZGVariable *variable in variables) { - [oldLabels addObject:variable.label]; + NSArray *cycleInfo = nil; + if ([ZGCalculator getVariableCycle:&cycleInfo variable:variable variableController:self]) + { + NSString *cycleInfoString = [cycleInfo componentsJoinedByString:@" → "]; + NSLog(@"Error: detected cycle (%@) while assigning variable (%@) label '%@'", cycleInfoString, variable.addressFormula, variable.label); + if (outCycleInfo != NULL) + { + *outCycleInfo = cycleInfoString; + } + + foundCycle = YES; + break; + } + } + + if (foundCycle) + { + NSUInteger labelIndex = 0; + for (ZGVariable *variable in variables) + { + variable.label = oldLabels[labelIndex]; + labelIndex++; + } + return NO; } 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++; - } + requestedLabels:oldLabels + cycleInfo:NULL]; // Re-annotate the variables so the labels are in the descriptions // Also annotate other variables that may be referencing these edited variables @@ -1217,6 +1303,8 @@ - (void)editVariables:(NSArray *)variables requestedLabels:(NSArra } [self annotateVariablesAutomatically:variablesToAnnotate.array process:windowController.currentProcess]; + + return YES; } #pragma mark Relativizing Variable Addresses diff --git a/Bit Slicer/en.lproj/[Code] Edit Variable Address.strings b/Bit Slicer/en.lproj/[Code] Edit Variable Address.strings new file mode 100644 index 00000000..17eb863f --- /dev/null +++ b/Bit Slicer/en.lproj/[Code] Edit Variable Address.strings @@ -0,0 +1,6 @@ + +/* Alert title indicating that this address would create a cycle */ +"addressCycleAlertTitle" = "Address creates a cycle"; + +/* Alert message indicating that this address would create a cycle */ +"addressCycleAlertMessageFormat" = "The address '%@' cannot be set because it creates a cycle between labels '%@'"; diff --git a/Bit Slicer/en.lproj/[Code] Edit Variable Label.strings b/Bit Slicer/en.lproj/[Code] Edit Variable Label.strings index f84e38a6..5881c40e 100644 --- a/Bit Slicer/en.lproj/[Code] Edit Variable Label.strings +++ b/Bit Slicer/en.lproj/[Code] Edit Variable Label.strings @@ -8,6 +8,12 @@ /* 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 would create a cycle */ +"labelCycleAlertTitle" = "Label creates a cycle"; + +/* Alert message indicating that a label would creates a new cycle */ +"labelCycleAlertMessageFormat" = "A label cannot be set because it creates a cycle '%@'"; + /* Alert title indicating that a label must use a number token */ "requireUsingOrdinalAlertTitle" = "Label must include $n"; diff --git a/Bit Slicer/en.lproj/[Code] Variable Actions.strings b/Bit Slicer/en.lproj/[Code] Variable Actions.strings index e36676ba..14c6f0b8 100644 --- a/Bit Slicer/en.lproj/[Code] Variable Actions.strings +++ b/Bit Slicer/en.lproj/[Code] Variable Actions.strings @@ -67,3 +67,9 @@ /* Alert message title for changing variable size */ "failedChangeSizeAlertMessage" = "The size could not be changed. Perhaps the requested size is too big?"; + +/* Alert title for failing to change variable address due to a label cycle */ +"failedRelateVariablesAlertTitle" = "Label creates a cycle"; + +/* Alert message for failing to change variable address due to a label cycle */ +"failedRelateVariablesAlertMessageFormat" = "A label cannot be set because it creates a cycle '%@'"; diff --git a/Bit Slicer/es.lproj/[Code] Edit Variable Address.strings b/Bit Slicer/es.lproj/[Code] Edit Variable Address.strings new file mode 100644 index 00000000..17eb863f --- /dev/null +++ b/Bit Slicer/es.lproj/[Code] Edit Variable Address.strings @@ -0,0 +1,6 @@ + +/* Alert title indicating that this address would create a cycle */ +"addressCycleAlertTitle" = "Address creates a cycle"; + +/* Alert message indicating that this address would create a cycle */ +"addressCycleAlertMessageFormat" = "The address '%@' cannot be set because it creates a cycle between labels '%@'"; diff --git a/Bit Slicer/es.lproj/[Code] Edit Variable Label.strings b/Bit Slicer/es.lproj/[Code] Edit Variable Label.strings index f84e38a6..65edd053 100644 --- a/Bit Slicer/es.lproj/[Code] Edit Variable Label.strings +++ b/Bit Slicer/es.lproj/[Code] Edit Variable Label.strings @@ -8,6 +8,12 @@ /* 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 would create a cycle */ +"labelCycleAlertTitle" = "Label creates a cycle"; + +/* Alert message indicating that a label would creates a new cycle */ +"labelCycleMultipleAlertMessageFormat" = "The labels cannot be set because one of them creates a cycle '%@'"; + /* Alert title indicating that a label must use a number token */ "requireUsingOrdinalAlertTitle" = "Label must include $n"; diff --git a/Bit Slicer/es.lproj/[Code] Variable Actions.strings b/Bit Slicer/es.lproj/[Code] Variable Actions.strings index 8bbf5ce4..a702a6c0 100644 Binary files a/Bit Slicer/es.lproj/[Code] Variable Actions.strings and b/Bit Slicer/es.lproj/[Code] Variable Actions.strings differ diff --git a/Bit Slicer/ru.lproj/[Code] Edit Variable Address.strings b/Bit Slicer/ru.lproj/[Code] Edit Variable Address.strings new file mode 100644 index 00000000..17eb863f --- /dev/null +++ b/Bit Slicer/ru.lproj/[Code] Edit Variable Address.strings @@ -0,0 +1,6 @@ + +/* Alert title indicating that this address would create a cycle */ +"addressCycleAlertTitle" = "Address creates a cycle"; + +/* Alert message indicating that this address would create a cycle */ +"addressCycleAlertMessageFormat" = "The address '%@' cannot be set because it creates a cycle between labels '%@'"; diff --git a/Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings b/Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings index f84e38a6..65edd053 100644 --- a/Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings +++ b/Bit Slicer/ru.lproj/[Code] Edit Variable Label.strings @@ -8,6 +8,12 @@ /* 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 would create a cycle */ +"labelCycleAlertTitle" = "Label creates a cycle"; + +/* Alert message indicating that a label would creates a new cycle */ +"labelCycleMultipleAlertMessageFormat" = "The labels cannot be set because one of them creates a cycle '%@'"; + /* Alert title indicating that a label must use a number token */ "requireUsingOrdinalAlertTitle" = "Label must include $n"; diff --git a/Bit Slicer/ru.lproj/[Code] Variable Actions.strings b/Bit Slicer/ru.lproj/[Code] Variable Actions.strings index af190199..7411d6b5 100644 --- a/Bit Slicer/ru.lproj/[Code] Variable Actions.strings +++ b/Bit Slicer/ru.lproj/[Code] Variable Actions.strings @@ -66,3 +66,9 @@ /* Alert message title for changing variable size */ "failedChangeSizeAlertMessage" = "Размер не может быть изменен. Возможно, запрашиваемый размер слишком большой?"; + +/* Alert title for failing to change variable address due to a label cycle */ +"failedRelateVariablesAlertTitle" = "Label creates a cycle"; + +/* Alert message for failing to change variable address due to a label cycle */ +"failedRelateVariablesAlertMessageFormat" = "A label cannot be set because it creates a cycle '%@'";