{"id":94085,"date":"2016-08-15T07:00:00","date_gmt":"2016-08-15T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=94085"},"modified":"2024-05-13T11:33:56","modified_gmt":"2024-05-13T18:33:56","slug":"20160815-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160815-00\/?p=94085","title":{"rendered":"How can I debug a function that has been subjected to COMDAT folding?"},"content":{"rendered":"<p>Suppose you want to set a breakpoint on a function, but you find that <a title=\"Why does the debugger show me the wrong function?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050322-00\/?p=36113\">the function has been subjected to COMDAT folding<\/a>, so your attempt to set a breakpoint on the function ends up setting a breakpoint on some other function, and your breakpoint ends up firing when either your desired function or the other identical function gets called. How can you get your breakpoint to fire only on the function you are debugging?<\/p>\n<p>One way to do this is to disable COMDAT folding temporarily and rebuild. Mind you, this may result in your binary size exploding, but since you&#8217;re just debugging, this probably doesn&#8217;t bother you that much. On the other hand, there may be parts of the program that are relying on COMDAT folding, or it may be hard to find the build setting that controls COMDAT folding, and you run the risk of forgetting to change the setting back and accidentally committing a change that disables COMDAT folding!<\/p>\n<p>The easy way is to mutate the function. Add a call to a harmless function like <code>Get\u00adTick\u00adCount()<\/code>. Note that the harmless function must be something the compiler can&#8217;t optimize out, so don&#8217;t try <code>free(nullptr)<\/code> because the compiler is allowed to take advantage of the fact that <code>free(nullptr)<\/code> is required by the language standard to have no effect and can consequently optimize the call out entirely.<\/p>\n<p>Then again, if you&#8217;re going to mutate the function, you may as well mutate it in a way that makes debugging easier. For example, you might add<\/p>\n<pre>bool breakpoint = false;\r\n\r\nvoid TheFunction()\r\n{\r\n if (breakpoint) DebugBreak();\r\n ... rest of function ...\r\n}\r\n<\/pre>\n<p>Then you can patch the breakpoint variable to <code>true<\/code> and boom, there&#8217;s your breakpoint.<\/p>\n<p>If you can&#8217;t recompile the binary, then your options are more limited. If the set of callers is manageable, you could try setting a breakpoint on each of the callers. Or if there is something in the function that lets you detect which identical function you&#8217;re in, you can use that. For example, maybe the two functions are<\/p>\n<pre>class Circle\r\n{\r\npublic:\r\n   virtual int GetRadius() { return m_radius; }\r\nprivate:\r\n  int m_radius;\r\n  int m_xcenter;\r\n  int m_ycenter;\r\n};\r\n\r\nclass Channel\r\n{\r\npublic:\r\n   int GetId() { return m_id; }\r\nprivate:\r\n  HANDLE m_signal;\r\n  int m_id;\r\n};\r\n<\/pre>\n<p>Since <code>Circle::Get\u00adRadius<\/code> and <code>Channel::Get\u00adId<\/code> compile to the same code, they will get COMDAT-folded. But you can still figure out which method you&#8217;re in by looking at other parts of the <code>this<\/code> pointer. In the example above, you see that <code>Circle<\/code> has a virtual method, hence a vtable, so you can use a conditional breakpoint to check whether the vtable matches.<\/p>\n<p>If you use a boring debugger, it might be something like this:<\/p>\n<pre>0:001&gt; bp Circle::GetRadius \"j poi(ecx)==0x10014270 r;g\"\r\n<\/pre>\n<p>If you use a fancy debugger, then use your fancy debugger&#8217;s conditional breakpoint facility.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The easy way is to mutate the function.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-94085","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The easy way is to mutate the function.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94085","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=94085"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94085\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=94085"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=94085"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=94085"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}