diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 38c498b1901..fb22cbbf82a 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -859,7 +859,9 @@ dwarf2_per_bfd::dwarf2_per_bfd (bfd *obfd, const dwarf2_debug_sections *names,
 				bool can_copy_)
   : obfd (obfd),
     can_copy (can_copy_),
-    captured_cwd (current_directory),
+    captured_cwd (current_directory != nullptr
+		  ? std::optional<std::string> (current_directory)
+		  : std::nullopt),
     captured_debug_dir (debug_file_directory)
 {
   if (names == NULL)
@@ -6735,7 +6737,10 @@ try_open_dwop_file (dwarf2_per_bfd *per_bfd, const char *file_name, int is_dwp,
 
   gdb::unique_xmalloc_ptr<char> absolute_name;
   desc = openp (search_path, flags, file_name, O_RDONLY | O_BINARY,
-		&absolute_name, per_bfd->captured_cwd.c_str ());
+		&absolute_name,
+		(per_bfd->captured_cwd.has_value ()
+		 ? per_bfd->captured_cwd->c_str ()
+		 : nullptr));
   if (desc < 0)
     return NULL;
 
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 15dd2abf3a1..a7c1861a64d 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -757,8 +757,11 @@ struct dwarf2_per_bfd
     abstract_to_concrete;
 
   /* Current directory, captured at the moment that object this was
-     created.  */
-  std::string captured_cwd;
+     created.  If nullopt, the working directory was unavailable
+     which means getcwd failed either due to directory deletion or
+     permission issues. So paths should be treated as absolute.  */
+  std::optional<std::string> captured_cwd;
+
   /* Captured copy of debug_file_directory.  */
   std::string captured_debug_dir;
 };
diff --git a/gdb/testsuite/gdb.base/getcwd-fail-helper.c b/gdb/testsuite/gdb.base/getcwd-fail-helper.c
new file mode 100644
index 00000000000..63ffff07a31
--- /dev/null
+++ b/gdb/testsuite/gdb.base/getcwd-fail-helper.c
@@ -0,0 +1,84 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2026 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Helper to reproduce getcwd failure by deleting cwd via child process.  */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+int
+main (int argc, char *argv[])
+{
+  const char *temp_dir = argv[1];
+  const char *gdb_path = argv[2];
+
+  /* Create and change to temp directory.  */
+  if (mkdir (temp_dir, 0755) != 0)
+    {
+      perror ("mkdir failed");
+      return 1;
+    }
+
+  if (chdir (temp_dir) != 0)
+    {
+      perror ("chdir failed");
+      return 1;
+    }
+
+  /* child deletes directory, parent execs GDB.  */
+  pid_t pid = fork ();
+  if (pid < 0)
+    {
+      perror ("fork failed");
+      return 1;
+    }
+
+  if (pid == 0)
+    {
+      /* cd to / and delete the temp directory.  */
+      if (chdir ("/") != 0)
+        exit (1);
+
+      if (rmdir (temp_dir) != 0)
+        exit (1);
+
+      exit (0);
+    }
+
+  /* wait for child to delete directory.  */
+  int status;
+  waitpid (pid, &status, 0);
+
+  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
+    {
+      fprintf (stderr, "Failed to delete directory\n");
+      return 1;
+    }
+
+  /* Exec GDB.  */
+  char **gdb_args = malloc ((argc - 1) * sizeof (char *));
+  gdb_args[0] = (char *) gdb_path;
+  for (int i = 3; i < argc; i++)
+    gdb_args[i - 2] = argv[i];
+  gdb_args[argc - 2] = NULL;
+
+  execv (gdb_path, gdb_args);
+  perror ("execv failed");
+  return 1;
+}
diff --git a/gdb/testsuite/gdb.base/getcwd-fail.c b/gdb/testsuite/gdb.base/getcwd-fail.c
new file mode 100644
index 00000000000..5fecf0bbd93
--- /dev/null
+++ b/gdb/testsuite/gdb.base/getcwd-fail.c
@@ -0,0 +1,20 @@
+ /* Copyright 2026 Free Software Foundation, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/getcwd-fail.exp b/gdb/testsuite/gdb.base/getcwd-fail.exp
new file mode 100644
index 00000000000..1596bfbd761
--- /dev/null
+++ b/gdb/testsuite/gdb.base/getcwd-fail.exp
@@ -0,0 +1,76 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test GDB when current working directory has been deleted.
+# Reproduces crash: getcwd() returns NULL.
+
+# Run the test only on native configurations.
+require isnative
+require {!is_remote target}
+
+require {is_any_target "*-*-linux*" "*-*-aix*"}
+
+standard_testfile .c
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug}]} {
+    return -1
+}
+
+# Compile helper program
+set helper_src "${srcdir}/${subdir}/getcwd-fail-helper.c"
+set helper_bin [standard_output_file "getcwd-fail-helper"]
+
+# Debug needs to be there so we can trigger getcwd the dwarf2/read.c code.
+if {[gdb_compile $helper_src $helper_bin executable {debug}] != ""} {
+    untested "failed to compile helper"
+    return -1
+}
+
+set temp_dir [standard_output_file "temp_getcwd_test"]
+set gdb_path [transform $GDB]
+
+# The test code creates temp dir, child deletes it, parent execs GDB
+set test "gdb in deleted cwd"
+set spawn_id [remote_spawn host "$helper_bin $temp_dir $gdb_path -nw -nx -q $binfile"]
+
+set crashed 0
+
+remote_expect host 30 {
+    -re "terminate called.*logic_error.*basic_string.*construction from null" {
+        set crashed 1
+        exp_continue
+    }
+    -re "Fatal signal.*IOT/Abort" {
+        set crashed 1
+        exp_continue
+    }
+    -re "$gdb_prompt $" {
+        if {$crashed} {
+            fail "$test - crashed"
+        } else {
+            pass "$test"
+        }
+    }
+    eof {
+        if {$crashed} {
+            fail "$test - crashed with std::logic_error"
+        } else {
+            pass "$test"
+        }
+    }
+    timeout {
+        fail "$test - timeout"
+    }
+}
