美文网首页
LLDB源码探索(四)

LLDB源码探索(四)

作者: 浅墨入画 | 来源:发表于2021-03-10 22:10 被阅读0次

    一. 判断地址在堆区

    堆上分配的对象,一般占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;
    }
    

    相关文章

      网友评论

          本文标题:LLDB源码探索(四)

          本文链接:https://www.haomeiwen.com/subject/kxyuqltx.html