diff --git a/libgloss/arm/syscalls.c b/libgloss/arm/syscalls.c
index 710a741ee..162059fc0 100644
--- a/libgloss/arm/syscalls.c
+++ b/libgloss/arm/syscalls.c
@@ -15,6 +15,7 @@
 #include <reent.h>
 #include <unistd.h>
 #include <sys/wait.h>
+#include <limits.h>
 #include "swi.h"
 
 /* Forward prototypes.  */
@@ -46,6 +47,7 @@ void	initialise_monitor_handles (void);
 static int	checkerror	(int);
 static int	error		(int);
 static int	get_errno	(void);
+static int	path_is_dir	(const char *);
 
 /* Semihosting utilities.  */
 static void initialise_semihosting_exts (void);
@@ -346,6 +348,46 @@ checkerror (int result)
   return result;
 }
 
+/* Check if the given path is likely a directory. */
+static int
+path_is_dir (const char *path)
+{
+  size_t path_len;
+  size_t dir_len;
+  char dir_path[PATH_MAX + 3];
+  int fd;
+
+  path_len = strlen (path);
+  if (path_len == 0)
+    return 0;
+
+  if (path_len + 3 > sizeof (dir_path))
+    {
+      errno = ENAMETOOLONG;
+      return -1;
+    }
+
+  /* Build a new string that ends with "/.". */
+  memcpy (dir_path, path, path_len);
+  dir_len = path_len;
+  if (dir_path[dir_len - 1] != '/')
+    dir_path[dir_len++] = '/';
+  dir_path[dir_len++] = '.';
+  dir_path[dir_len] = '\0';
+
+  /* Try to open the directory. */
+  fd = _open (dir_path, O_RDONLY);
+
+  /* Error means that path either does not exist
+   * or is not a directory. */
+  if (fd == -1)
+    return 0;
+
+  /* Not interested in the error.  */
+  _close (fd);
+  return 1;
+}
+
 /* fh, is a valid internal file handle.
    ptr, is a null terminated string.
    len, is the length in bytes to read. 
@@ -738,10 +780,14 @@ _swistat (int fd, struct stat * st)
       return -1;
     }
 
-  /* Always assume a character device,
-     with 1024 byte blocks. */
-  st->st_mode |= S_IFCHR;
   st->st_blksize = 1024;
+  if (_isatty (fd))
+    {
+      /* Assume character device. */
+      st->st_mode |= S_IFCHR;
+      return 0;
+    }
+
 #ifdef ARM_RDI_MONITOR
   res = checkerror (do_AngelSWI (AngelSWI_Reason_FLen, &pfd->handle));
 #else
@@ -752,7 +798,19 @@ _swistat (int fd, struct stat * st)
   checkerror (res);
 #endif
   if (res == -1)
-    return -1;
+    {
+      if (errno == EISDIR)
+	{
+	  /* Path is a directory. */
+	  st->st_mode |= S_IFDIR;
+	  return 0;
+	}
+      return -1;
+    }
+
+  /* Assume regular file. */
+  st->st_mode |= S_IFREG;
+
   /* Return the file size. */
   st->st_size = res;
   return 0;
@@ -770,12 +828,23 @@ _stat (const char *fname, struct stat *st)
 {
   int fd, res;
   memset (st, 0, sizeof (* st));
+  res = path_is_dir (fname);
+  if (res == 1)
+    {
+      st->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
+      st->st_blksize = 1024;
+      return 0;
+    }
+  else if (res == -1)
+    return -1;
+
   /* The best we can do is try to open the file readonly.  If it exists,
      then we can guess a few things about it.  */
   if ((fd = _open (fname, O_RDONLY)) == -1)
     return -1;
-  st->st_mode |= S_IFREG | S_IREAD;
   res = _swistat (fd, st);
+  if (res == 0)
+    st->st_mode |= S_IREAD;
   /* Not interested in the error.  */
   _close (fd); 
   return res;
