LLDB查询对象存储区域

LLDB查询对象存储区域(mach-o 栈区 堆区)

#import "LGCatAddress.h"
// 1. C++插件
// 2. 模版
// 3. lldb + 基本上所有mach-o,执行其他代码信息
// cat address 0x00010000010
// 命令传递的参数
namespace LG {
using lldb::eReturnStatusFailed;
using lldb::eReturnStatusSuccessFinishResult;
using lldb::SBCommandInterpreter;
using lldb::SBCommandReturnObject;
using lldb::SBDebugger;
using lldb::SBError;
using lldb::SBExpressionOptions;
using lldb::SBFrame;
using lldb::SBStream;
using lldb::SBSymbol;
using lldb::SBTarget;
using lldb::SBThread;
using lldb::SBValue;
using lldb::SBAddress;
using lldb::SBSection;
using lldb::SBModule;
std::tuple tryMachOAddress(SBAddress addr, SBTarget target) {
    // section
    SBSection section = addr.GetSection();
    if (!section.IsValid()) {
        return std::make_tuple(false, nullptr);
    }
    NSMutableString *sectionName = [NSString stringWithUTF8String:section.GetName()].mutableCopy;
    SBSection tmpS = section;
    while (tmpS.GetParent().IsValid()) {
        tmpS = tmpS.GetParent();
        sectionName = [NSMutableString stringWithFormat:@"%s.%@", tmpS.GetName(), sectionName];
    }
    SBModule module = addr.GetModule();
    if (module.IsValid()) {
        sectionName = [NSMutableString stringWithFormat:@"%s.%@", addr.GetModule().GetFileSpec().GetFilename(), sectionName];
    }
    uint64_t addrOffset = addr.GetLoadAddress(target) - section.GetLoadAddress(target);
    [sectionName appendFormat:@" +%llx", addrOffset];
    SBSymbol symbol = addr.GetSymbol();
    NSMutableString *returnDescription = [NSMutableString stringWithFormat:@"%llx", addr.GetOffset()];
    if (symbol.IsValid()) {
        [returnDescription appendFormat:@"%s", symbol.GetName()];
        SBAddress startAddr =  symbol.GetStartAddress();

        uint64_t addrOffset = addr.GetLoadAddress(target) - startAddr.GetLoadAddress(target);
        [returnDescription appendFormat:@" <+%llu> ", addrOffset];

        if (symbol.GetMangledName()) {
            [returnDescription appendFormat:@", (%s)", symbol.GetMangledName()];
        }
        [returnDescription appendFormat:@", External: %@ ", symbol.IsSynthetic() ? @"YES" : @"NO"];
    }
    
    [returnDescription appendFormat:@"%@", sectionName];
    return std::make_tuple(true, returnDescription.UTF8String);
}
std::tuple  tryStackAddress(SBAddress addr, SBTarget target) {
        // frame -> thread
        SBThread thread = target.GetProcess().GetSelectedThread();
        uint32_t num_frames = thread.GetNumFrames();
        SBStream stream;
        for (UInt32 i = 0; i < num_frames; i++) {
            const uint64_t address = addr.GetLoadAddress(target);
            SBFrame frame = thread.GetFrameAtIndex(i);
            const uint64_t fp = frame.GetFP();
            const uint64_t sp = frame.GetSP();
            if (address >= sp && address <= fp) {
                stream.Printf("stack address (SP: 0x%llx FP: 0x%llx) %s", sp, fp, frame.GetFunctionName());
                return std::make_tuple(true, [NSString stringWithUTF8String:stream.GetData()].UTF8String);
            }
        }
        return std::make_tuple(false, nullptr);
    }
// 插件执行的环境
// 执行插件所在的调试环境

// lldb -》 运行在一个进程上
// exec -〉 运行在一个进程上 lldb -》debugserver
// lldb -> 加载这个插件的-》调代码-〉cat address
// 2个环境 -》 porcess -〉 2堆
// 开发porcess
//hmap
// 执行插件-》调试环境-〉执行相关的判断代码
// 自定义协议 + 客户端 服务端 大厂用 人力物力成本大 引擎
// 动态库 + 苹果点头
    std::tuple 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
          )___");
//        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);
        // 执行它支持的语言的代码
        // lldb调试环境
        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);
    }
    
    bool CatAddressCommand::DoExecute(lldb::SBDebugger debugger, char **command,
                                      lldb::SBCommandReturnObject & result) {
        SBTarget target = debugger.GetSelectedTarget();
        SBThread thread = target.GetProcess().GetSelectedThread();
        if (!thread.IsValid()) {
            result.SetError("Expects an address");
            //false:命令处理失败
            return false;
        }
        // 0x -> 地址 -》SBAddress
        // 0x10000
        NSString *cmd = [NSString stringWithCString:*command encoding:NSUTF8StringEncoding];
        if ( !cmd || cmd.length < 1) {
            result.SetError("Expects an address");
            return false;
        }
        long address = 0;
        char* end = nullptr;
        if ([cmd.lowercaseString hasPrefix:@"0x"]) {
            address = strtol(*command, &end, 16);
        } else {
            address = strtol(*command, &end, 10);
        }
        bool foundAddress = false;
        const char *returnDescription = nullptr ;
        SBAddress addr = target.ResolveLoadAddress(address);
        // mach-o 所在的Section   addr.GetSection()

        // 1. 扫描Mach-o
        if (addr.GetSection().IsValid()) {
            std::tuple tuple = tryMachOAddress(addr, target);
            foundAddress = std::get<0>(tuple);
            returnDescription = std::get<1>(tuple);
        }
        // 2. 扫描stack
        if (returnDescription == nullptr) {
            std::tuple tuple = tryStackAddress(addr, target);
            foundAddress = std::get<0>(tuple);
            returnDescription = std::get<1>(tuple);
        }
        // 3. 扫描堆
        if (returnDescription == nullptr) {
            std::tuple tuple = tryHeapAddress(addr, target);
            foundAddress = std::get<0>(tuple);
            returnDescription = std::get<1>(tuple);
        }
        SBStream stream = SBStream();
        if (foundAddress) {
            stream.Printf("address:%s, %s", *command, returnDescription);
            result.AppendMessage(stream.GetData());
            //true:命令处理成功
            return true;
        } else {
            stream.Printf("Couldn't find address, reverting to \"image lookup -a %s\"", *command);
            result.AppendMessage(stream.GetData());
            return false;
        }
        
    }
}

// 一个疗程
// 苹果的验证机制 -》 SIP -〉自编译的lldb.dylib
// SIP -〉还是不行 -》签名的事

// 继承SBCommandPluginInterface
// 动态库插件的mach-o扫描符号 lldb::PluginInitialize
// SBDebugger: 当前的调试器
// 干什么?自定义的命令挂载上
namespace lldb {
    bool PluginInitialize(SBDebugger debugger) {
        // SBCommandInterpreter :
        lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
        // p
        // po 单个关键字的命令
        
        // br set 多个关键字的命令
        // cat address <地址> :地址所在的空间:mach-o、堆上、栈上
        // help cat
        // help cat address
        lldb::SBCommand cmd = interpreter.AddMultiwordCommand("cat", NULL);
        cmd.AddCommand("address", new LG::CatAddressCommand(@"Cat !"), "cat address ---- ");
        return true;
    }
}

测试用例

#import 
#import "LGCatAddress.h"

@interface LGCatAddressTests : XCTestCase
{
    lldb::SBDebugger _debugger;
    lldb::SBTarget _target;
    lldb::SBProcess _process;
    lldb::SBCommandInterpreter _interp;
}
@end

@implementation LGCatAddressTests

- (void)setUp {
    // 初始化SBDebugger -》加载一个可执行文件-〉验证我们的插件
    lldb::SBDebugger::Initialize();
    _debugger = lldb::SBDebugger::Create();
    _debugger.SetAsync(false);
    
    // 1. 初始化target
    _target = _debugger.CreateTargetWithFileAndArch("/Users/xiaokai/Desktop/逻辑IOS/iOS\ 高级强化班/第十四节课、单元测试与UI测试/上课代码/02-插件判断地址在堆区/LGCatAddress/TestExec/a.out", "x86_64");
    _target.BreakpointCreateByLocation("test.c", 17);
    _interp = _debugger.GetCommandInterpreter();
}


- (void)testExample {
    _process = _target.LaunchSimple(nil, nil, "/Users/xiaokai/Desktop/逻辑IOS/iOS\ 高级强化班/第十四节课、单元测试与UI测试/上课代码/02-插件判断地址在堆区/LGCatAddress/TestExec");
    lldb::SBCommandReturnObject result;

//    _interp.HandleCommand("r", result);
    XCTAssertTrue(_process.GetNumThreads() > 0);
    lldb::SBThread thread = _process.GetThreadAtIndex(0);
    const char * name = thread.GetFrameAtIndex(0).GetFunctionName();
    // 测试代码
    // 手动的命令解释器+CatAddressCommand
//    LG::CatAddressCommand lgCmd(@"zhin笨");
//    lldb::SBCommand cmd = _interp.AddMultiwordCommand("cat", NULL);
//    cmd.AddCommand("address", &lgCmd, "cat address");
    // 调用我的cat address
    _interp.HandleCommand("plugin load /Users/ws/Library/Developer/Xcode/DerivedData/LGCatAddress-gwqawrzsvandhqawsrpvhsxvjifb/Build/Products/Debug/libLGCatAddress.dylib", result);
    NSLog(@"%s", result.GetOutput());
    _interp.HandleCommand("cat address 0x10000", result);
    NSLog(@"%s", result.GetOutput());
    
    
    lldb::SBStream stream;
    // cat address (po m)地址
    _interp.HandleCommand("po m", result);
    stream.Printf("cat address %s", result.GetOutput());
    _interp.HandleCommand(stream.GetData(), result);
    NSLog(@"%s", result.GetOutput());

    // cat address (po b)地址
    _interp.HandleCommand("po b", result);
    lldb::SBStream bstream;
    bstream.Printf("cat address %s", result.GetOutput());
    _interp.HandleCommand(bstream.GetData(), result);
    NSLog(@"%s", result.GetOutput());
    
    // 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());

}


@end

你可能感兴趣的:(LLDB查询对象存储区域)