一. 判断地址在堆区
堆上分配的对象,一般占16字节
malloc_zone_from_ptr:判断传入的指针是不是在当前应用的堆上,如果不是返回空值
malloc_size:返回在堆上分配的内存块大小
malloc_good_size:对齐
新建工程LGMallocAddress,ViewController内容如下
#import "ViewController.h"
#import <malloc/malloc.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *objc = [NSObject new];
void *ptr = (__bridge void *)(objc);
NSString *str;
if (malloc_zone_from_ptr(ptr)) {
str = [[NSString alloc] initWithFormat:@"%p heap pointer, (0x%zx bytes), zone: %p", ptr, (size_t)malloc_good_size((size_t)malloc_size(ptr)), (void*)malloc_zone_from_ptr(ptr)];
}
NSLog(@"%@", str);
}
@end
// C++ 版本
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *object = [NSObject new];
void *ptr = (__bridge void *)(object);
char name[80];
if ((void*)malloc_zone_from_ptr(ptr)) {
size_t a = (size_t)malloc_good_size((size_t)malloc_size(ptr));
void *p = (void*)malloc_zone_from_ptr(ptr);
sprintf(name, "%p heap pointer, (0x%zx bytes), zone: %p", ptr, a, p);
} else {
memset(name,'\0',sizeof(name));
}
bool isReturn = strcmp(name,"") == 0;
}
// Swift版本
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let objc = NSObject()
// __bridge Unmanaged toOpaque -> 地址 -》UnsafeMutableRawPointer/UnsafeRawPointer
let address = Unmanaged.passUnretained(objc).toOpaque()
var returnString: String?
guard let ptr = malloc_zone_from_ptr(address) else {
return
}
// ⚠️ UnsafeRawPointer-> 16进制的数据Int(bitPattern: ptr) -》数据
returnString = String(format: "%p heap pointer, (0x%x bytes), zone: %p", Int(bitPattern: address), malloc_good_size(malloc_size(address)), Int(bitPattern: ptr))
}
}
// 运行工程打印
2021-03-07 23:58:47.035264+0800 LGMallocAddress[26911:2628538] 0x600001f08460 heap pointer, (0x10 bytes), zone: 0x7fff86d4c000
(lldb) e -- malloc_good_size(17)
(size_t) $0 = 32
(lldb) po objc
<NSObject: 0x600000914670>
(lldb) me read -s 8 -f x -c 4 -- 0x600000914670
0x600000914670: 0x00007fff86d50660 0x0000000000000000
0x600000914680: 0x0000000000000000 0x0000000000000000
二. 判断插件地址在堆区
// LGCatAddress.mm文件添加如下方法
// 执行插件 和 执行插件所在的调试环境,是两个process环境,两个进程中每个进程有每个进程的堆
// 执行插件-》调试环境-〉执行相关的判断代码
std::tuple<bool, const char *> tryHeapAddress(SBAddress addr, SBTarget target) {
// 执行它支持的字符串
SBStream stream = SBStream();
stream.Printf("uintptr_t ptr_t = %llu;", addr.GetLoadAddress(target));
stream.Printf("void *ptr = (void *)ptr_t;");
// 执行多行字符串
stream.Printf(R"---(
@import CoreFoundation;
char name[80];
if ((void*)malloc_zone_from_ptr(ptr)) {
size_t a = (size_t)malloc_good_size((size_t)malloc_size(ptr));
void *p = (void*)malloc_zone_from_ptr(ptr);
sprintf(name, "%%p heap pointer, (0x%%zx bytes), zone: %%p", ptr, a, p);
} else {
memset(name,'\0',sizeof(name));
}
bool isReturn = strcmp(name,"") == 0;
)---");
stream.Printf("isReturn ? nil : name;");
lldb::SBExpressionOptions eval_options;
//指定语言类型
eval_options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
//eval_options.SetLanguage(lldb::eLanguageTypeSwift);
eval_options.SetAutoApplyFixIts(false);
eval_options.SetGenerateDebugInfo(false);
//执行它支持的语言的代码
SBValue value = target.EvaluateExpression(stream.GetData(), eval_options);
SBStream returnStream;
if (value.GetError().Success()) {
value.GetDescription(returnStream);
const char *m = returnStream.GetData();
} else {
value.GetError().GetDescription(returnStream);
const char *m = returnStream.GetData();
}
// value.GetData();
//代码返回的内容
return std::make_tuple(false, nullptr);
}
// bool CatAddressCommand::DoExecute 方法中调用
// 扫描堆
if (returnDescription == nullptr) {
std::tuple<bool, const char *> tuple = tryHeapAddress(addr, target);
foundAddress = std::get<0>(tuple);
returnDescription = std::get<1>(tuple);
}
// 单元测试文件LGCatAddressTests.mm,方法testExample中调用
// cat address (po p)地址 --malloc
_interp.HandleCommand("po p", result);
lldb::SBStream pstream;
pstream.Printf("cat address %s", result.GetOutput());
_interp.HandleCommand(pstream.GetData(), result);
NSLog(@"%s", result.GetOutput());
// 打印堆地址
(lldb) e -- result.GetOutput()
(const char *) $1 = 0x0000000102863230 "Couldn't find address, reverting to "image lookup -a 0x0000000100304150\n\n"\n"
三. lldb插件Swift
// 执行插件 和 执行插件所在的调试环境,是两个process环境,两个进程中每个进程有每个进程的堆
// 执行插件-》调试环境-〉执行相关的判断代码
std::tuple<bool, const char *> tryHeapAddress(SBAddress addr, SBTarget target) {
// 执行它支持的字符串
SBStream stream = SBStream();
stream.Printf("import Foundation\n");
stream.Printf("let address: UnsafeRawPointer? =unsafeRawPointer(bitPattern: %llu)\n", addr.GetLoadAddress(target));
// 执行多行字符串
stream.Printf(R"___(
var returnString: String?
if let address = address, let ptr = malloc_zone_from_ptr(address) {
returnString = String(format: "%%p heap pointer, (0x%%x bytes), zone: %%p", Int(bitPattern: address), malloc_good_size(malloc_size(address)), Int(bitPattern: ptr))
}
guard let string = returnString else {
return ""
}
return string
)___");
lldb::SBExpressionOptions eval_options;
//指定语言类型
//eval_options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
eval_options.SetLanguage(lldb::eLanguageTypeSwift);
eval_options.SetAutoApplyFixIts(false);
eval_options.SetGenerateDebugInfo(false);
//执行它支持的语言的代码
SBValue value = target.EvaluateExpression(stream.GetData(), eval_options);
SBStream returnStream;
if (value.GetError().Success()) {
value.GetDescription(returnStream);
return std::make_tuple(true, [NSString stringWithUTF8String:returnStream.GetData()].UTF8String);
} else {
value.GetError().GetDescription(returnStream);
}
//代码返回的内容
return std::make_tuple(false, nullptr);
}
四. 调试lldb源码配置
链接lldb动态库的时候可以通过xcconfig来进行配置
创建SBAPI学习动态库,创建Config.xcconfig并进行配置
// Config.xcconfig内容如下
HEADER_SEARCH_PATHS = ${SRCROOT}/include
LD_RUNPATH_SEARCH_PATHS = ${SRCROOT}
SLASH=/
// 把带有调试信息的liblldb.12.0.0git.dylib 引入
OTHER_LDFLAGS = $(inherited) ${SLASH}/${SRCROOT}/liblldb.12.0.0git.dylib
#import <Foundation/Foundation.h>
#import <lldb/API/LLDB.h>
using lldb::SBDebugger;
using lldb::SBTarget;
using lldb::SBProcess;
int main(int argc, const char * argv[]) {
//初始化配置
SBDebugger::Initialize();
// C++Api PY Api一样的
//初始化SBDebugger
SBDebugger debugger = SBDebugger::Create();
bool isValid = debugger.IsValid();
debugger.SetAsync(false);
NSLog(@"%d", debugger.GetNumTargets());
SBTarget target = debugger.CreateTargetWithFileAndArch("/Users/ws/Desktop/VIP课程/第十四节课、单元测试与UI测试/上课代码/03-lldb源码调试/SBAPI学习/test", "x86_64");
// target.BreakpointCreateByLocation("test.m", 12);
target.BreakpointCreateByName("main");
isValid = target.IsValid();
SBProcess process = target.LaunchSimple(nil, nil, "/Users/ws/Desktop/VIP课程/第十四节课、单元测试与UI测试/上课代码/03-lldb源码调试/SBAPI学习");
isValid = process.IsValid();
NSLog(@"process.State: %d", process.GetState());
lldb::SBThread thread = process.GetThreadAtIndex(0);
NSLog(@"Thread: %d", process.GetNumThreads());
// unable to locate debugserver
const char *name = thread.GetFrameAtIndex(0).GetFunctionName();
NSLog(@"%s", name);
lldb::SBCommandReturnObject result;
// 开始手动执行命令
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
interpreter.HandleCommand("r", result);
interpreter.HandleCommand("po Cat", result);
result.AppendMessage("Cat 有错误,Cat老师不行");
interpreter.HandleCommand("di -f -m", result);
result.AppendMessage("Cat 有错误,Cat老师不行");
// SIP Cmd+r
// 建议
// 1. 如果源码 SIP Cmd+r
// 流程
NSLog(@"%s", result.GetOutput());
return 0;
}
网友评论