)]}'
{
  "commit": "f0bdf68d3fb6db1dd2b83e07062e2104cdb785c2",
  "tree": "dae28b1523aa24202dabec02b21066a985c0fec2",
  "parents": [
    "2ecee236752932672fb3d6cd63c6976927f747d8"
  ],
  "author": {
    "name": "Andrew Burgess",
    "email": "aburgess@redhat.com",
    "time": "Fri Dec 16 15:15:42 2022 +0000"
  },
  "committer": {
    "name": "Andrew Burgess",
    "email": "aburgess@redhat.com",
    "time": "Sun Feb 12 06:19:53 2023 +0000"
  },
  "message": "gdb/c++: fix handling of breakpoints on @plt symbols\n\nThis commit should fix PR gdb/20091, PR gdb/17201, and PR gdb/17071.\nAdditionally, PR gdb/17199 relates to this area of code, but is more\nof a request to refactor some parts of GDB, this commit does not\naddress that request, but it is probably worth reading that PR when\nlooking at this commit.\n\nWhen the current language is C++, and the user places a breakpoint on\na function in a shared library, GDB will currently find two locations\nfor the breakpoint, one location will be within the function itself as\nwe would expect, but the other location will be within the PLT table\nfor the call to the named function.  Consider this session:\n\n  $ gdb -q /tmp/breakpoint-shlib-func\n  Reading symbols from /tmp/breakpoint-shlib-func...\n  (gdb) start\n  Temporary breakpoint 1 at 0x40112e: file /tmp/breakpoint-shlib-func.cc, line 20.\n  Starting program: /tmp/breakpoint-shlib-func\n\n  Temporary breakpoint 1, main () at /tmp/breakpoint-shlib-func.cc:20\n  20\t  int answer \u003d foo ();\n  (gdb) break foo\n  Breakpoint 2 at 0x401030 (2 locations)\n  (gdb) info breakpoints\n  Num     Type           Disp Enb Address            What\n  2       breakpoint     keep y   \u003cMULTIPLE\u003e\n  2.1                         y   0x0000000000401030 \u003cfoo()@plt\u003e\n  2.2                         y   0x00007ffff7fc50fd in foo() at /tmp/breakpoint-shlib-func-lib.cc:20\n\nThis is not the expected behaviour.  If we compile the same test using\na C compiler then we see this:\n\n  (gdb) break foo\n  Breakpoint 2 at 0x7ffff7fc50fd: file /tmp/breakpoint-shlib-func-c-lib.c, line 20.\n  (gdb) info breakpoints\n  Num     Type           Disp Enb Address            What\n  2       breakpoint     keep y   0x00007ffff7fc50fd in foo at /tmp/breakpoint-shlib-func-c-lib.c:20\n\nHere\u0027s what\u0027s happening.  When GDB parses the symbols in the main\nexecutable and the shared library we see a number of different symbols\nfor foo, and use these to create entries in GDB\u0027s msymbol table:\n\n  - In the main executable we see a symbol \u0027foo@plt\u0027 that points at\n    the plt entry for foo, from this we add two entries into GDB\u0027s\n    msymbol table, one called \u0027foo@plt\u0027 which points at the plt entry\n    and has type mst_text, then we create a second symbol, this time\n    called \u0027foo\u0027 with type mst_solib_trampoline which also points at\n    the plt entry,\n\n  - Then, when the shared library is loaded we see another symbol\n    called \u0027foo\u0027, this one points at the actual implementation in the\n    shared library.  This time GDB creates a msymbol called \u0027foo\u0027 with\n    type mst_text that points at the implementation.\n\nThis means that GDB creates 3 msymbols to represent the 2 symbols\nfound in the executable and shared library.\n\nWhen the user creates a breakpoint on \u0027foo\u0027 GDB eventually ends up in\nsearch_minsyms_for_name (linespec.c), this function then calls\niterate_over_minimal_symbols passing in the name we are looking for\nwrapped in a lookup_name_info object.\n\nIn iterate_over_minimal_symbols we iterate over two hash tables (using\nthe name we\u0027re looking for as the hash key), first we walk the hash\ntable of symbol linkage names, then we walk the hash table of\ndemangled symbol names.\n\nWhen the language is C++ the symbols for \u0027foo\u0027 will all have been\nmangled, as a result, in this case, the iteration of the linkage name\nhash table will find no matching results.\n\nHowever, when we walk the demangled hash table we do find some\nresults.  In order to match symbol names, GDB obtains a symbol name\nmatching function by calling the get_symbol_name_matcher method on the\nlanguage_defn class.  For C++, in this case, the matching function we\nuse is cp_fq_symbol_name_matches, which delegates the work to\nstrncmp_iw_with_mode with mode strncmp_iw_mode::MATCH_PARAMS and\nlanguage set to language_cplus.\n\nThe strncmp_iw_mode::MATCH_PARAMS mode means that strncmp_iw_mode will\nskip any parameters in the demangled symbol name when checking for a\nmatch, e.g. \u0027foo\u0027 will match the demangled name \u0027foo()\u0027.  The way this\nis done is that the strings are matched character by character, but,\nonce the string we are looking for (\u0027foo\u0027 here) is exhausted, if we\nare looking at \u0027(\u0027 then we consider the match a success.\n\nLets consider the 3 symbols GDB created.  If the function declaration\nis \u0027void foo ()\u0027 then from the main executable we added symbols\n\u0027_Z3foov@plt\u0027 and \u0027_Z3foov\u0027, while from the shared library we added\nanother symbol call \u0027_Z3foov\u0027.  When these are demangled they become\n\u0027foo()@plt\u0027, \u0027foo()\u0027, and \u0027foo()\u0027 respectively.\n\nNow, the \u0027_Z3foov\u0027 symbol from the main executable has the type\nmst_solib_trampoline, and in search_minsyms_for_name, we search for\nany symbols of type mst_solib_trampoline and filter these out of the\nresults.\n\nHowever, the \u0027_Z3foov@plt\u0027 symbol (from the main executable), and the\n\u0027_Z3foov\u0027 symbol (from the shared library) both have type mst_text.\n\nDuring the demangled name matching, due to the use of MATCH_PARAMS\nmode, we stop the comparison as soon as we hit a \u0027(\u0027 in the demangled\nname.  And so, \u0027_Z3foov@plt\u0027, which demangles to \u0027foo()@plt\u0027 matches\n\u0027foo\u0027, and \u0027_Z3foov\u0027, which demangles to \u0027foo()\u0027 also matches \u0027foo\u0027.\n\nBy contrast, for C, there are no demangled hash table entries to be\niterated over (in iterate_over_minimal_symbols), we only consider the\nlinkage name symbols which are \u0027foo@plt\u0027 and \u0027foo\u0027.  The plain \u0027foo\u0027\nsymbol obviously matches when we are looking for \u0027foo\u0027, but in this\ncase the \u0027foo@plt\u0027 will not match due to the \u0027@plt\u0027 suffix.\n\nAnd so, when the user asks for a breakpoint in \u0027foo\u0027, and the language\nis C, search_minsyms_for_name, returns a single msymbol, the mst_text\nsymbol for foo in the shared library, while, when the language is C++,\nwe get two results, \u0027_Z3foov\u0027 for the shared library function, and\n\u0027_Z3foov@plt\u0027 for the plt entry in the main executable.\n\nI propose to fix this in strncmp_iw_with_mode.  When the mode is\nMATCH_PARAMS, instead of stopping at a \u0027(\u0027 and assuming the match is a\nsuccess, GDB will instead search forward for the matching, closing,\n\u0027)\u0027, effectively skipping the parameter list, and then resume\nmatching.  Thus, when comparing \u0027foo\u0027 to \u0027foo()@plt\u0027 GDB will\neffectively compare against \u0027foo@plt\u0027 (skipping the parameter list),\nand the match will fail, just as it does when the language is C.\n\nThere is one slight complication, which is revealed by the test\ngdb.linespec/cpcompletion.exp, when searching for the symbol of a\nconst member function, the demangled symbol will have \u0027const\u0027 at the\nend of its name, e.g.:\n\n  struct_with_const_overload::const_overload_fn() const\n\nPreviously, the matching would stop at the \u0027(\u0027 character, but after my\nchange the whole \u0027()\u0027 is skipped, and the match resumes.  As a result,\nthe \u0027const\u0027 modifier results in a failure to match, when previously\nGDB would have found a match.\n\nTo work around this issue, in strncmp_iw_with_mode, when mode is\nMATCH_PARAMS, after skipping the parameter list, if the next character\nis \u0027@\u0027 then we assume we are looking at something like \u0027@plt\u0027 and\nreturn a value indicating the match failed, otherwise, we return a\nvalue indicating the match succeeded, this allows things like \u0027const\u0027\nto be skipped.\n\nWith these changes in place I now see GDB correctly setting a\nbreakpoint only at the implementation of \u0027foo\u0027 in the shared library.\n\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d20091\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d17201\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d17071\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d17199\n\nTested-By: Bruno Larsen \u003cblarsen@redhat.com\u003e\nApproved-By: Simon Marchi \u003csimon.marchi@efficios.com\u003e\n",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "2fd7e608df56e83f218fa502f7b280acdace72c1",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.cp/breakpoint-shlib-func-lib.cc"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "a86d06560d4dfab7bebb22438af66b7cd884406d",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.cp/breakpoint-shlib-func.cc"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "dc7c4a8a8eaeee983ced41e493d148a44ef1eed3",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.cp/breakpoint-shlib-func.exp"
    },
    {
      "type": "modify",
      "old_id": "d763e91d7e162f33c5583538deeddb119aed2f58",
      "old_mode": 33188,
      "old_path": "gdb/utils.c",
      "new_id": "91e6974b97640b802f1ff1b0449231d1d37daec8",
      "new_mode": 33188,
      "new_path": "gdb/utils.c"
    }
  ]
}
