Search code examples
xcodeframeworkslldb

Where Debug info stored in Framework?


As the title mentioned, I'm confusing about where is the debug info stored in .Framework file.

I googled for serval days, what I gots are:

Framework binary compiled by debug mode will include a debug info segment, to indicate the symbol location. Release mode compiling will move it to a dSYM file.

But, what confused me is, I build a framework with ninja, and it doesn't generate dSYM file. Meanwhile I can't find the symbol location by dwarfdump command or MachOView app. As Regards strings command can get some relative file path results, like ../../flutter/fml/memory/task_runner_checker.cc.

Here dwarfdump prints:

Flutter.framework/Flutter:      file format Mach-O arm64

.debug_info contents:

Here is my questions:

  1. When I triggered breakpoint at somewhere in the framework, the source code still shows. Why?

  2. When I run lldb command, it shows:

(lldb) image lookup -a $pc --verbose
      Address: Flutter[0x0000000001964f18] (Flutter.__TEXT.__text + 26604184)
      Summary: Flutter`dart::BootstrapNatives::DN_LoadLibraryFromTypedData(dart::Thread*, dart::Zone*, dart::NativeArguments*) + 44 [inlined] dart::NativeArguments::NativeArgAt(int) const at object.cc:537
               Flutter`dart::BootstrapNatives::DN_LoadLibraryFromTypedData(dart::Thread*, dart::Zone*, dart::NativeArguments*) + 44 [inlined] dart::DN_HelperLoadLibraryFromTypedData(dart::Isolate*, dart::Thread*, dart::Zone*, dart::NativeArguments*) at object.cc:534
               Flutter`dart::BootstrapNatives::DN_LoadLibraryFromTypedData(dart::Thread*, dart::Zone*, dart::NativeArguments*) + 44 at object.cc:534
       Module: file = "/Users/xx/Library/Developer/Xcode/DerivedData/XXX-ddigzjlnuypwnydlawevfrkmdsov/Build/Products/Debug-iphoneos/XXX.app/Frameworks/Flutter.framework/Flutter", arch = "arm64"
  CompileUnit: id = {0x00000000}, file = "/Users/xx/Documents/workspace/aion/flutter_engine/src/third_party/dart/runtime/lib/object.cc", language = "c++14"
     Function: id = {0x7d40006244d}, name = "dart::BootstrapNatives::DN_LoadLibraryFromTypedData(dart::Thread*, dart::Zone*, dart::NativeArguments*)", mangled = "_ZN4dart16BootstrapNatives27DN_LoadLibraryFromTypedDataEPNS_6ThreadEPNS_4ZoneEPNS_15NativeArgumentsE", range = [0x0000000117310eec-0x0000000117311490)
     FuncType: id = {0x7d40006244d}, byte-size = 0, decl = bootstrap_natives.h:507, compiler_type = "class dart::ObjectPtr (class dart::Thread *, class dart::Zone *, class dart::NativeArguments *)"
       Blocks: id = {0x7d40006244d}, range = [0x117310eec-0x117311490)
               id = {0x7d40006249b}, ranges = [0x117310f18-0x1173113e0)[0x117311404-0x117311490), name = "DN_HelperLoadLibraryFromTypedData", decl = object.cc:534, mangled = _ZN4dartL33DN_HelperLoadLibraryFromTypedDataEPNS_7IsolateEPNS_6ThreadEPNS_4ZoneEPNS_15NativeArgumentsE, demangled = dart::DN_HelperLoadLibraryFromTypedData(dart::Isolate*, dart::Thread*, dart::Zone*, dart::NativeArguments*)
               id = {0x7d40006253a}, range = [0x117310f18-0x117310f24), name = "NativeArgAt", decl = native_arguments.h:129, mangled = _ZNK4dart15NativeArguments11NativeArgAtEi, demangled = dart::NativeArguments::NativeArgAt(int) const
    LineEntry: [0x0000000117310f18-0x0000000117310f24): /Users/xx/Documents/workspace/xxx/flutter_engine/src/third_party/dart/runtime/vm/native_arguments.h:132:14
       Symbol: id = {0x0013fd0f}, range = [0x0000000117310eec-0x0000000117311490), name="dart::BootstrapNatives::DN_LoadLibraryFromTypedData(dart::Thread*, dart::Zone*, dart::NativeArguments*)", mangled="_ZN4dart16BootstrapNatives27DN_LoadLibraryFromTypedDataEPNS_6ThreadEPNS_4ZoneEPNS_15NativeArgumentsE"
     Variable: id = {0x7d400062553}, name = "this", type = "const dart::NativeArguments *", location = DW_OP_reg20 W20, decl = 
     Variable: id = {0x7d40006255c}, name = "index", type = "int", location = <decoding error> 00 00 00, decl = native_arguments.h:129
     Variable: id = {0x7d4000624a8}, name = "isolate", type = "dart::Isolate *", location = , decl = object.cc:534
     Variable: id = {0x7d4000624ad}, name = "thread", type = "dart::Thread *", location = , decl = object.cc:534
     Variable: id = {0x7d4000624b2}, name = "zone", type = "dart::Zone *", location = DW_OP_reg19 W19, decl = object.cc:534
     Variable: id = {0x7d4000624bb}, name = "arguments", type = "dart::NativeArguments *", location = DW_OP_reg20 W20, decl = object.cc:534
     Variable: id = {0x7d4000624c4}, name = "program", type = "unique_ptr<dart::xx_kernel::Program, std::__1::default_delete<dart::xx_kernel::Program> >", location = DW_OP_breg31 WSP+64, decl = object.cc:556
     Variable: id = {0x7d400062468}, name = "thread", type = "dart::Thread *", location = DW_OP_reg24 W24, decl = object.cc:534
     Variable: id = {0x7d400062479}, name = "zone", type = "dart::Zone *", location = DW_OP_reg19 W19, decl = object.cc:534
     Variable: id = {0x7d40006248a}, name = "arguments", type = "dart::NativeArguments *", location = DW_OP_reg20 W20, decl = object.cc:534

So, where the lldb get Compile Unit and LineEntry outputs?


Solution

  • Debug information on Darwin systems exists in one of two places: In the .o files, and later after dsymutil is run to create a .dSYM, it exists in the .dSYM bundle, all collected together, relocated to the actual binary's addresses.

    This was a build-link-debug performance enhancement. Linking all of the debug information -- updating all the symbol addresses, copying it all around -- is very slow, so leaving the debug information in the .o files for this common iterative development cycle, and having the debugger locate the .o files and update the addresses of the functions internally, allows for rapid development.

    Leaving all of the debug information in the .o files requires that they all be present, of course! And at the same file paths. So it is not good when you need to move a binary between computers, or save it for later debugging. For these cases, you link the debug information with dsymutil and you get a .dSYM bundle.