{"id":377,"date":"2018-08-17T13:08:56","date_gmt":"2018-08-17T20:08:56","guid":{"rendered":"http:\/\/blog.mozilla.org\/sfink\/?p=377"},"modified":"2021-06-13T14:10:15","modified_gmt":"2021-06-13T21:10:15","slug":"type-examination-in-gdb","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/sfink\/2018\/08\/17\/type-examination-in-gdb\/","title":{"rendered":"Type examination in gdb"},"content":{"rendered":"<p>Sometimes, the exact layout of objects in memory becomes very important. Some situations you may encounter:<\/p>\n<ul>\n<li>When overlaying different types as &#8220;views&#8221; of the same memory location, perhaps via <code>reinterpret_cast<\/code>, <code>union<\/code>s, or <code>void*<\/code>-casting. You want to know where the field in one view lands in another.\n<li>When examining a struct layout&#8217;s packing, to see if there is space being wasted.\n<li>When looking at a crash at some offset like 0xc8, it&#8217;s common for that to be a NULL pointer dereference of a field of some structure, as if you did <code>MyStruct* foo = nullptr; return foo->field;<\/code>.\n<\/ul>\n<p>A very handy command for looking at the underlying storage of types is <code>pahole<\/code>. But I&#8217;m usually in gdb already when I want to examine types. Plus, I somehow have never gotten comfortable with the separate <code>pahole<\/code> command &#8212; possibly because it has a tendency to seg fault when I try running it. The latest gdb (8.1) also has it built-in if you run <code>ptype\/o <i>typename<\/i><\/code>.<\/p>\n<p><a href=\"http:\/\/tromey.com\/blog\/\" rel=\"noopener\" target=\"_blank\">Tom Tromey<\/a> implemented a simple version of pahole inside gdb using the Python scripting APIs. I stole<sup>1<\/sup> his code, fixed some bugs, mucked with his output layout, added some more bugs, fixed some of those, and added it to my gdb startup script collection. I also abstracted out the type traversal and created an additional command to examine what is at a given offset.<\/p>\n<h2><code>offset<\/code><\/h2>\n<p>Let&#8217;s say we have a crash at the address 0x58. Suspecting a NULL pointer dereference while manipulating a <code>js::RegExpShared<\/code> object, let&#8217;s look at what is at that offset:<\/p>\n<pre>\r\n(gdb) offset 0x58 js::RegExpShared\r\nScanning byte offsets 88..95\r\noverlap at byte 88..127 with this.tables : js::RegExpShared::JitCodeTables\r\noverlap at byte 88..95 with this.tables.mBegin : mozilla::UniquePtr<unsigned char [], JS::FreePolicy> *\r\n<\/pre>\n<p>By default, when you examine an offset, <code>offset<\/code> will look at native word&#8217;s worth of memory. Here, I&#8217;m running on 64-bit, so we&#8217;re looking at the 8 bytes starting at 0x58 (aka 88 decimal). (You could do <code>offset\/1 88 js::RegExpShared<\/code> to only look at the single byte offset 88.)<\/p>\n<p>From the above output, we can see that the field <code>tables<\/code> overlaps the offset range being inspected. <code>tables<\/code> itself is a <code>js::RegExpShared::JitCodeTables<\/code> structure, and its <code>mBegin<\/code> field occupies the relevant offsets.<\/p>\n<p>Let&#8217;s look at another example:<\/p>\n<pre>\r\n(gdb) offset 184 JSContext\r\nScanning byte offsets 184..191\r\noverlap at byte 184..199 with this.kind_ : js::WriteOnceData\r\noverlap at byte 184..187 with this.kind_.value : js::ContextKind\r\noverlap at byte 188..187 with this.kind_.check : js::CheckUnprotected\r\noverlap at byte 188..191 with this.kind_ : <32-bit hole> in js::WriteOnceData before field 'nwrites'\r\n<\/pre>\n<p>This has some weirdnesses. First, notice the &#8220;byte 188..187&#8221; range of kind_.check. That&#8217;s an empty <code>js::CheckUnprotected<\/code> struct<sup>2<\/sup>.<\/p>\n<p>Next, we seem to have collided with a hole in the JSContext structure. We can use <code>pahole<\/code> to look at the overall structure. But first, let&#8217;s switch to a simpler structure (JSContext is huge and the output would be pages long).<\/p>\n<pre>\r\n(gdb) offset 0 js::jit::ABIArg\r\nScanning byte offsets 0..7\r\noverlap at byte 0..3 with this.kind_ : js::jit::ABIArg::Kind\r\noverlap at byte 4..7 with this : <32-bit hole> in js::jit::ABIArg before field 'u'\r\n<\/pre>\n<p>Now we can get a higher-level view with pahole.<\/p>\n<h2><code>pahole<\/code><\/h2>\n<pre>\r\n(gdb) pahole js::jit::ABIArg\r\n  offset size\r\n       0   16 : struct js::jit::ABIArg {\r\n       0    4 :   kind_ : js::jit::ABIArg::Kind\r\n       4    4 : --> 32 bit hole in js::jit::ABIArg <--\r\n       8    8 :   u : struct union {...} {\r\n   8  +0    1 :     gpr_ : js::jit::Register::Code\r\n   8  +0    8 :     fpu_ : js::jit::FloatRegister::Code\r\n   8  +0    4 :     offset_ : uint32_t\r\n                  } union {...}\r\n                } js::jit::ABIArg\r\n<\/pre>\n<p>This displays the full structure, with each field (or hole) displayed beside its offset and size within the overall type. Offsets of fields directly inside of the given type are given directly. Offsets within sub-structures are given as the offset of that structure within the outermost struct, plus an offset within the inner struct.<\/p>\n<p>These outputs can get very noisy when they are deeply nested, possibly displaying a lot more data than you care about. You can clamp the depth of the tree with a <code>\/N<\/code> suffix option if you wish:<\/p>\n<pre>\r\n(gdb) pahole\/1 js::jit::ABIArg\r\n  offset size\r\n       0   16 : struct js::jit::ABIArg {\r\n       0    4 :   kind_ : js::jit::ABIArg::Kind\r\n       4    4 : --> 32 bit hole in struct js::jit::ABIArg <--\r\n       8    8 :   u : union {...}\r\n                } struct js::jit::ABIArg\r\n<\/pre>\n<p>Probably not useful with this example, since the interesting stuff is now hidden, but it makes large or deeply nested types much more readable.<\/p>\n<h2>Installing<\/h2>\n<p>If you would like to use this stuff, you can see the <a href=\"https:\/\/github.com\/hotsphink\/sfink-tools\/blob\/master\/README.md\" rel=\"noopener\" target=\"_blank\">full directions<\/a> for installing my random helper crap, or you can just grab the one file <a href=\"https:\/\/raw.githubusercontent.com\/hotsphink\/sfink-tools\/master\/conf\/gdbinit.pahole.py\" rel=\"noopener\" target=\"_blank\">gdbinit.pahole.py<\/a> and source it from your ~\/.gdbinit:<\/p>\n<pre>\r\nsource ~\/path\/to\/gdbinit.pahole.py\r\n<\/pre>\n<h3>Footnotes<\/h3>\n<p>1. \"Stole\" in the GPLv3 sense, that is -- tromey's original and my modified version are both released under the GPLv3 license.<\/p>\n<p>2. Whether empty structs should even be displayed is questionable. What does that even mean?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes, the exact layout of objects in memory becomes very important. Some situations you may encounter: When overlaying different types as &#8220;views&#8221; of the same memory location, perhaps via reinterpret_cast, unions, or void*-casting. You want to know where the field in one view lands in another. When examining a struct layout&#8217;s packing, to see if [&hellip;]<\/p>\n","protected":false},"author":206,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[666,137],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/posts\/377"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/users\/206"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/comments?post=377"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/posts\/377\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/media?parent=377"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/categories?post=377"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/sfink\/wp-json\/wp\/v2\/tags?post=377"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}