commit b65d60a46447c9af8a4763d5f720636fd7a84ff4
Author: Omar Sandoval <osandov@fb.com>
Date:   Mon Oct 7 01:30:35 2019 -0700

    libdwfl: add interface for evaluating DWARF expressions in a frame
    
    libdwfl can evaluate DWARF expressions in order to unwind the stack, but
    this functionality isn't exposed to clients of the library. Now that the
    pieces are in place, add dwfl_frame_eval_expr to provide this feature.

diff --git a/libdw/libdw.map b/libdw/libdw.map
index c1469c4ed..d06a29ed6 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -376,4 +376,5 @@ ELFUTILS_0.178 {
     dwfl_detach_thread;
     dwfl_frame_module;
     dwfl_frame_dwarf_frame;
+    dwfl_frame_eval_expr;
 } ELFUTILS_0.177;
diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c
index 9738ca72d..4c2df837f 100644
--- a/libdwfl/frame_unwind.c
+++ b/libdwfl/frame_unwind.c
@@ -787,3 +787,15 @@ dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias)
   *bias = state->bias;
   return state->frame;
 }
+
+bool
+dwfl_frame_eval_expr (Dwfl_Frame *state, const Dwarf_Op *ops, size_t nops,
+		      Dwarf_Addr *result)
+{
+  if (state->frame == NULL)
+    {
+      __libdwfl_seterrno (DWFL_E_NO_DWARF);
+      return false;
+    }
+  return expr_eval (state, state->frame, ops, nops, result, state->bias);
+}
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index b450816bb..90a3e1032 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -829,6 +829,12 @@ int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
 bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation)
   __nonnull_attribute__ (1, 2);
 
+/* Evaluate a DWARF expression in the context of a frame.  On success, returns
+   true and fills in *RESULT.  On error, returns false. */
+bool dwfl_frame_eval_expr (Dwfl_Frame *state, const Dwarf_Op *ops, size_t nops,
+			   Dwarf_Addr *result)
+  __nonnull_attribute__ (1, 2, 4);
+
 #ifdef __cplusplus
 }
 #endif
commit 55136ea91fd4d2a791573adf18e7247fb1dc866a
Author: Omar Sandoval <osandov@fb.com>
Date:   Mon Oct 7 01:25:31 2019 -0700

    libdwfl: cache Dwfl_Module and Dwarf_Frame for Dwfl_Frame
    
    The next change will need to have the Dwarf_Frame readily available, so
    rather than finding it again every time, let's cache it for reuse. The
    CFI frame can also be useful to clients of libdwfl, so add
    dwfl_frame_dwarf_frame to get it. Similarly, the Dwfl_Module is also
    frequently needed in conjunction with the frame, so cache it and add
    dwfl_frame_module.

diff --git a/libdw/libdw.map b/libdw/libdw.map
index f20ffc2f9..c1469c4ed 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -374,4 +374,6 @@ ELFUTILS_0.178 {
   global:
     dwfl_attach_thread;
     dwfl_detach_thread;
+    dwfl_frame_module;
+    dwfl_frame_dwarf_frame;
 } ELFUTILS_0.177;
diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c
index 61fad8b9c..3f660f7e0 100644
--- a/libdwfl/dwfl_frame.c
+++ b/libdwfl/dwfl_frame.c
@@ -94,6 +94,8 @@ state_alloc (Dwfl_Thread *thread)
   if (state == NULL)
     return NULL;
   state->thread = thread;
+  state->mod = NULL;
+  state->frame = NULL;
   state->signal_frame = false;
   state->initial_frame = true;
   state->pc_state = DWFL_FRAME_STATE_ERROR;
diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c
index d7dfa5a94..9738ca72d 100644
--- a/libdwfl/frame_unwind.c
+++ b/libdwfl/frame_unwind.c
@@ -523,6 +523,8 @@ new_unwound (Dwfl_Frame *state)
   state->unwound = unwound;
   unwound->thread = thread;
   unwound->unwound = NULL;
+  unwound->mod = NULL;
+  unwound->frame = NULL;
   unwound->signal_frame = false;
   unwound->initial_frame = false;
   unwound->pc_state = DWFL_FRAME_STATE_ERROR;
@@ -544,6 +546,8 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
       __libdwfl_seterrno (DWFL_E_LIBDW);
       return;
     }
+  state->frame = frame;
+  state->bias = bias;
 
   Dwfl_Frame *unwound = new_unwound (state);
   if (unwound == NULL)
@@ -724,20 +728,20 @@ __libdwfl_frame_unwind (Dwfl_Frame *state)
      Then we need to unwind from the original, unadjusted PC.  */
   if (! state->initial_frame && ! state->signal_frame)
     pc--;
-  Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc);
-  if (mod == NULL)
+  state->mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc);
+  if (state->mod == NULL)
     __libdwfl_seterrno (DWFL_E_NO_DWARF);
   else
     {
       Dwarf_Addr bias;
-      Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (mod, &bias);
+      Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (state->mod, &bias);
       if (cfi_eh)
 	{
 	  handle_cfi (state, pc - bias, cfi_eh, bias);
 	  if (state->unwound)
 	    return;
 	}
-      Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias);
+      Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (state->mod, &bias);
       if (cfi_dwarf)
 	{
 	  handle_cfi (state, pc - bias, cfi_dwarf, bias);
@@ -770,3 +774,16 @@ __libdwfl_frame_unwind (Dwfl_Frame *state)
   assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET);
   state->unwound->signal_frame = signal_frame;
 }
+
+Dwfl_Module *
+dwfl_frame_module (Dwfl_Frame *state)
+{
+  return state->mod;
+}
+
+Dwarf_Frame *
+dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias)
+{
+  *bias = state->bias;
+  return state->frame;
+}
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index a22afc781..b450816bb 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -750,6 +750,16 @@ pid_t dwfl_thread_tid (Dwfl_Thread *thread)
 Dwfl_Thread *dwfl_frame_thread (Dwfl_Frame *state)
   __nonnull_attribute__ (1);
 
+/* Return module containing the PC for frame STATE.  Returns NULL if no module
+   contains the PC.  */
+Dwfl_Module *dwfl_frame_module (Dwfl_Frame *state)
+  __nonnull_attribute__ (1);
+
+/* Return CFI frame for frame STATE.  Returns NULL if no CFI frame was
+   found. */
+Dwarf_Frame *dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias)
+  __nonnull_attribute__ (1, 2);
+
 /* Called by Dwfl_Thread_Callbacks.set_initial_registers implementation.
    For every known continuous block of registers <FIRSTREG..FIRSTREG+NREGS)
    (inclusive..exclusive) set their content to REGS (array of NREGS items).
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 0dbcebf58..2aeeb66ab 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -257,6 +257,11 @@ struct Dwfl_Frame
   Dwfl_Thread *thread;
   /* Previous (outer) frame.  */
   Dwfl_Frame *unwound;
+  /* Module containing pc. */
+  Dwfl_Module *mod;
+  /* CFI frame containing pc. */
+  Dwarf_Frame *frame;
+  Dwarf_Addr bias;
   bool signal_frame : 1;
   bool initial_frame : 1;
   enum
commit 6a6c4d372f19a57004d1fc198258409dd78700aa
Author: Omar Sandoval <osandov@fb.com>
Date:   Mon Oct 7 01:22:39 2019 -0700

    libdwfl: add interface for attaching to/detaching from threads
    
    libdwfl has implementations of attaching to/detaching from threads and
    unwinding stack traces. However, that functionality is only available
    through the dwfl_thread_getframes interface, which isn't very flexible.
    This adds two new functions, dwfl_attach_thread and dwfl_detach_thread,
    which separate the thread stopping functionality out of
    dwfl_thread_getframes. Additionally, it makes dwfl_thread_getframes
    cache the stack trace for threads stopped this way. This makes it
    possible to use the frames after dwfl_thread_getframes returns.

diff --git a/libdw/libdw.map b/libdw/libdw.map
index decac05c7..f20ffc2f9 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -370,3 +370,8 @@ ELFUTILS_0.177 {
     # presume that NULL is only returned on error (otherwise ELF_K_NONE).
     dwelf_elf_begin;
 } ELFUTILS_0.175;
+ELFUTILS_0.178 {
+  global:
+    dwfl_attach_thread;
+    dwfl_detach_thread;
+} ELFUTILS_0.177;
diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c
index 5bbf850e8..61fad8b9c 100644
--- a/libdwfl/dwfl_frame.c
+++ b/libdwfl/dwfl_frame.c
@@ -103,6 +103,29 @@ state_alloc (Dwfl_Thread *thread)
   return state;
 }
 
+static Dwfl_Frame *
+start_unwind(Dwfl_Thread *thread)
+{
+  if (ebl_frame_nregs (thread->process->ebl) == 0)
+    {
+      __libdwfl_seterrno (DWFL_E_NO_UNWIND);
+      return NULL;
+    }
+  if (state_alloc (thread) == NULL)
+    {
+      __libdwfl_seterrno (DWFL_E_NOMEM);
+      return NULL;
+    }
+  if (! thread->process->callbacks->set_initial_registers (thread,
+							   thread->callbacks_arg))
+    {
+      free_states (thread->unwound);
+      thread->unwound = NULL;
+      return NULL;
+    }
+  return thread->unwound;
+}
+
 void
 internal_function
 __libdwfl_process_free (Dwfl_Process *process)
@@ -366,6 +389,45 @@ getthread (Dwfl *dwfl, pid_t tid,
    return err;
 }
 
+static int
+attach_thread_cb(Dwfl_Thread *thread, void *arg)
+{
+  Dwfl_Thread *copied = malloc (sizeof (*copied));
+  if (copied == NULL)
+    {
+      __libdwfl_seterrno (DWFL_E_NOMEM);
+      return DWARF_CB_ABORT;
+    }
+  *copied = *thread;
+  if (start_unwind (copied) == NULL)
+    {
+      free (copied);
+      return DWARF_CB_ABORT;
+    }
+  *(Dwfl_Thread **)arg = copied;
+  return DWARF_CB_OK;
+}
+
+Dwfl_Thread *
+dwfl_attach_thread(Dwfl *dwfl, pid_t tid)
+{
+  Dwfl_Thread *thread;
+  if (getthread (dwfl, tid, attach_thread_cb, &thread))
+    return NULL;
+  return thread;
+}
+
+void
+dwfl_detach_thread(Dwfl_Thread *thread)
+{
+  if (thread == NULL)
+    return;
+  if (thread->process->callbacks->thread_detach)
+    thread->process->callbacks->thread_detach (thread, thread->callbacks_arg);
+  free_states (thread->unwound);
+  free (thread);
+}
+
 struct one_thread
 {
   int (*callback) (Dwfl_Frame *frame, void *arg);
@@ -394,63 +456,55 @@ dwfl_thread_getframes (Dwfl_Thread *thread,
 		       int (*callback) (Dwfl_Frame *state, void *arg),
 		       void *arg)
 {
-  Ebl *ebl = thread->process->ebl;
-  if (ebl_frame_nregs (ebl) == 0)
-    {
-      __libdwfl_seterrno (DWFL_E_NO_UNWIND);
-      return -1;
-    }
-  if (state_alloc (thread) == NULL)
-    {
-      __libdwfl_seterrno (DWFL_E_NOMEM);
-      return -1;
-    }
   Dwfl_Process *process = thread->process;
-  if (! process->callbacks->set_initial_registers (thread,
-						   thread->callbacks_arg))
-    {
-      free_states (thread->unwound);
-      thread->unwound = NULL;
-      return -1;
-    }
+  int ret = -1;
+  bool cache = thread->unwound != NULL;
+  if (! cache && start_unwind (thread) == NULL)
+    return -1;
   Dwfl_Frame *state = thread->unwound;
-  thread->unwound = NULL;
+  if (! cache)
+    thread->unwound = NULL;
   if (! state_fetch_pc (state))
-    {
-      if (process->callbacks->thread_detach)
-	process->callbacks->thread_detach (thread, thread->callbacks_arg);
-      free_states (state);
-      return -1;
-    }
+    goto out;
   do
     {
       int err = callback (state, arg);
       if (err != DWARF_CB_OK)
 	{
-	  if (process->callbacks->thread_detach)
-	    process->callbacks->thread_detach (thread, thread->callbacks_arg);
-	  free_states (state);
-	  return err;
+	  ret = err;
+	  goto out;
+	}
+      if (state->unwound == NULL)
+	__libdwfl_frame_unwind (state);
+      else if (state->unwound->pc_state == DWFL_FRAME_STATE_ERROR)
+	{
+	  /* This frame was previously cached as an error.  We still return -1,
+	     but we don't know what the original error was.  */
+	  __libdwfl_seterrno (DWFL_E_NOERROR);
 	}
-      __libdwfl_frame_unwind (state);
       Dwfl_Frame *next = state->unwound;
-      /* The old frame is no longer needed.  */
-      free (state);
+      if (! cache)
+	{
+	  /* The old frame is no longer needed.  */
+	  free (state);
+	}
       state = next;
     }
   while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
 
-  Dwfl_Error err = dwfl_errno ();
-  if (process->callbacks->thread_detach)
-    process->callbacks->thread_detach (thread, thread->callbacks_arg);
-  if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
+  if (state && state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED)
+    ret = 0;
+out:
+  if (! cache)
     {
+      if (process->callbacks->thread_detach)
+	{
+	  Dwfl_Error err = dwfl_errno ();
+	  process->callbacks->thread_detach (thread, thread->callbacks_arg);
+	  __libdwfl_seterrno (err);
+	}
       free_states (state);
-      __libdwfl_seterrno (err);
-      return -1;
     }
-  assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
-  free_states (state);
-  return 0;
+  return ret;
 }
 INTDEF(dwfl_thread_getframes)
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index a0c1d3573..a22afc781 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -775,6 +775,18 @@ int dwfl_getthreads (Dwfl *dwfl,
 		     void *arg)
   __nonnull_attribute__ (1, 2);
 
+/* Attach to a thread.  The returned thread must be detached and freed with
+   dwfl_detach_thread.  Returns NULL on error.  This calls the
+   set_initial_registers callback.  While a thread is attached,
+   dwfl_thread_getframes will cache the unwound frames for the thread.  They
+   remain valid until dwfl_detach_thread is called.  */
+Dwfl_Thread *dwfl_attach_thread(Dwfl *dwfl, pid_t tid)
+  __nonnull_attribute__ (1);
+
+/* Detach from a thread that was attached with dwfl_attach_thread and free it.
+   This calls the detach_thread callback.  */
+void dwfl_detach_thread(Dwfl_Thread *thread);
+
 /* Iterate through the frames for a thread.  Returns zero if all frames
    have been processed by the callback, returns -1 on error, or the value of
    the callback when not DWARF_CB_OK.  -1 returned on error will
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index f631f9464..0dbcebf58 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -244,7 +244,8 @@ struct Dwfl_Thread
 {
   Dwfl_Process *process;
   pid_t tid;
-  /* Bottom (innermost) frame while we're initializing, NULL afterwards.  */
+  /* Bottom (innermost) frame.  If the stack trace is not cached, then this is
+     NULL except during initialization.  */
   Dwfl_Frame *unwound;
   void *callbacks_arg;
 };
commit 09d612a0892f1f49885c49ebc750020264031ca4
Author: Omar Sandoval <osandov@osandov.com>
Date:   Wed Sep 4 17:13:40 2019 -0700

    configure: Add --disable-shared
    
    If we're building the elfutils libraries to link statically, then
    there's no point in building shared libraries. Add --disable-shared
    which lets us skip over building any .so's and the _pic.a's that we
    build them from.

diff --git a/backends/Makefile.am b/backends/Makefile.am
index f4052125b..1beb661eb 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -34,7 +34,10 @@ endif
 AM_CPPFLAGS += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \
 	   -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw
 
-noinst_LIBRARIES = libebl_backends.a libebl_backends_pic.a
+noinst_LIBRARIES = libebl_backends.a
+if ENABLE_SHARED
+noinst_LIBRARIES += libebl_backends_pic.a
+endif
 
 modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \
 	  tilegx m68k bpf riscv csky
diff --git a/configure.ac b/configure.ac
index 68ab925c2..5fcdd518d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -70,6 +70,11 @@ AC_ARG_ENABLE([programs],
 	      [], [enable_programs=yes])
 AM_CONDITIONAL(ENABLE_PROGRAMS, test "$enable_programs" = yes)
 
+AC_ARG_ENABLE([shared],
+	      AS_HELP_STRING([--disable-shared], [do not build shared libraries]),
+	      [], [enable_shared=yes])
+AM_CONDITIONAL(ENABLE_SHARED, test "$enable_shared" = yes)
+
 AC_ARG_ENABLE(deterministic-archives,
 [AS_HELP_STRING([--enable-deterministic-archives],
 		[ar and ranlib default to -D behavior])], [
diff --git a/debuginfod/Makefile.am b/debuginfod/Makefile.am
index f4756c92f..dcae77d07 100644
--- a/debuginfod/Makefile.am
+++ b/debuginfod/Makefile.am
@@ -86,16 +86,20 @@ libdebuginfod.so$(EXEEXT): $(srcdir)/libdebuginfod.map $(libdebuginfod_so_LIBS)
 	@$(textrel_check)
 	$(AM_V_at)ln -fs $@ $@.$(VERSION)
 
+if ENABLE_SHARED
 install: install-am libdebuginfod.so
 	$(mkinstalldirs) $(DESTDIR)$(libdir)
 	$(INSTALL_PROGRAM) libdebuginfod.so $(DESTDIR)$(libdir)/libdebuginfod-$(PACKAGE_VERSION).so
 	ln -fs libdebuginfod-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdebuginfod.so.$(VERSION)
 	ln -fs libdebuginfod.so.$(VERSION) $(DESTDIR)$(libdir)/libdebuginfod.so
+endif
 
 uninstall: uninstall-am
+if ENABLE_SHARED
 	rm -f $(DESTDIR)$(libdir)/libdebuginfod-$(PACKAGE_VERSION).so
 	rm -f $(DESTDIR)$(libdir)/libdebuginfod.so.$(VERSION)
 	rm -f $(DESTDIR)$(libdir)/libdebuginfod.so
+endif
 	rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils
 
 EXTRA_DIST = libdebuginfod.map
diff --git a/libasm/Makefile.am b/libasm/Makefile.am
index b2bff9292..8a5a9d0f0 100644
--- a/libasm/Makefile.am
+++ b/libasm/Makefile.am
@@ -34,8 +34,10 @@ GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include)
 VERSION = 1
 
 lib_LIBRARIES = libasm.a
+if ENABLE_SHARED
 noinst_LIBRARIES = libasm_pic.a
 noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
+endif
 pkginclude_HEADERS = libasm.h
 
 libasm_a_SOURCES = asm_begin.c asm_abort.c asm_end.c asm_error.c \
@@ -72,16 +74,20 @@ libasm.so$(EXEEXT): $(srcdir)/libasm.map $(libasm_so_LIBS) $(libasm_so_DEPS)
 	@$(textrel_check)
 	$(AM_V_at)ln -fs $@ $@.$(VERSION)
 
+if ENABLE_SHARED
 install: install-am libasm.so
 	$(mkinstalldirs) $(DESTDIR)$(libdir)
 	$(INSTALL_PROGRAM) libasm.so $(DESTDIR)$(libdir)/libasm-$(PACKAGE_VERSION).so
 	ln -fs libasm-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libasm.so.$(VERSION)
 	ln -fs libasm.so.$(VERSION) $(DESTDIR)$(libdir)/libasm.so
+endif
 
 uninstall: uninstall-am
+if ENABLE_SHARED
 	rm -f $(DESTDIR)$(libdir)/libasm-$(PACKAGE_VERSION).so
 	rm -f $(DESTDIR)$(libdir)/libasm.so.$(VERSION)
 	rm -f $(DESTDIR)$(libdir)/libasm.so
+endif
 	rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils
 
 noinst_HEADERS = libasmP.h symbolhash.h
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index 59def7d1b..57dc698ed 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -38,7 +38,10 @@ LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=)
 LEX_OUTPUT_ROOT = lex.$(<F:lex.l=)
 AM_YFLAGS = -p$(<F:parse.y=)
 
-noinst_LIBRARIES = libcpu.a libcpu_pic.a
+noinst_LIBRARIES = libcpu.a
+if ENABLE_SHARED
+noinst_LIBRARIES += libcpu_pic.a
+endif
 
 noinst_HEADERS = i386_dis.h x86_64_dis.h
 
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 33b5838dc..0297520bb 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -35,8 +35,10 @@ AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf -pthread
 VERSION = 1
 
 lib_LIBRARIES = libdw.a
+if ENABLE_SHARED
 noinst_LIBRARIES = libdw_pic.a
 noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
+endif
 
 include_HEADERS = dwarf.h
 pkginclude_HEADERS = libdw.h known-dwarf.h
@@ -120,16 +122,20 @@ libdw.so$(EXEEXT): $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS)
 	@$(textrel_check)
 	$(AM_V_at)ln -fs $@ $@.$(VERSION)
 
+if ENABLE_SHARED
 install: install-am libdw.so
 	$(mkinstalldirs) $(DESTDIR)$(libdir)
 	$(INSTALL_PROGRAM) libdw.so $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so
 	ln -fs libdw-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdw.so.$(VERSION)
 	ln -fs libdw.so.$(VERSION) $(DESTDIR)$(libdir)/libdw.so
+endif
 
 uninstall: uninstall-am
+if ENABLE_SHARED
 	rm -f $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so
 	rm -f $(DESTDIR)$(libdir)/libdw.so.$(VERSION)
 	rm -f $(DESTDIR)$(libdir)/libdw.so
+endif
 	rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils
 
 libdwfl_objects = $(shell $(AR) t ../libdwfl/libdwfl.a)
diff --git a/libdwelf/Makefile.am b/libdwelf/Makefile.am
index a35a2873c..29cc51f59 100644
--- a/libdwelf/Makefile.am
+++ b/libdwelf/Makefile.am
@@ -34,7 +34,10 @@ AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdw \
 	       -I$(srcdir)/../libdwfl -I$(srcdir)/../libebl
 VERSION = 1
 
-noinst_LIBRARIES = libdwelf.a libdwelf_pic.a
+noinst_LIBRARIES = libdwelf.a
+if ENABLE_SHARED
+noinst_LIBRARIES += libdwelf_pic.a
+endif
 
 pkginclude_HEADERS = libdwelf.h
 noinst_HEADERS = libdwelfP.h
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 47bd62a5e..952be8ba5 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -35,7 +35,9 @@ AM_CPPFLAGS += -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
 VERSION = 1
 
 noinst_LIBRARIES = libdwfl.a
+if ENABLE_SHARED
 noinst_LIBRARIES += libdwfl_pic.a
+endif
 
 pkginclude_HEADERS = libdwfl.h
 
diff --git a/libebl/Makefile.am b/libebl/Makefile.am
index d0d475b83..b8e0eeb26 100644
--- a/libebl/Makefile.am
+++ b/libebl/Makefile.am
@@ -34,7 +34,10 @@ endif
 AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdw -I$(srcdir)/../libasm
 VERSION = 1
 
-noinst_LIBRARIES = libebl.a libebl_pic.a
+noinst_LIBRARIES = libebl.a
+if ENABLE_SHARED
+noinst_LIBRARIES += libebl_pic.a
+endif
 
 libebl_a_SOURCES = eblopenbackend.c eblclosebackend.c eblreloctypename.c \
 		   eblsegmenttypename.c eblsectiontypename.c \
diff --git a/libelf/Makefile.am b/libelf/Makefile.am
index d5d63f733..94e6e38f6 100644
--- a/libelf/Makefile.am
+++ b/libelf/Makefile.am
@@ -35,8 +35,10 @@ GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include)
 VERSION = 1
 
 lib_LIBRARIES = libelf.a
+if ENABLE_SHARED
 noinst_LIBRARIES = libelf_pic.a
 noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
+endif
 include_HEADERS = libelf.h gelf.h nlist.h
 
 noinst_HEADERS = abstract.h common.h exttypes.h gelf_xlate.h libelfP.h \
@@ -122,6 +124,7 @@ libelf.so$(EXEEXT): $(srcdir)/libelf.map $(libelf_so_LIBS) $(libelf_so_DEPS)
 	@$(textrel_check)
 	$(AM_V_at)ln -fs $@ $@.$(VERSION)
 
+if ENABLE_SHARED
 install: install-am libelf.so
 	$(mkinstalldirs) $(DESTDIR)$(libdir)
 	$(INSTALL_PROGRAM) libelf.so $(DESTDIR)$(libdir)/libelf-$(PACKAGE_VERSION).so
@@ -132,6 +135,7 @@ uninstall: uninstall-am
 	rm -f $(DESTDIR)$(libdir)/libelf-$(PACKAGE_VERSION).so
 	rm -f $(DESTDIR)$(libdir)/libelf.so.$(VERSION)
 	rm -f $(DESTDIR)$(libdir)/libelf.so
+endif
 
 EXTRA_DIST = libelf.map
 
commit 8c342f6d3662e48e94495e35bf8745c901ff60b4
Author: Omar Sandoval <osandov@osandov.com>
Date:   Wed Sep 4 17:13:23 2019 -0700

    configure: Add --disable-programs
    
    In some cases, it's useful to build the elfutils libraries without the
    utilities. Add a configure option which lets us do that. The default is
    still to build everything.

diff --git a/Makefile.am b/Makefile.am
index bd8926b52..0b13c717f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,7 +27,11 @@ AM_MAKEFLAGS = --no-print-directory
 pkginclude_HEADERS = version.h
 
 SUBDIRS = config m4 lib libelf libcpu backends libebl libdwelf libdwfl libdw \
-	  libasm src po doc tests
+	  libasm
+if ENABLE_PROGRAMS
+SUBDIRS += src
+endif
+SUBDIRS += po doc tests
 
 if DEBUGINFOD
 SUBDIRS += debuginfod
diff --git a/configure.ac b/configure.ac
index 25555d0bc..68ab925c2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,6 +65,11 @@ AC_CONFIG_FILES([debuginfod/Makefile])
 
 AC_CANONICAL_HOST
 
+AC_ARG_ENABLE([programs],
+	      AS_HELP_STRING([--disable-programs], [do not build utility programs]),
+	      [], [enable_programs=yes])
+AM_CONDITIONAL(ENABLE_PROGRAMS, test "$enable_programs" = yes)
+
 AC_ARG_ENABLE(deterministic-archives,
 [AS_HELP_STRING([--enable-deterministic-archives],
 		[ar and ranlib default to -D behavior])], [
diff --git a/debuginfod/Makefile.am b/debuginfod/Makefile.am
index 52ead30ae..f4756c92f 100644
--- a/debuginfod/Makefile.am
+++ b/debuginfod/Makefile.am
@@ -57,7 +57,9 @@ libeu = ../lib/libeu.a
 
 AM_LDFLAGS = -Wl,-rpath-link,../libelf:../libdw:.
 
+if ENABLE_PROGRAMS
 bin_PROGRAMS = debuginfod debuginfod-find
+endif
 debuginfod_SOURCES = debuginfod.cxx
 debuginfod_LDADD = $(libdw) $(libelf) $(libeu) $(libdebuginfod) $(libmicrohttpd_LIBS) $(libcurl_LIBS) $(sqlite3_LIBS) $(libarchive_LIBS) -lpthread -ldl
 
