From 5193d1f404a47dffdc7421ca38986e9a6d216a9f Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 14 Dec 2018 11:59:23 -0700 Subject: [PATCH] Add gdb to the build This optionally adds gdb to the Rust build, allowing gdb to be installed via rustup. This makes it simpler to make debuginfo changes, as gdb updates can now be shipped immediately. If gdb is not checked out, nothing changes. The build is perhaps a bit chatty, as gdb's "make" and "make install" are run each time, even if they do nothing. rust-gdb is modified to prefer the gdb installed by rustup. This is analogous to what was done for rust-lldb. The built gdb requires Python 2.7 as a shared library (other dependencies are statically linked). This is a least-common-denominator Python that is widely available and stable; dynamic linking is used to avoid breaking existing gdb Python code that might load shared libraries that themselves require a dynamic libpython. To avoid problems here, a small wrapper program is used that attemps to dlopen libpython; with failures being reported to the user in an intelligible way. Two of the Linux dist builds are updated to build gdb. More could be added if need be. If gdb is built as part of the build, and if no other gdb was specified in config.toml, then the just-built gdb will be used for debuginfo testing. Closes #34457 --- .gitmodules | 4 + config.toml.example | 3 + src/bootstrap/bootstrap.py | 4 + src/bootstrap/builder.rs | 2 + src/bootstrap/config.rs | 4 + src/bootstrap/configure.py | 1 + src/bootstrap/dist.rs | 99 ++++++++++++++++++++++ src/bootstrap/lib.rs | 13 +++ src/bootstrap/native.rs | 42 +++++++++ src/bootstrap/sanity.rs | 3 +- src/bootstrap/test.rs | 6 ++ src/ci/docker/dist-i686-linux/Dockerfile | 9 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 9 +- src/etc/rust-gdb | 14 ++- src/tools/build-manifest/src/main.rs | 17 ++++ src/tools/gdb | 1 + src/tools/tidy/src/lib.rs | 1 + 17 files changed, 227 insertions(+), 5 deletions(-) create mode 160000 src/tools/gdb diff --git a/.gitmodules b/.gitmodules index 70164d48a307b..62a79245484aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -52,6 +52,10 @@ path = src/tools/clang url = https://github.com/rust-lang-nursery/clang.git branch = rust-release-80-v2 +[submodule "src/tools/gdb"] + path = src/tools/gdb + url = https://github.com/rust-dev-tools/gdb.git + branch = rust-8.2 [submodule "src/doc/rustc-guide"] path = src/doc/rustc-guide url = https://github.com/rust-lang/rustc-guide.git diff --git a/config.toml.example b/config.toml.example index f75e220de47e7..1d35a2cac996b 100644 --- a/config.toml.example +++ b/config.toml.example @@ -383,6 +383,9 @@ # This is only built if LLVM is also being built. #lldb = false +# Indicates whether GDB will also be built. +#build-gdb = false + # Whether to deny warnings in crates #deny-warnings = true diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d143dffb24be5..6a9aee64f1cb3 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -723,6 +723,10 @@ def update_submodules(self): config = self.get_toml('lldb') if config is None or config == 'false': continue + if module.endswith("gdb"): + config = self.get_toml('build-gdb') + if config is None or config == 'false': + continue check = self.check_submodule(module, slow_submodules) filtered_submodules.append((module, check)) submodules_names.append(module) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 405fc871eef76..626e9e35d8c1d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -363,6 +363,7 @@ impl<'a> Builder<'a> { tool::Rustdoc, tool::Clippy, native::Llvm, + native::Gdb, tool::Rustfmt, tool::Miri, native::Lld @@ -461,6 +462,7 @@ impl<'a> Builder<'a> { dist::Clippy, dist::LlvmTools, dist::Lldb, + dist::Gdb, dist::Extended, dist::HashSign ), diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 2ae9da9c085d4..79335b8556523 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -92,6 +92,8 @@ pub struct Config { pub lldb_enabled: bool, pub llvm_tools_enabled: bool, + pub gdb_enabled: bool, + // rust codegen options pub rust_optimize: bool, pub rust_codegen_units: Option, @@ -320,6 +322,7 @@ struct Rust { wasm_syscall: Option, lld: Option, lldb: Option, + build_gdb: Option, llvm_tools: Option, deny_warnings: Option, backtrace_on_ice: Option, @@ -552,6 +555,7 @@ impl Config { set(&mut config.wasm_syscall, rust.wasm_syscall); set(&mut config.lld_enabled, rust.lld); set(&mut config.lldb_enabled, rust.lldb); + set(&mut config.gdb_enabled, rust.build_gdb); set(&mut config.llvm_tools_enabled, rust.llvm_tools); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 5467c9f9d5bf9..1afff20d4f604 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -70,6 +70,7 @@ def v(*args): o("full-tools", None, "enable all tools") o("lld", "rust.lld", "build lld") o("lldb", "rust.lldb", "build lldb") +o("gdb", "rust.build-gdb", "build gdb") o("missing-tools", "dist.missing-tools", "allow failures when building tools") # Optimization and debugging options. These may be overridden by the release diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 927f9bf8ddbca..4d56a6f4c5bb0 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -35,6 +35,11 @@ use crate::tool::{self, Tool}; use crate::cache::{INTERNER, Interned}; use time; +#[cfg(unix)] +use std::os::unix::fs::symlink as symlink_file; +#[cfg(windows)] +use std::os::windows::fs::symlink_file; + pub fn pkgname(builder: &Builder, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, builder.cargo_package_vers()) @@ -48,6 +53,8 @@ pub fn pkgname(builder: &Builder, component: &str) -> String { format!("{}-{}", component, builder.llvm_tools_package_vers()) } else if component == "lldb" { format!("{}-{}", component, builder.lldb_package_vers()) + } else if component == "gdb" { + format!("{}-{}", component, builder.gdb_package_vers()) } else { assert!(component.starts_with("rust")); format!("{}-{}", component, builder.rust_package_vers()) @@ -1400,6 +1407,7 @@ impl Step for Extended { let llvm_tools_installer = builder.ensure(LlvmTools { stage, target }); let clippy_installer = builder.ensure(Clippy { stage, target }); let lldb_installer = builder.ensure(Lldb { target }); + let gdb_installer = builder.ensure(Gdb { target }); let mingw_installer = builder.ensure(Mingw { host: target }); let analysis_installer = builder.ensure(Analysis { compiler: builder.compiler(stage, self.host), @@ -1440,6 +1448,7 @@ impl Step for Extended { tarballs.extend(rustfmt_installer.clone()); tarballs.extend(llvm_tools_installer); tarballs.extend(lldb_installer); + tarballs.extend(gdb_installer); tarballs.push(analysis_installer); tarballs.push(std_installer); if builder.config.docs { @@ -1873,6 +1882,7 @@ impl Step for HashSign { cmd.arg(builder.package_vers(&builder.release_num("rustfmt"))); cmd.arg(builder.llvm_tools_package_vers()); cmd.arg(builder.lldb_package_vers()); + cmd.arg(builder.gdb_package_vers()); cmd.arg(addr); builder.create_dir(&distdir(builder)); @@ -2121,3 +2131,92 @@ impl Step for Lldb { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } } + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Gdb { + pub target: Interned, +} + +impl Step for Gdb { + type Output = Option; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = false; + + fn should_run(run: ShouldRun) -> ShouldRun { + let builder = run.builder; + run.path("src/tools/gdb").default_condition(builder.config.gdb_enabled) + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Gdb { + target: run.target, + }); + } + + fn run(self, builder: &Builder) -> Option { + let target = self.target; + + if builder.config.dry_run { + return None; + } + + let gdb_install = builder.gdb_out(target).join("install"); + let bindir = gdb_install.join("bin"); + let gdb_exe = bindir.join(exe("gdb", &target)); + if !gdb_exe.exists() { + return None; + } + + builder.info(&format!("Dist Gdb ({})", target)); + let src = builder.src.join("src/tools/gdb"); + let name = pkgname(builder, "gdb"); + + let tmp = tmpdir(builder); + let image = tmp.join("gdb-image"); + drop(fs::remove_dir_all(&image)); + + // Prepare the image directory + let root = image.join("lib/rustlib").join(&*target); + let dst = root.join("bin"); + t!(fs::create_dir_all(&dst)); + // Install gdb as real-gdb, and run-gdb as gdb. + let filename = bindir.join(exe("gdb", &target)); + builder.copy(&filename, &dst.join(exe("real-gdb", &target))); + let filename = bindir.join(exe("run-gdb", &target)); + builder.copy(&filename, &dst.join(exe("gdb", &target))); + + // gdb "share" files. + let sharedir = gdb_install.join("share/gdb"); + let dst = root.join("share/gdb"); + t!(fs::create_dir_all(&dst)); + builder.cp_r(&sharedir, &dst); + + // We want to pick up the system auto-loads. + t!(symlink_file(&Path::new("/usr/share/gdb/auto-load"), &dst.join("auto-load"))); + + // Prepare the overlay + let overlay = tmp.join("gdb-overlay"); + drop(fs::remove_dir_all(&overlay)); + builder.create_dir(&overlay); + builder.install(&src.join("COPYING3"), &overlay, 0o644); + builder.create(&overlay.join("version"), &builder.gdb_vers()); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=gdb-installed.") + .arg("--image-dir").arg(&image) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) + .arg("--non-installed-overlay").arg(&overlay) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=gdb"); + + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) + } +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index c5b8f19eee6fb..850088ec97081 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -594,6 +594,11 @@ impl Build { self.out.join(&*target).join("lld") } + /// Output directory for gdb build. + fn gdb_out(&self, target: Interned) -> PathBuf { + self.out.join(&*target).join("gdb") + } + /// Output directory for all documentation for a target fn doc_out(&self, target: Interned) -> PathBuf { self.out.join(&*target).join("doc") @@ -1047,6 +1052,14 @@ impl Build { self.rust_version() } + fn gdb_package_vers(&self) -> String { + self.package_vers(&self.rust_version()) + } + + fn gdb_vers(&self) -> String { + self.rust_version() + } + fn llvm_link_tools_dynamically(&self, target: Interned) -> bool { (target.contains("linux-gnu") || target.contains("apple-darwin")) } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index d9f51f6fd3d07..86ad69d85bf46 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -473,6 +473,48 @@ impl Step for Lld { } } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Gdb { + pub target: Interned, +} + +impl Step for Gdb { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = false; + + fn should_run(run: ShouldRun) -> ShouldRun { + let builder = run.builder; + run.path("src/tools/gdb").default_condition(builder.config.gdb_enabled) + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Gdb { + target: run.target + }); + } + + fn run(self, builder: &Builder) { + if builder.config.dry_run { + return; + } + + let root = builder.gdb_out(self.target); + let build = root.join("build"); + let install = root.join("install"); + let src = builder.src.join("src/tools/gdb"); + t!(fs::create_dir_all(&build)); + t!(fs::create_dir_all(&install)); + + let mut cmd = Command::new(&src.join("build-for-rust.sh")); + cmd.arg(&src) + .arg(&build) + .arg(&install); + + builder.run(&mut cmd); + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TestHelpers { pub target: Interned, diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index f585495b0aa94..b2dfc301ff630 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -126,8 +126,7 @@ pub fn check(build: &mut Build) { .or_else(|| cmd_finder.maybe_have("node")) .or_else(|| cmd_finder.maybe_have("nodejs")); - build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p)) - .or_else(|| cmd_finder.maybe_have("gdb")); + build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p)); // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 11932d58ceac6..e94c6f963330d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1111,8 +1111,14 @@ impl Step for Compiletest { cmd.arg("--lldb-python").arg(builder.python()); } + // If config.toml specifies a gdb, use it; otherwise, if we + // built a gdb, prefer that. if let Some(ref gdb) = builder.config.gdb { cmd.arg("--gdb").arg(gdb); + } else if builder.config.gdb_enabled { + cmd.arg("--gdb").arg(builder.gdb_out(target).join("install/bin/gdb")); + } else { + cmd.arg("--gdb").arg("gdb"); } let run = |cmd: &mut Command| { diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index b087ea7899f4c..aca828702a26c 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -23,7 +23,13 @@ RUN yum upgrade -y && yum install -y \ pkgconfig \ wget \ autoconf \ - gettext + gettext \ + xz-static \ + xz-devel \ + expat-static \ + expat-devel \ + ncurses-static \ + ncurses-devel ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib @@ -95,6 +101,7 @@ ENV HOSTS=i686-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ + --enable-gdb \ --enable-sanitizers \ --enable-profiler \ --set target.i686-unknown-linux-gnu.linker=clang \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index a1a778c2b2c61..cd870888c3c82 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -23,7 +23,13 @@ RUN yum upgrade -y && yum install -y \ pkgconfig \ wget \ autoconf \ - gettext + gettext \ + xz-static \ + xz-devel \ + expat-static \ + expat-devel \ + ncurses-static \ + ncurses-devel ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib @@ -95,6 +101,7 @@ ENV HOSTS=x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ + --enable-gdb \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index 743952a5bef89..a1a526b4abe69 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -16,10 +16,22 @@ set -e RUSTC_SYSROOT=`rustc --print=sysroot` GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" +if [ -z "$RUST_GDB" ]; then + # Find the host triple so we can find lldb in rustlib. + host=`rustc -vV | sed -n -e 's/^host: //p'` + RUST_GDB=gdb + if [ -f "$RUSTC_SYSROOT/lib/rustlib/$host/bin/gdb" ]; then + bin="$RUSTC_SYSROOT/lib/rustlib/$host/bin" + # Pass the path to real-gdb to the wrapper. This avoids + # having to modify PATH here, which might possibly be + # confusing inside gdb. + RUST_GDB="$bin/gdb $bin/real-gdb" + fi +fi + # Run GDB with the additional arguments that load the pretty printers # Set the environment variable `RUST_GDB` to overwrite the call to a # different/specific command (defaults to `gdb`). -RUST_GDB="${RUST_GDB:-gdb}" PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" exec ${RUST_GDB} \ --directory="$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index ea6c7115d39ab..bf06bf157ca1e 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -200,6 +200,7 @@ struct Builder { rustfmt_release: String, llvm_tools_release: String, lldb_release: String, + gdb_release: String, input: PathBuf, output: PathBuf, @@ -215,6 +216,7 @@ struct Builder { rustfmt_version: Option, llvm_tools_version: Option, lldb_version: Option, + gdb_version: Option, rust_git_commit_hash: Option, cargo_git_commit_hash: Option, @@ -223,6 +225,7 @@ struct Builder { rustfmt_git_commit_hash: Option, llvm_tools_git_commit_hash: Option, lldb_git_commit_hash: Option, + gdb_git_commit_hash: Option, should_sign: bool, } @@ -251,6 +254,7 @@ fn main() { let rustfmt_release = args.next().unwrap(); let llvm_tools_release = args.next().unwrap(); let lldb_release = args.next().unwrap(); + let gdb_release = args.next().unwrap(); let s3_address = args.next().unwrap(); // Do not ask for a passphrase while manually testing @@ -267,6 +271,7 @@ fn main() { rustfmt_release, llvm_tools_release, lldb_release, + gdb_release, input, output, @@ -282,6 +287,7 @@ fn main() { rustfmt_version: None, llvm_tools_version: None, lldb_version: None, + gdb_version: None, rust_git_commit_hash: None, cargo_git_commit_hash: None, @@ -290,6 +296,7 @@ fn main() { rustfmt_git_commit_hash: None, llvm_tools_git_commit_hash: None, lldb_git_commit_hash: None, + gdb_git_commit_hash: None, should_sign, }.build(); @@ -305,6 +312,7 @@ impl Builder { self.llvm_tools_version = self.version("llvm-tools", "x86_64-unknown-linux-gnu"); // lldb is only built for macOS. self.lldb_version = self.version("lldb", "x86_64-apple-darwin"); + self.gdb_version = self.version("lldb", "x86_64-unknown-linux-gnu"); self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu"); self.cargo_git_commit_hash = self.git_commit_hash("cargo", "x86_64-unknown-linux-gnu"); @@ -314,6 +322,7 @@ impl Builder { self.llvm_tools_git_commit_hash = self.git_commit_hash("llvm-tools", "x86_64-unknown-linux-gnu"); self.lldb_git_commit_hash = self.git_commit_hash("lldb", "x86_64-unknown-linux-gnu"); + self.lldb_git_commit_hash = self.git_commit_hash("gdb", "x86_64-unknown-linux-gnu"); self.digest_and_sign(); let manifest = self.build_manifest(); @@ -353,6 +362,7 @@ impl Builder { self.package("rust-analysis", &mut manifest.pkg, TARGETS); self.package("llvm-tools-preview", &mut manifest.pkg, TARGETS); self.package("lldb-preview", &mut manifest.pkg, TARGETS); + self.package("gdb", &mut manifest.pkg, TARGETS); manifest.renames.insert("rls".to_owned(), Rename { to: "rls-preview".to_owned() }); manifest.renames.insert("rustfmt".to_owned(), Rename { to: "rustfmt-preview".to_owned() }); @@ -403,6 +413,7 @@ impl Builder { Component { pkg: "rustfmt-preview".to_string(), target: host.to_string() }, Component { pkg: "llvm-tools-preview".to_string(), target: host.to_string() }, Component { pkg: "lldb-preview".to_string(), target: host.to_string() }, + Component { pkg: "gdb".to_string(), target: host.to_string() }, Component { pkg: "rust-analysis".to_string(), target: host.to_string() }, ]); @@ -524,6 +535,8 @@ impl Builder { format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target) } else if component == "lldb" || component == "lldb-preview" { format!("lldb-{}-{}.tar.gz", self.lldb_release, target) + } else if component == "gdb" { + format!("gdb-{}-{}.tar.gz", self.gdb_release, target) } else { format!("{}-{}-{}.tar.gz", component, self.rust_release, target) } @@ -542,6 +555,8 @@ impl Builder { &self.llvm_tools_version } else if component == "lldb" || component == "lldb-preview" { &self.lldb_version + } else if component == "gdb" { + &self.gdb_version } else { &self.rust_version } @@ -560,6 +575,8 @@ impl Builder { &self.llvm_tools_git_commit_hash } else if component == "lldb" || component == "lldb-preview" { &self.lldb_git_commit_hash + } else if component == "gdb" { + &self.gdb_git_commit_hash } else { &self.rust_git_commit_hash } diff --git a/src/tools/gdb b/src/tools/gdb new file mode 160000 index 0000000000000..f1f53755e84e3 --- /dev/null +++ b/src/tools/gdb @@ -0,0 +1 @@ +Subproject commit f1f53755e84e32511afd7cd38ee9d71987e2662c diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 614d2053a432b..f028e1bd5111d 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -70,6 +70,7 @@ fn filter_dirs(path: &Path) -> bool { "src/tools/miri", "src/tools/lld", "src/tools/lldb", + "src/tools/gdb", "src/target", "src/stdsimd", "src/rust-sgx",