Skip to content

Commit

Permalink
Allow dragging variables onto a labeled variable to relate them
Browse files Browse the repository at this point in the history
The dragged variables will be assigned new address formulas based on the labeled variable's address.
  • Loading branch information
zorgiepoo committed May 11, 2024
1 parent 81b6f68 commit ef8bed6
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 49 deletions.
110 changes: 81 additions & 29 deletions Bit Slicer/ZGDocumentTableController.m
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ @implementation ZGDocumentTableController
ZGTableView * _Nullable _variablesTableView;
}

#define ZGVariableReorderType @"ZGVariableReorderType"
#define ZGVariableRowsType @"ZGVariableRowsType"

#define WATCH_VARIABLES_UPDATE_TIME_INTERVAL 0.1

Expand All @@ -90,7 +90,7 @@ - (void)setVariablesTableView:(ZGTableView *)tableView
_variablesTableView = tableView;
[_variablesTableView setDataSource:self];
[_variablesTableView setDelegate:self];
[_variablesTableView registerForDraggedTypes:@[ZGVariableReorderType, ZGVariablePboardType]];
[_variablesTableView registerForDraggedTypes:@[ZGVariableRowsType, ZGVariablePboardType]];
}

- (void)cleanUp
Expand Down Expand Up @@ -336,10 +336,46 @@ - (void)updateWatchVariablesTable:(NSTimer *)__unused timer

#pragma mark Table View Drag & Drop

- (NSDragOperation)tableView:(NSTableView *)__unused tableView validateDrop:(id <NSDraggingInfo>)draggingInfo proposedRow:(NSInteger)__unused row proposedDropOperation:(NSTableViewDropOperation)operation
- (NSDragOperation)tableView:(NSTableView *)__unused tableView validateDrop:(id <NSDraggingInfo>)draggingInfo proposedRow:(NSInteger)proposedRow proposedDropOperation:(NSTableViewDropOperation)operation
{
if ([draggingInfo draggingSource] == _variablesTableView && [draggingInfo.draggingPasteboard.types containsObject:ZGVariableReorderType] && operation != NSTableViewDropOn)
if ([draggingInfo draggingSource] == _variablesTableView && [draggingInfo.draggingPasteboard.types containsObject:ZGVariableRowsType])
{
if (operation == NSTableViewDropOn)
{
if (proposedRow < 0)
{
return NO;
}

NSArray<NSNumber *> *draggingRows = [draggingInfo.draggingPasteboard propertyListForType:ZGVariableRowsType];

if ([draggingRows containsObject:@(proposedRow)])
{
return NSDragOperationNone;
}

NSArray<ZGVariable *> *documentVariables = _documentData.variables;
if ((NSUInteger)proposedRow >= documentVariables.count)
{
return NSDragOperationNone;
}

ZGVariable *variableAtProposedRow = documentVariables[(NSUInteger)proposedRow];
if (variableAtProposedRow.label.length == 0)
{
return NSDragOperationNone;
}

for (NSNumber *draggingRow in draggingRows)
{
ZGVariable *draggingVariable = documentVariables[draggingRow.unsignedIntegerValue];
if (draggingVariable.type == ZGScript || draggingVariable.usesDynamicLabelAddress)
{
return NSDragOperationNone;
}
}
}

return NSDragOperationMove;
}
else if ([draggingInfo.draggingPasteboard.types containsObject:ZGVariablePboardType] && operation != NSTableViewDropOn)
Expand All @@ -362,41 +398,57 @@ - (void)reorderVariables:(NSArray<ZGVariable *> *)newVariables
[_variablesTableView reloadData];
}

- (BOOL)tableView:(NSTableView *)__unused tableView acceptDrop:(id <NSDraggingInfo>)draggingInfo row:(NSInteger)newRow dropOperation:(NSTableViewDropOperation)__unused operation
- (BOOL)tableView:(NSTableView *)__unused tableView acceptDrop:(id <NSDraggingInfo>)draggingInfo row:(NSInteger)newRow dropOperation:(NSTableViewDropOperation)operation
{
if (newRow < 0)
{
return NO;
}

if ([draggingInfo draggingSource] == _variablesTableView && [draggingInfo.draggingPasteboard.types containsObject:ZGVariableReorderType])
if ([draggingInfo draggingSource] == _variablesTableView && [draggingInfo.draggingPasteboard.types containsObject:ZGVariableRowsType])
{
NSMutableArray<ZGVariable *> *variables = [NSMutableArray arrayWithArray:_documentData.variables];
NSArray<NSNumber *> *rows = [draggingInfo.draggingPasteboard propertyListForType:ZGVariableReorderType];
NSArray<NSNumber *> *rows = [draggingInfo.draggingPasteboard propertyListForType:ZGVariableRowsType];

// Fill in the current rows with null objects
for (NSNumber *row in rows)
if (operation == NSTableViewDropOn)
{
[variables
replaceObjectAtIndex:row.unsignedIntegerValue
withObject:(id)[NSNull null]];
NSArray<ZGVariable *> *documentVariables = _documentData.variables;

ZGVariable *targetLabeledVariable = documentVariables[(NSUInteger)newRow];
NSArray<ZGVariable *> *draggedVariables = [rows zgMapUsingBlock:^id _Nonnull(NSNumber *row) {
return documentVariables[row.unsignedIntegerValue];
}];

ZGDocumentWindowController *windowController = _windowController;
[windowController.variableController relateVariables:draggedVariables toLabeledVariable:targetLabeledVariable];
}

// Insert the objects to the new position
for (NSNumber *row in rows)
else
{
[variables
insertObject:[_documentData.variables objectAtIndex:row.unsignedIntegerValue]
atIndex:(NSUInteger)newRow];
NSMutableArray<ZGVariable *> *variables = [NSMutableArray arrayWithArray:_documentData.variables];

// Fill in the current rows with null objects
for (NSNumber *row in rows)
{
[variables
replaceObjectAtIndex:row.unsignedIntegerValue
withObject:(id)[NSNull null]];
}

newRow++;
// Insert the objects to the new position
for (NSNumber *row in rows)
{
[variables
insertObject:[_documentData.variables objectAtIndex:row.unsignedIntegerValue]
atIndex:(NSUInteger)newRow];

newRow++;
}

// Remove all the old objects
[variables removeObject:(id)[NSNull null]];

// Set the new variables
[self reorderVariables:variables];
}

// Remove all the old objects
[variables removeObject:(id)[NSNull null]];

// Set the new variables
[self reorderVariables:variables];
}
else if ([draggingInfo.draggingPasteboard.types containsObject:ZGVariablePboardType])
{
Expand All @@ -411,7 +463,7 @@ - (BOOL)tableView:(NSTableView *)__unused tableView acceptDrop:(id <NSDraggingIn
NSArray<ZGVariable *> *variables = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[[NSArray class], [ZGVariable class]]] fromData:pasteboardData error:&unarchiveError];
if (variables == nil)
{
NSLog(@"Error: failed to unarchive variables in drag-dsop: %@", unarchiveError);
NSLog(@"Error: failed to unarchive variables in drag-drop: %@", unarchiveError);
return NO;
}

Expand All @@ -430,13 +482,13 @@ - (BOOL)tableView:(NSTableView *)__unused tableView acceptDrop:(id <NSDraggingIn

- (BOOL)tableView:(NSTableView *)__unused tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard
{
[pasteboard declareTypes:@[ZGVariableReorderType, ZGVariablePboardType] owner:self];
[pasteboard declareTypes:@[ZGVariableRowsType, ZGVariablePboardType] owner:self];

NSMutableArray<NSNumber *> *rows = [[NSMutableArray alloc] init];
[rowIndexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL * __unused stop) {
[rows addObject:@(index)];
}];
[pasteboard setPropertyList:[NSArray arrayWithArray:rows] forType:ZGVariableReorderType];
[pasteboard setPropertyList:[NSArray arrayWithArray:rows] forType:ZGVariableRowsType];

NSArray<ZGVariable *> *variables = [_documentData.variables objectsAtIndexes:rowIndexes];

Expand Down
2 changes: 1 addition & 1 deletion Bit Slicer/ZGEditAddressWindowController.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ - (IBAction)editAddress:(id)__unused sender
[NSApp endSheet:window];
[window close];

[_variableController editVariable:ZGUnwrapNullableObject(_variable) addressFormula:_addressTextField.stringValue];
[_variableController editVariables:@[ZGUnwrapNullableObject(_variable)] addressFormulas:@[_addressTextField.stringValue]];

_variable = nil;
}
Expand Down
2 changes: 1 addition & 1 deletion Bit Slicer/ZGPyDebugger.m
Original file line number Diff line number Diff line change
Expand Up @@ -1510,7 +1510,7 @@ static BOOL writeRegister(NSDictionary<NSString *, NSValue *> *registerOffsetsDi
dispatch_async(dispatch_get_main_queue(), ^{
ZGVariable *variable = [variableController variableForLabel:labelString];

[variableController editVariable:variable addressFormula:addressString];
[variableController editVariables:@[variable] addressFormulas:@[addressString]];
});

return Py_BuildValue("");
Expand Down
4 changes: 3 additions & 1 deletion Bit Slicer/ZGVariableController.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,15 @@ typedef struct
- (void)changeVariable:(ZGVariable *)variable newValue:(NSString *)stringObject shouldRecordUndo:(BOOL)recordUndoFlag;
- (void)changeVariableEnabled:(BOOL)enabled rowIndexes:(NSIndexSet *)rowIndexes;

- (void)relateVariables:(NSArray<ZGVariable *> *)variables toLabeledVariable:(ZGVariable *)labeledVariable;

- (void)relativizeVariables:(NSArray<ZGVariable *> *)variables;
+ (ZGMachBinaryAnnotationInfo)machBinaryAnnotationInfoForProcess:(ZGProcess *)process;
+ (void)annotateVariables:(NSArray<ZGVariable *> *)variables annotationInfo:(ZGMachBinaryAnnotationInfo)annotationInfo process:(ZGProcess *)process variableController:(nullable ZGVariableController *)variableController symbols:(BOOL)symbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler;
+ (void)annotateVariables:(NSArray<ZGVariable *> *)variables process:(ZGProcess *)process variableController:(nullable ZGVariableController *)variableController symbols:(BOOL)requiresSymbols async:(BOOL)async completionHandler:(void (^)(void))completionHandler;

- (void)editVariables:(NSArray<ZGVariable *> *)variables newValues:(NSArray<NSString *> *)newValues;
- (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddressFormula;
- (void)editVariables:(NSArray<ZGVariable *> *)variables addressFormulas:(NSArray<NSString *> *)newAddressFormulas;
- (void)editVariables:(NSArray<ZGVariable *> *)variables requestedSizes:(NSArray<NSNumber *> *)requestedSizes;
- (void)editVariables:(NSArray<ZGVariable *> *)variables requestedLabels:(NSArray<NSString *> *)requestedLabels;

Expand Down
125 changes: 109 additions & 16 deletions Bit Slicer/ZGVariableController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,73 @@ - (void)changeVariableEnabled:(BOOL)enabled rowIndexes:(NSIndexSet *)rowIndexes
}
}

- (void)relateVariables:(NSArray<ZGVariable *> *)variables toLabeledVariable:(ZGVariable *)labeledVariable
{
ZGDocumentWindowController *windowController = _windowController;
ZGProcess *process = windowController.currentProcess;

// If there are any duplicate addresses or any address is zero or the addresses are < than the labeled variable
// we will assume the variable's addresses are not meaningful and can be overwritten based on stride
// Otherwise we will assume the current addresses are meaningful and are relative to the labeled variable
ZGMemoryAddress labeledVariableAddress = labeledVariable.address;
NSMutableSet<NSNumber *> *visitedAddresses = [NSMutableSet set];
BOOL currentAddressesRelatable = YES;
for (ZGVariable *variable in variables)
{
if (variable.address == 0x0 || variable.address < labeledVariableAddress)
{
currentAddressesRelatable = NO;
break;
}

if ([visitedAddresses containsObject:@(variable.address)])
{
currentAddressesRelatable = NO;
break;
}

[visitedAddresses addObject:@(variable.address)];
}

NSMutableArray<NSString *> *newAddressFormulas = [NSMutableArray array];
NSString *label = labeledVariable.label;
if (!currentAddressesRelatable)
{
ZGMemoryAddress currentAddress = labeledVariableAddress + labeledVariable.size;

ZGProcessType processType = process.type;
for (ZGVariable *variable in variables)
{
ZGMemorySize variableSize = variable.size;

// Fix any data potential data alignment
ZGMemorySize dataAlignment = ZGDataAlignment(processType, variable.type, variableSize);
ZGMemorySize unalignedSize = (currentAddress % dataAlignment);
if (unalignedSize != 0)
{
currentAddress += dataAlignment - unalignedSize;
}

NSString *newAddressFormula = [NSString stringWithFormat:@"label(\"%@\") + 0x%llX", label, currentAddress - labeledVariableAddress];

[newAddressFormulas addObject:newAddressFormula];

currentAddress += variableSize;
}
}
else
{
for (ZGVariable *variable in variables)
{
NSString *newAddressFormula = [NSString stringWithFormat:@"label(\"%@\") + 0x%llX", label, variable.address - labeledVariableAddress];

[newAddressFormulas addObject:newAddressFormula];
}
}

[self editVariables:variables addressFormulas:newAddressFormulas];
}

#pragma mark Edit Variables Values

- (void)editVariables:(NSArray<ZGVariable *> *)variables newValues:(NSArray<NSString *> *)newValues
Expand Down Expand Up @@ -1040,37 +1107,63 @@ - (void)editVariables:(NSArray<ZGVariable *> *)variables newValues:(NSArray<NSSt

#pragma mark Edit Variables Address

- (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddressFormula
- (void)editVariables:(NSArray<ZGVariable *> *)variables addressFormulas:(NSArray<NSString *> *)newAddressFormulas
{
ZGDocumentWindowController *windowController = _windowController;

windowController.undoManager.actionName = ZGLocalizedStringFromVariableActionsTable(@"undoAddressChange");
NSArray<NSString *> *oldAddressFormulas = [variables zgMapUsingBlock:^id _Nonnull(ZGVariable *variable) {
return variable.addressFormula;
}];

NSString *undoActionName = (variables.count == 1) ? ZGLocalizedStringFromVariableActionsTable(@"undoAddressChange") : ZGLocalizedStringFromVariableActionsTable(@"undoAddressChanges");
windowController.undoManager.actionName = undoActionName;

[(ZGVariableController *)[windowController.undoManager prepareWithInvocationTarget:self]
editVariable:variable
addressFormula:variable.addressFormula];
editVariables:variables
addressFormulas:oldAddressFormulas];

variable.addressFormula = newAddressFormula;
if (variable.usesDynamicPointerAddress || variable.usesDynamicBaseAddress || variable.usesDynamicSymbolAddress || variable.usesDynamicLabelAddress)
BOOL needsToReloadTable = NO;
BOOL anyVariableHasLabel = NO;
NSUInteger variableIndex = 0;
for (ZGVariable *variable in variables)
{
variable.usesDynamicAddress = YES;
NSString *newAddressFormula = newAddressFormulas[variableIndex];

variable.addressFormula = newAddressFormula;
if (variable.usesDynamicPointerAddress || variable.usesDynamicBaseAddress || variable.usesDynamicSymbolAddress || variable.usesDynamicLabelAddress)
{
variable.usesDynamicAddress = YES;
}
else
{
variable.usesDynamicAddress = NO;
variable.addressStringValue = [ZGCalculator evaluateExpression:newAddressFormula];

needsToReloadTable = YES;
}
variable.finishedEvaluatingDynamicAddress = NO;

if (variable.label.length > 0)
{
anyVariableHasLabel = YES;
}

variableIndex++;
}
else

if (needsToReloadTable)
{
variable.usesDynamicAddress = NO;
variable.addressStringValue = [ZGCalculator evaluateExpression:newAddressFormula];

[windowController.variablesTableView reloadData];
}
variable.finishedEvaluatingDynamicAddress = NO;

NSMutableArray<ZGVariable *> *variablesToAnnotate = [NSMutableArray arrayWithObject:variable];
if (variable.label.length > 0)
NSMutableOrderedSet<ZGVariable *> *variablesToAnnotate = [NSMutableOrderedSet orderedSetWithArray:variables];
if (anyVariableHasLabel > 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)
if ([variablesToAnnotate containsObject:otherVariable])
{
continue;
}
Expand All @@ -1082,7 +1175,7 @@ - (void)editVariable:(ZGVariable *)variable addressFormula:(NSString *)newAddres
}
}

[self annotateVariablesAutomatically:variablesToAnnotate process:windowController.currentProcess];
[self annotateVariablesAutomatically:variablesToAnnotate.array process:windowController.currentProcess];

[windowController updateSearchAddressOptions];
}
Expand Down
3 changes: 3 additions & 0 deletions Bit Slicer/en.lproj/[Code] Variable Actions.strings
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
/* Undo action for changing variable address */
"undoAddressChange" = "Address Change";

/* Undo action for changing variable addresses */
"undoAddressChanges" = "Address Changes";

/* Undo action for relativizing a single variable */
"undoRelativizeSingleVariable" = "Relativize Variable";

Expand Down
Binary file modified Bit Slicer/es.lproj/[Code] Variable Actions.strings
Binary file not shown.
5 changes: 4 additions & 1 deletion Bit Slicer/ru.lproj/[Code] Variable Actions.strings
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
/* Undo action for changing variable address */
"undoAddressChange" = "Изменение адреса";

/* Undo action for changing variable addresses */
"undoAddressChanges" = "Address Changes";

/* Undo action for relativizing a single variable */
"undoRelativizeSingleVariable" = "РевиталиRelativize Variable";

Expand All @@ -74,4 +77,4 @@
"failedChangeSizeAlertTitle" = "Не удалось изменить размер";

/* Alert message title for changing variable size */
"failedChangeSizeAlertMessage" = "Размер не может быть изменен. Возможно, запрашиваемый размер слишком большой?";
"failedChangeSizeAlertMessage" = "Размер не может быть изменен. Возможно, запрашиваемый размер слишком большой?";

0 comments on commit ef8bed6

Please sign in to comment.