FLEXIvar.m 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //
  2. // FLEXIvar.m
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 6/30/15.
  7. // Copyright (c) 2015 Tanner Bennett. All rights reserved.
  8. //
  9. #import "FLEXIvar.h"
  10. #import "FLEXRuntimeUtility.h"
  11. #import "FLEXRuntimeSafety.h"
  12. #import "FLEXTypeEncodingParser.h"
  13. #include <dlfcn.h>
  14. @interface FLEXIvar () {
  15. NSString *_flex_description;
  16. }
  17. @end
  18. @implementation FLEXIvar
  19. #pragma mark Initializers
  20. - (id)init {
  21. [NSException
  22. raise:NSInternalInconsistencyException
  23. format:@"Class instance should not be created with -init"
  24. ];
  25. return nil;
  26. }
  27. + (instancetype)ivar:(Ivar)ivar {
  28. return [[self alloc] initWithIvar:ivar];
  29. }
  30. + (instancetype)named:(NSString *)name onClass:(Class)cls {
  31. Ivar ivar = class_getInstanceVariable(cls, name.UTF8String);
  32. return [self ivar:ivar];
  33. }
  34. - (id)initWithIvar:(Ivar)ivar {
  35. NSParameterAssert(ivar);
  36. self = [super init];
  37. if (self) {
  38. _objc_ivar = ivar;
  39. [self examine];
  40. }
  41. return self;
  42. }
  43. #pragma mark Other
  44. - (NSString *)description {
  45. if (!_flex_description) {
  46. NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.typeEncoding];
  47. _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType];
  48. }
  49. return _flex_description;
  50. }
  51. - (NSString *)debugDescription {
  52. return [NSString stringWithFormat:@"<%@ name=%@, encoding=%@, offset=%ld>",
  53. NSStringFromClass(self.class), self.name, self.typeEncoding, (long)self.offset];
  54. }
  55. - (void)examine {
  56. _name = @(ivar_getName(self.objc_ivar) ?: "(nil)");
  57. _offset = ivar_getOffset(self.objc_ivar);
  58. _typeEncoding = @(ivar_getTypeEncoding(self.objc_ivar) ?: "");
  59. NSString *typeForDetails = _typeEncoding;
  60. NSString *sizeForDetails = nil;
  61. if (_typeEncoding.length) {
  62. _type = (FLEXTypeEncoding)[_typeEncoding characterAtIndex:0];
  63. FLEXGetSizeAndAlignment(_typeEncoding.UTF8String, &_size, nil);
  64. sizeForDetails = [@(_size).stringValue stringByAppendingString:@" bytes"];
  65. } else {
  66. _type = FLEXTypeEncodingNull;
  67. typeForDetails = @"no type info";
  68. sizeForDetails = @"unknown size";
  69. }
  70. Dl_info exeInfo;
  71. if (dladdr(_objc_ivar, &exeInfo)) {
  72. _imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
  73. }
  74. _details = [NSString stringWithFormat:
  75. @"%@, offset %@ — %@",
  76. sizeForDetails, @(_offset), typeForDetails
  77. ];
  78. }
  79. - (id)getValue:(id)target {
  80. id value = nil;
  81. if (!FLEXIvarIsSafe(_objc_ivar) || _type == FLEXTypeEncodingNull) {
  82. return nil;
  83. }
  84. #ifdef __arm64__
  85. // See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
  86. if (self.type == FLEXTypeEncodingObjcClass && [self.name isEqualToString:@"isa"]) {
  87. value = object_getClass(target);
  88. } else
  89. #endif
  90. if (self.type == FLEXTypeEncodingObjcObject || self.type == FLEXTypeEncodingObjcClass) {
  91. value = object_getIvar(target, self.objc_ivar);
  92. } else {
  93. void *pointer = (__bridge void *)target + self.offset;
  94. value = [FLEXRuntimeUtility
  95. valueForPrimitivePointer:pointer
  96. objCType:self.typeEncoding.UTF8String
  97. ];
  98. }
  99. return value;
  100. }
  101. - (void)setValue:(id)value onObject:(id)target {
  102. const char *typeEncodingCString = self.typeEncoding.UTF8String;
  103. if (self.type == FLEXTypeEncodingObjcObject) {
  104. object_setIvar(target, self.objc_ivar, value);
  105. } else if ([value isKindOfClass:[NSValue class]]) {
  106. // Primitive - unbox the NSValue.
  107. NSValue *valueValue = (NSValue *)value;
  108. // Make sure that the box contained the correct type.
  109. NSAssert(
  110. strcmp(valueValue.objCType, typeEncodingCString) == 0,
  111. @"Type encoding mismatch (value: %s; ivar: %s) in setting ivar named: %@ on object: %@",
  112. valueValue.objCType, typeEncodingCString, self.name, target
  113. );
  114. NSUInteger bufferSize = 0;
  115. if (FLEXGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL)) {
  116. void *buffer = calloc(bufferSize, 1);
  117. [valueValue getValue:buffer];
  118. void *pointer = (__bridge void *)target + self.offset;
  119. memcpy(pointer, buffer, bufferSize);
  120. free(buffer);
  121. }
  122. }
  123. }
  124. - (id)getPotentiallyUnboxedValue:(id)target {
  125. return [FLEXRuntimeUtility
  126. potentiallyUnwrapBoxedPointer:[self getValue:target]
  127. type:self.typeEncoding.UTF8String
  128. ];
  129. }
  130. @end