From: Adrian Freihofer <[email protected]> Setting GDB's sysroot to the recipe's D (image/) directory is often not enough: D only contains "usr/lib", but the target reports merged-usr paths like "/lib/libfoo.so.0", so the sysroot lookup fails and GDB falls back to solib-search-path, resolving the library from the full image's rootfs-dbg/rootfs instead. Recipes that install libraries outside the standard libdir hit this on every rebuild, silently debugging with stale symbols from the last full image build. Confirmed against gdb-17.2 gdb/solib.c (solib_find_1()) by capturing the GDB MI trace of an attach session and cross-checking against that code.
Fix: add RecipeModified._find_elf_dirs(), which walks D and returns every directory containing an ELF file, and prepend those directories to additionalSOLibSearchPath, ahead of the rootfs-dbg/rootfs entries, in every generated launch config. Since with usrmerge in DISTRO_FEATURES (the default) base_libdir and libdir resolve to the same path, this can introduce literal duplicates in the list; dedupe with list(dict.fromkeys(...)) instead of a set, since the order of the list is essential: it defines GDB's solib-search-path priority. Also extend the launch.json oe-selftest assertions to check that the first additionalSOLibSearchPath entry is the recipe's own image (D) directory, not rootfs-dbg. Signed-off-by: Adrian Freihofer <[email protected]> --- meta/lib/oeqa/selftest/cases/devtool.py | 5 ++ scripts/lib/devtool/ide_sdk.py | 62 +++++++++++++++++-------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py index 3e0eb7948f..de59feadb8 100644 --- a/meta/lib/oeqa/selftest/cases/devtool.py +++ b/meta/lib/oeqa/selftest/cases/devtool.py @@ -3591,6 +3591,11 @@ class DevtoolIdeSdkGccTests(DevtoolIdeSdkTests): so_paths = config.get("additionalSOLibSearchPath", []) self.assertIn("/.debug", so_paths, f"Configuration '{config['name']}' should include debug symbol paths") self.assertIn("/rootfs-dbg/", so_paths, f"Configuration '{config['name']}' should include rootfs-dbg paths") + # The recipe's own D/usr/lib must come first, so GDB's solib-search-path basename fallback + # prefers freshly rebuilt libraries over a stale rootfs-dbg/rootfs copy from the last full image build. + first_so_path = so_paths.split(":", 1)[0] + self.assertIn("/image/", first_so_path, f"Configuration '{config['name']}' first SO lib search path should be the recipe's own image dir: {first_so_path}") + self.assertNotIn("rootfs-dbg", first_so_path, f"Configuration '{config['name']}' first SO lib search path should not be rootfs-dbg: {first_so_path}") # Verify source file mappings source_map = config.get("sourceFileMap", {}) diff --git a/scripts/lib/devtool/ide_sdk.py b/scripts/lib/devtool/ide_sdk.py index 9225546c5e..6558137134 100755 --- a/scripts/lib/devtool/ide_sdk.py +++ b/scripts/lib/devtool/ide_sdk.py @@ -827,27 +827,50 @@ class RecipeModified: return True return False + @staticmethod + def _find_elf_dirs(root): + """Return every directory under root that contains an ELF file""" + elf_dirs = [] + for dirpath, _dirnames, filenames in os.walk(root): + for filename in filenames: + file_path = os.path.join(dirpath, filename) + if os.path.islink(file_path): + continue + try: + with open(file_path, 'rb') as elf_file: + is_elf = elf_file.read(4) == b'\x7fELF' + except OSError: + continue + if is_elf: + elf_dirs.append(dirpath) + break + return elf_dirs + def solib_search_path(self, image): - """Search for debug symbols in the rootfs and rootfs-dbg + """Search for debug symbols - The debug symbols of shared libraries which are provided by other packages - are grabbed from the -dbg packages in the rootfs-dbg. + This recipe's own D is searched (for ELF files, wherever they are + installed), so that this recipe's freshly rebuilt libraries take + precedence over any stale copy from the last full image build. + "set sysroot D" alone cannot achieve this: GDB's sysroot (tested with + GDB 17.2) only matches "/lib" paths, but D usually only contains + "usr/lib" (no top-level "lib" symlink), so it falls back to + solib-search-path's basename matching instead. This also covers + libraries not installed into the standard libdirs. - But most cross debugging tools like gdb, perf, and systemtap need to find - executable/library first and through it debuglink note find corresponding - symbols file. Therefore the library paths from the rootfs are added as well. - - Note: For the devtool modified recipe compiled from the IDE, the debug - symbols are taken from the unstripped binaries in the image folder. - Also, devtool deploy-target takes the files from the image folder. - debug symbols in the image folder refer to the corresponding source files - with absolute paths of the build machine. Debug symbols found in the - rootfs-dbg are relocated and contain paths which refer to the source files - installed on the target device e.g. /usr/src/... + D is listed first, ahead of rootfs-dbg/rootfs. For every other + library, i.e. one provided by another package, debug symbols are + grabbed from the -dbg packages in rootfs-dbg. gdb, perf, and + systemtap need to find the executable/library itself first, and + through its debuglink find the symbols file, so the plain rootfs + paths are added too. """ base_libdir = self.base_libdir.lstrip('/') libdir = self.libdir.lstrip('/') - so_paths = [ + # dedupe (e.g. base_libdir = libdir) while keeping the order (using dict instead of set) + so_paths = dict.fromkeys([ + # This recipe's own rebuilt libraries/plugins, ahead of rootfs-dbg/rootfs. + *self._find_elf_dirs(self.d), # debug symbols for package_debug_split_style: debug-with-srcpkg or .debug os.path.join(image.rootfs_dbg, base_libdir, ".debug"), os.path.join(image.rootfs_dbg, libdir, ".debug"), @@ -858,13 +881,12 @@ class RecipeModified: # With image-combined-dbg.bbclass the binaries are copied into rootfs-dbg os.path.join(image.rootfs_dbg, base_libdir), os.path.join(image.rootfs_dbg, libdir), - # Without image-combined-dbg.bbclass the binaries are only in rootfs. - # Note: Stepping into source files located in rootfs-dbg does not - # work without image-combined-dbg.bbclass yet. + # Without image-combined-dbg.bbclass the binaries are only in rootfs + # (stepping into rootfs-dbg sources needs image-combined-dbg.bbclass) os.path.join(image.rootfs, base_libdir), os.path.join(image.rootfs, libdir) - ] - return so_paths + ]) + return list(so_paths) def solib_search_path_str(self, image): """Return a : separated list of paths usable by GDB's set solib-search-path""" -- 2.55.0
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#245235): https://lists.openembedded.org/g/openembedded-core/message/245235 Mute This Topic: https://lists.openembedded.org/mt/121125163/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
