--- coregrind/m_ume/elf.c.orig
+++ coregrind/m_ume/elf.c
@@ -26,7 +26,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
+#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) || defined(VGO_openbsd)
 
 #include "pub_core_basics.h"
 #include "pub_core_vki.h"
@@ -51,7 +51,11 @@
 #  define _FILE_OFFSET_BITS 64
 #endif
 /* This is for ELF types etc, and also the AT_ constants. */
+#if !defined(VGO_openbsd)
 #include <elf.h>
+#else
+#include <gelf.h>
+#endif
 #if defined(VGO_solaris)
 #  include <sys/fasttrap.h> // PT_SUNWDTRACE_SIZE
 #  if defined(SOLARIS_PT_SUNDWTRACE_THRP)
@@ -398,6 +402,7 @@
    Int    i;
    SysRes res;
    ESZ(Addr) elfbrk = 0;
+#if !defined(VGO_openbsd)
 
    for (i = 0; i < e->e.e_phnum; i++) {
       ESZ(Phdr) *ph = &e->p[i];
@@ -414,7 +419,41 @@
       if (brkaddr > elfbrk)
          elfbrk = brkaddr;
    }
+#else
+   ESZ(Word) mapsize;
+   ESZ(Addr) base_offset, base_vaddr, base_vlimit, baseaddr;
+   ESZ(Phdr) *ph0, *phlast;
 
+   if (e->e.e_phnum < 1) {
+      VG_(printf)("valgrind: m_ume.c: too few sections\n");
+      return 1;
+   }
+
+   /* Map the entire address space of the object. */
+   ph0 = NULL;
+   phlast = NULL;
+   for (i = 1; i < e->e.e_phnum; i++) {
+      ESZ(Phdr) *ph = &e->p[i];
+      if (ph->p_type != PT_LOAD)
+         continue;
+      if (ph0 == NULL)
+         ph0 = ph;
+      if (phlast == NULL || ph->p_vaddr > phlast->p_vaddr)
+         phlast = &e->p[i];
+   }
+   if (ph0 == NULL || phlast == NULL) {
+      VG_(printf)("valgrind: m_ume.c: too few loadable sections\n");
+      return 1;
+   }
+   base_offset = VG_PGROUNDDN(ph0->p_offset);
+   base_vaddr = VG_PGROUNDDN(ph0->p_vaddr);
+   base_vlimit = VG_PGROUNDUP(phlast->p_vaddr + phlast->p_memsz);
+   mapsize = base_vlimit - base_vaddr;
+   baseaddr = VG_PGROUNDDN(ph0->p_vaddr + base);
+   res = VG_(am_mmap_anon_fixed_client)(baseaddr, mapsize, VKI_PROT_NONE);
+   check_mmap(res, baseaddr, mapsize);
+#endif
+
    for (i = 0; i < e->e.e_phnum; i++) {
       ESZ(Phdr) *ph = &e->p[i];
       ESZ(Addr) addr, bss, brkaddr;
@@ -435,8 +474,24 @@
       filesz  = ph->p_filesz;
       bss     = addr+filesz;
       memsz   = ph->p_memsz;
+#if defined(VGO_openbsd)
+      // On OpenBSD, p_filesz of the BSS area is set to 0. Also, if the lower
+      // 12 bits of addr is 0, bss and addr have the same value. Therefore,
+      // VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) = 0, the following
+      // `if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr)' statement becomes false,
+      // and VG_(am_mmap_file_fixed_client)() is not called. Additionally,
+      // di_notify_ACHIEVE_ACCEPT_STATE() is not called and the first_epoch
+      // variable in DebugInfo is not set to a valid value.
+      if ((addr & 0xfff) == 0 && filesz == 0)
+         bss += memsz;
+#endif
       brkaddr = addr+memsz;
 
+#if defined(VGO_openbsd)
+      if (brkaddr > elfbrk)
+         elfbrk = brkaddr;
+#endif
+
       // Tom says: In the following, do what the Linux kernel does and only
       // map the pages that are required instead of rounding everything to
       // the specified alignment (ph->p_align).  (AMD64 doesn't work if you
@@ -460,6 +515,7 @@
       if (memsz > filesz) {
          UInt bytes;
 
+#if !defined(VGO_openbsd)
          bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
          if (bytes > 0) {
             if (0) VG_(debugLog)(0,"ume","mmap_anon_fixed_client #2\n");
@@ -478,6 +534,42 @@
             bytes = VKI_PAGE_SIZE - bytes;
             VG_(memset)((void *)bss, 0, bytes);
          }
+#else
+         bytes = VG_PGROUNDUP(bss) - bss;
+         if (bytes > 0) {
+            /* Make sure the end of the segment is writable */
+            if ((prot & VKI_PROT_WRITE) == 0) {
+               res = VG_(am_do_mprotect_NO_NOTIFY)((UWord)VG_PGROUNDDN(bss),
+                  VKI_PAGE_SIZE, prot|VKI_PROT_WRITE);
+               if (sr_isError(res)) {
+                  VG_(printf)("valgrind: m_ume.c: mprotect failed\n");
+                  return (1);
+               }
+            }
+            VG_(memset)((char *)bss, 0, bytes);
+            /* Reset the data protection back */
+            if ((prot & VKI_PROT_WRITE) == 0) {
+               res = VG_(am_do_mprotect_NO_NOTIFY)((UWord)VG_PGROUNDDN(bss),
+                  VKI_PAGE_SIZE, prot);
+               if (sr_isError(res)) {
+                  VG_(printf)("valgrind: m_ume.c: mprotect failed\n");
+                  return (1);
+               }
+            }
+         }
+
+         /* Overlay the BSS segment onto the proper region. */
+         if (VG_PGROUNDUP(brkaddr) > VG_PGROUNDUP(bss)) {
+            res = VG_(am_do_mprotect_NO_NOTIFY)((UWord)VG_PGROUNDUP(bss),
+               VG_PGROUNDUP(brkaddr) - VG_PGROUNDUP(bss), prot);
+            if (sr_isError(res)) {
+               VG_(printf)("valgrind: m_ume.c: mprotect failed\n");
+               return (1);
+            }
+            VG_(am_notify_mprotect)((Addr)VG_PGROUNDUP(bss),
+               VG_PGROUNDUP(brkaddr) - VG_PGROUNDUP(bss), prot);
+         }
+#endif
       }
    }
 
@@ -879,7 +971,7 @@
    return 0;
 }
 
-#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
+#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) || defined(VGO_openbsd)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
