diff --git a/pressure-vessel/adverb.c b/pressure-vessel/adverb.c
index 10adefb2cc285b6ed480d3c942550178bffe29ff..b5ef2b9a099924a157542b51b60b7709ecf7f604 100644
--- a/pressure-vessel/adverb.c
+++ b/pressure-vessel/adverb.c
@@ -44,6 +44,7 @@
 #include "bwrap-lock.h"
 #include "flatpak-utils-base-private.h"
 #include "launcher.h"
+#include "supported-architectures.h"
 #include "utils.h"
 #include "wrap-interactive.h"
 
@@ -65,18 +66,6 @@ static gboolean opt_wait = FALSE;
 static gboolean opt_write = FALSE;
 static GPid child_pid;
 
-typedef struct
-{
-  const gchar *abi;
-  const gchar *directory_name;
-} AbiTuplesDetails;
-
-static AbiTuplesDetails abi_tuples_details[] =
-{
-  { SRT_ABI_I386, "ubuntu12_32" },
-  { SRT_ABI_X86_64, "ubuntu12_64" },
-};
-
 typedef struct
 {
   int original_stdout_fd;
@@ -487,12 +476,12 @@ generate_lib_temp_dirs (LibTempDirs *lib_temp_dirs,
 
   lib_temp_dirs->abi_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
-  for (abi = 0; abi < G_N_ELEMENTS (abi_tuples_details); abi++)
+  for (abi = 0; abi < PV_N_SUPPORTED_ARCHITECTURES; abi++)
     {
       g_autofree gchar *libdl_platform = NULL;
       g_autofree gchar *abi_path = NULL;
       libdl_platform = srt_system_info_dup_libdl_platform (info,
-                                                           abi_tuples_details[abi].abi,
+                                                           pv_multiarch_details[abi].tuple,
                                                            error);
       if (!libdl_platform)
         return glnx_prefix_error (error,
@@ -504,7 +493,7 @@ generate_lib_temp_dirs (LibTempDirs *lib_temp_dirs,
         return glnx_throw_errno_prefix (error, "Unable to create \"%s\"", abi_path);
 
       g_hash_table_insert (lib_temp_dirs->abi_paths,
-                           g_strdup (abi_tuples_details[abi].abi),
+                           g_strdup (pv_multiarch_details[abi].tuple),
                            g_steal_pointer (&abi_path));
     }
 
@@ -994,14 +983,15 @@ main (int argc,
             {
               g_autofree gchar *link = NULL;
 
-              for (gsize abi = 0; abi < G_N_ELEMENTS (abi_tuples_details); abi++)
+              for (gsize abi = 0; abi < PV_N_SUPPORTED_ARCHITECTURES; abi++)
                 {
                   g_autofree gchar *expected_suffix = g_strdup_printf ("/%s/gameoverlayrenderer.so",
-                                                                       abi_tuples_details[abi].directory_name);
+                                                                       pv_multiarch_details[abi].gameoverlayrenderer_dir);
+
                   if (g_str_has_suffix (preload, expected_suffix))
                     {
                       link = g_build_filename (g_hash_table_lookup (lib_temp_dirs->abi_paths,
-                                                                    abi_tuples_details[abi].abi),
+                                                                    pv_multiarch_details[abi].tuple),
                                                "gameoverlayrenderer.so", NULL);
                       break;
                     }
diff --git a/pressure-vessel/meson.build b/pressure-vessel/meson.build
index 2838ba1d861c558139488448e107b1c7f1961e5e..5560636ef90641a01117dae7dcd7f1ba776262e1 100644
--- a/pressure-vessel/meson.build
+++ b/pressure-vessel/meson.build
@@ -147,6 +147,8 @@ executable(
   'pressure-vessel-adverb',
   sources : [
     'adverb.c',
+    'supported-architectures.c',
+    'supported-architectures.h',
     'wrap-interactive.c',
     'wrap-interactive.h',
   ],
@@ -228,6 +230,8 @@ pressure_vessel_wrap_lib = static_library(
     'graphics-provider.h',
     'runtime.c',
     'runtime.h',
+    'supported-architectures.c',
+    'supported-architectures.h',
     'wrap-flatpak.c',
     'wrap-flatpak.h',
     'wrap-pipewire.c',
diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index 2f528fa5d55419073870c7655ebd38079b0dae2a..6cf25b6a70d5d33284f7f316984dfe5bdd8ef0d4 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -43,6 +43,7 @@
 #include "exports.h"
 #include "flatpak-run-private.h"
 #include "mtree.h"
+#include "supported-architectures.h"
 #include "tree-copy.h"
 #include "utils.h"
 
@@ -201,140 +202,10 @@ path_visible_in_provider_namespace (PvRuntimeFlags flags,
   return FALSE;
 }
 
-/*
- * Supported Debian-style multiarch tuples
- */
-static const char * const multiarch_tuples[] =
-{
-  "x86_64-linux-gnu",
-  "i386-linux-gnu",
-  NULL
-};
-
-typedef struct
-{
-  const char *tuple;
-
-  /* Directories other than /usr/lib that we must search for loadable
-   * modules, least-ambiguous first, most-ambiguous last, not including
-   * Debian-style multiarch directories which are automatically derived
-   * from @tuple.
-   * - Exherbo <GNU-tuple>/lib
-   * - Red-Hat- or Arch-style lib<QUAL>
-   * - etc.
-   * Size is completely arbitrary, expand as needed */
-  const char *multilib[3];
-
-  /* Alternative paths for ld.so.cache, other than ld.so.cache itself.
-   * Size is completely arbitrary, expand as needed */
-  const char *other_ld_so_cache[2];
-
-  /* Known values that ${PLATFORM} can expand to.
-   * Refer to sysdeps/x86/cpu-features.c and sysdeps/x86/dl-procinfo.c
-   * in glibc.
-   * Size is completely arbitrary, expand as needed */
-  const char *platforms[5];
-} MultiarchDetails;
-
-/*
- * More details, in the same order as multiarch_tuples
- */
-static const MultiarchDetails multiarch_details[] =
-{
-  {
-    .tuple = "x86_64-linux-gnu",
-    .multilib = { "x86_64-pc-linux-gnu/lib", "lib64", NULL },
-    .other_ld_so_cache = { "ld-x86_64-pc-linux-gnu.cache", NULL },
-    .platforms = { "xeon_phi", "haswell", "x86_64", NULL },
-  },
-  {
-    .tuple = "i386-linux-gnu",
-    .multilib = { "i686-pc-linux-gnu/lib", "lib32", NULL },
-    .other_ld_so_cache = { "ld-i686-pc-linux-gnu.cache", NULL },
-    .platforms = { "i686", "i586", "i486", "i386", NULL },
-  },
-};
-G_STATIC_ASSERT (G_N_ELEMENTS (multiarch_details)
-                 == G_N_ELEMENTS (multiarch_tuples) - 1);
-
-/* Architecture-independent ld.so.cache filenames, other than the
- * conventional filename /etc/ld.so.cache used upstream and in Debian
- * (we assume this is also what's used in our runtimes). */
-static const char * const other_ld_so_cache[] =
-{
-  /* Clear Linux */
-  "/var/cache/ldconfig/ld.so.cache",
-};
-
-/*
- * @MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN:
- *  Return all library directories from which we might need to delete
- *  overridden libraries shipped in the runtime.
- */
-typedef enum
-{
-  MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN = (1 << 0),
-  MULTIARCH_LIBDIRS_FLAGS_NONE = 0
-} MultiarchLibdirsFlags;
-
-/*
- * Get the library directories associated with @self, most important or
- * unambiguous first.
- *
- * Returns: (transfer container) (element-type filename):
- */
-static GPtrArray *
-multiarch_details_get_libdirs (const MultiarchDetails *self,
-                               MultiarchLibdirsFlags flags)
-{
-  g_autoptr(GPtrArray) dirs = g_ptr_array_new_with_free_func (g_free);
-  gsize j;
-
-  /* Multiarch is the least ambiguous so we put it first.
-   *
-   * We historically searched /usr/lib before /lib, but Debian actually
-   * does the opposite, and we follow that here.
-   *
-   * Arguably we should search /usr/local/lib before /lib before /usr/lib,
-   * but we don't currently try /usr/local/lib. We could add a flag
-   * for that if we don't want to do it unconditionally. */
-  g_ptr_array_add (dirs,
-                   g_build_filename ("/lib", self->tuple, NULL));
-  g_ptr_array_add (dirs,
-                   g_build_filename ("/usr", "lib", self->tuple, NULL));
-
-  if (flags & MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN)
-    g_ptr_array_add (dirs,
-                     g_build_filename ("/usr", "lib", self->tuple, "mesa",
-                                       NULL));
-
-  /* Try other multilib variants next. This includes
-   * Exherbo/cross-compilation-style per-architecture prefixes,
-   * Red-Hat-style lib64 and Arch-style lib32. */
-  for (j = 0; j < G_N_ELEMENTS (self->multilib); j++)
-    {
-      if (self->multilib[j] == NULL)
-        break;
-
-      g_ptr_array_add (dirs,
-                       g_build_filename ("/", self->multilib[j], NULL));
-      g_ptr_array_add (dirs,
-                       g_build_filename ("/usr", self->multilib[j], NULL));
-    }
-
-  /* /lib and /usr/lib are lowest priority because they're the most
-   * ambiguous: we don't know whether they're meant to contain 32- or
-   * 64-bit libraries. */
-  g_ptr_array_add (dirs, g_strdup ("/lib"));
-  g_ptr_array_add (dirs, g_strdup ("/usr/lib"));
-
-  return g_steal_pointer (&dirs);
-}
-
 typedef struct
 {
   gsize multiarch_index;
-  const MultiarchDetails *details;
+  const PvMultiarchDetails *details;
   gchar *aliases_in_current_namespace;
   gchar *capsule_capture_libs_basename;
   gchar *capsule_capture_libs;
@@ -349,16 +220,14 @@ runtime_architecture_init (RuntimeArchitecture *self,
 {
   const gchar *argv[] = { NULL, "--print-ld.so", NULL };
 
-  g_return_val_if_fail (self->multiarch_index < G_N_ELEMENTS (multiarch_details),
-                        FALSE);
-  g_return_val_if_fail (self->multiarch_index < G_N_ELEMENTS (multiarch_tuples) - 1,
+  g_return_val_if_fail (self->multiarch_index < PV_N_SUPPORTED_ARCHITECTURES,
                         FALSE);
   g_return_val_if_fail (self->details == NULL, FALSE);
 
-  self->details = &multiarch_details[self->multiarch_index];
+  self->details = &pv_multiarch_details[self->multiarch_index];
   g_return_val_if_fail (self->details != NULL, FALSE);
   g_return_val_if_fail (self->details->tuple != NULL, FALSE);
-  g_return_val_if_fail (g_strcmp0 (multiarch_tuples[self->multiarch_index],
+  g_return_val_if_fail (g_strcmp0 (pv_multiarch_tuples[self->multiarch_index],
                                    self->details->tuple) == 0, FALSE);
 
   self->capsule_capture_libs_basename = g_strdup_printf ("%s-capsule-capture-libs",
@@ -393,8 +262,8 @@ runtime_architecture_init (RuntimeArchitecture *self,
 static gboolean
 runtime_architecture_check_valid (RuntimeArchitecture *self)
 {
-  g_return_val_if_fail (self->multiarch_index < G_N_ELEMENTS (multiarch_details), FALSE);
-  g_return_val_if_fail (self->details == &multiarch_details[self->multiarch_index], FALSE);
+  g_return_val_if_fail (self->multiarch_index < PV_N_SUPPORTED_ARCHITECTURES, FALSE);
+  g_return_val_if_fail (self->details == &pv_multiarch_details[self->multiarch_index], FALSE);
   g_return_val_if_fail (self->capsule_capture_libs_basename != NULL, FALSE);
   g_return_val_if_fail (self->capsule_capture_libs != NULL, FALSE);
   g_return_val_if_fail (self->libdir_in_current_namespace != NULL, FALSE);
@@ -1282,7 +1151,7 @@ pv_runtime_unpack (PvRuntime *self,
 
 typedef struct
 {
-  const MultiarchDetails *details;
+  const PvMultiarchDetails *details;
   PvRuntimeFlags flags;
   PvGraphicsProvider *provider;
   GCancellable *cancellable;
@@ -1290,7 +1159,7 @@ typedef struct
 
 /* Called in main thread */
 static EnumerationThreadInputs *
-enumeration_thread_inputs_new (const MultiarchDetails *details,
+enumeration_thread_inputs_new (const PvMultiarchDetails *details,
                                PvRuntimeFlags flags,
                                PvGraphicsProvider *provider,
                                GCancellable *cancellable)
@@ -1403,7 +1272,7 @@ enumerate_indep (gpointer data)
       G_GNUC_UNUSED g_autoptr(SrtProfilingTimer) part_timer =
         _srt_profiling_start ("Enumerating EGL ICDs in thread");
 
-      srt_system_info_list_egl_icds (system_info, multiarch_tuples);
+      srt_system_info_list_egl_icds (system_info, pv_multiarch_tuples);
     }
 
   if (g_cancellable_is_cancelled (inputs->cancellable))
@@ -1414,7 +1283,7 @@ enumerate_indep (gpointer data)
       G_GNUC_UNUSED g_autoptr(SrtProfilingTimer) part_timer =
         _srt_profiling_start ("Enumerating Vulkan ICDs in thread");
 
-      srt_system_info_list_vulkan_icds (system_info, multiarch_tuples);
+      srt_system_info_list_vulkan_icds (system_info, pv_multiarch_tuples);
     }
 
   if (g_cancellable_is_cancelled (inputs->cancellable))
@@ -1480,7 +1349,7 @@ enumeration_threads_clear (EnumerationThread **arr,
 /* Must be called in main thread */
 static void
 enumeration_thread_start_arch (EnumerationThread *self,
-                               const MultiarchDetails *details,
+                               const PvMultiarchDetails *details,
                                PvRuntimeFlags flags,
                                PvGraphicsProvider *provider)
 {
@@ -1547,11 +1416,11 @@ pv_runtime_initable_init (GInitable *initable,
                                       self->provider);
 
       self->arch_threads = g_new0 (EnumerationThread,
-                                   G_N_ELEMENTS (multiarch_details));
+                                   PV_N_SUPPORTED_ARCHITECTURES);
 
-      for (i = 0; i < G_N_ELEMENTS (multiarch_details); i++)
+      for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES; i++)
         enumeration_thread_start_arch (&self->arch_threads[i],
-                                       &multiarch_details[i],
+                                       &pv_multiarch_details[i],
                                        self->flags,
                                        self->provider);
     }
@@ -1845,7 +1714,7 @@ pv_runtime_dispose (GObject *object)
   g_clear_object (&self->provider);
   enumeration_thread_clear (&self->indep_thread);
   enumeration_threads_clear (&self->arch_threads,
-                             G_N_ELEMENTS (multiarch_details));
+                             PV_N_SUPPORTED_ARCHITECTURES);
 
   G_OBJECT_CLASS (pv_runtime_parent_class)->dispose (object);
 }
@@ -2247,9 +2116,9 @@ typedef struct
   gchar *resolved_library;
   /* Last entry is always NONEXISTENT; keyed by the index of a multiarch
    * tuple in multiarch_tuples. */
-  IcdKind kinds[G_N_ELEMENTS (multiarch_tuples)];
+  IcdKind kinds[PV_N_SUPPORTED_ARCHITECTURES + 1];
   /* Last entry is always NULL */
-  gchar *paths_in_container[G_N_ELEMENTS (multiarch_tuples)];
+  gchar *paths_in_container[PV_N_SUPPORTED_ARCHITECTURES + 1];
 } IcdDetails;
 
 static IcdDetails *
@@ -2271,7 +2140,7 @@ icd_details_new (gpointer icd)
   self->icd = g_object_ref (icd);
   self->resolved_library = NULL;
 
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+  for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES + 1; i++)
     {
       self->kinds[i] = ICD_KIND_NONEXISTENT;
       self->paths_in_container[i] = NULL;
@@ -2288,7 +2157,7 @@ icd_details_free (IcdDetails *self)
   g_object_unref (self->icd);
   g_free (self->resolved_library);
 
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+  for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES + 1; i++)
     g_free (self->paths_in_container[i]);
 
   g_slice_free (IcdDetails, self);
@@ -2700,9 +2569,9 @@ bind_runtime_base (PvRuntime *self,
    * /var/cache/ldconfig/ld.so.cache. For simplicity, we make all these
    * paths symlinks to /etc/ld.so.cache, so that we only have to populate
    * the cache in one place. */
-  for (i = 0; i < G_N_ELEMENTS (other_ld_so_cache); i++)
+  for (i = 0; pv_other_ld_so_cache[i] != NULL; i++)
     {
-      const char *path = other_ld_so_cache[i];
+      const char *path = pv_other_ld_so_cache[i];
 
       flatpak_bwrap_add_args (bwrap,
                               "--symlink", "/etc/ld.so.cache", path,
@@ -2714,9 +2583,9 @@ bind_runtime_base (PvRuntime *self,
    * does this. Again, for simplicity we direct all these to the same path:
    * it's OK to mix multiple architectures' libraries into one cache,
    * as done in upstream glibc (and Debian, Arch, etc.). */
-  for (i = 0; i < G_N_ELEMENTS (multiarch_details); i++)
+  for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES; i++)
     {
-      const MultiarchDetails *details = &multiarch_details[i];
+      const PvMultiarchDetails *details = &pv_multiarch_details[i];
 
       for (j = 0; j < G_N_ELEMENTS (details->other_ld_so_cache); j++)
         {
@@ -3096,8 +2965,8 @@ pv_runtime_remove_overridden_libraries (PvRuntime *self,
   timer = _srt_profiling_start ("Removing overridden %s libraries",
                                 arch->details->tuple);
 
-  dirs = multiarch_details_get_libdirs (arch->details,
-                                        MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN);
+  dirs = pv_multiarch_details_get_libdirs (arch->details,
+                                           PV_MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN);
   delete = g_new0 (GHashTable *, dirs->len);
   iters = g_new0 (GLnxDirFdIterator, dirs->len);
 
@@ -3554,7 +3423,7 @@ setup_json_manifest (PvRuntime *self,
         return TRUE;
     }
 
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+  for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES; i++)
     {
       g_assert (i < G_N_ELEMENTS (details->kinds));
       g_assert (i < G_N_ELEMENTS (details->paths_in_container));
@@ -3568,7 +3437,7 @@ setup_json_manifest (PvRuntime *self,
           g_assert (details->paths_in_container[i] != NULL);
 
           json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
-                                       seq, multiarch_tuples[i]);
+                                       seq, pv_multiarch_tuples[i]);
           write_to_file = g_build_filename (write_to_dir, json_base, NULL);
           json_in_container = g_build_filename (self->overrides_in_container,
                                                 "share", sub_dir,
@@ -4893,7 +4762,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
 
   part_timer = _srt_profiling_start ("Enumerating EGL ICDs");
   g_debug ("Enumerating EGL ICDs on provider system...");
-  egl_icds = srt_system_info_list_egl_icds (system_info, multiarch_tuples);
+  egl_icds = srt_system_info_list_egl_icds (system_info, pv_multiarch_tuples);
   n_egl_icds = g_list_length (egl_icds);
 
   egl_icd_details = g_ptr_array_new_full (n_egl_icds,
@@ -4926,7 +4795,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
   part_timer = _srt_profiling_start ("Enumerating Vulkan ICDs");
   g_debug ("Enumerating Vulkan ICDs on provider system...");
   vulkan_icds = srt_system_info_list_vulkan_icds (system_info,
-                                                  multiarch_tuples);
+                                                  pv_multiarch_tuples);
   n_vulkan_icds = g_list_length (vulkan_icds);
 
   vulkan_icd_details = g_ptr_array_new_full (n_vulkan_icds,
@@ -5025,16 +4894,16 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
    * for some architecture. */
   self->all_libc_from_provider = TRUE;
 
-  g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
+  g_assert (pv_multiarch_tuples[PV_N_SUPPORTED_ARCHITECTURES] == NULL);
 
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+  for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES; i++)
     {
       g_autoptr(GError) local_error = NULL;
       g_auto (RuntimeArchitecture) arch_on_stack = { i };
       RuntimeArchitecture *arch = &arch_on_stack;
 
-      part_timer = _srt_profiling_start ("%s libraries", multiarch_tuples[i]);
-      g_debug ("Checking for %s libraries...", multiarch_tuples[i]);
+      part_timer = _srt_profiling_start ("%s libraries", pv_multiarch_tuples[i]);
+      g_debug ("Checking for %s libraries...", pv_multiarch_tuples[i]);
 
       if (runtime_architecture_init (arch, self))
         {
@@ -5209,8 +5078,8 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
                                            nvidia_data_in_provider);
             }
 
-          dirs = multiarch_details_get_libdirs (arch->details,
-                                                MULTIARCH_LIBDIRS_FLAGS_NONE);
+          dirs = pv_multiarch_details_get_libdirs (arch->details,
+                                                   PV_MULTIARCH_LIBDIRS_FLAGS_NONE);
 
           for (j = 0; j < dirs->len; j++)
             {
@@ -5246,7 +5115,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
             }
 
           platform_token = srt_system_info_dup_libdl_platform (arch_system_info,
-                                                               multiarch_tuples[i],
+                                                               pv_multiarch_tuples[i],
                                                                &local_error);
           if (platform_token == NULL)
             {
@@ -5281,14 +5150,14 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
     {
       GString *archs = g_string_new ("");
 
-      g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
+      g_assert (pv_multiarch_tuples[PV_N_SUPPORTED_ARCHITECTURES] == NULL);
 
-      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+      for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES; i++)
         {
           if (archs->len > 0)
             g_string_append (archs, ", ");
 
-          g_string_append (archs, multiarch_tuples[i]);
+          g_string_append (archs, pv_multiarch_tuples[i]);
         }
 
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@@ -5518,7 +5387,7 @@ pv_runtime_bind (PvRuntime *self,
 
           search_path = _srt_graphics_get_vulkan_search_paths ("/",
                                                                self->original_environ,
-                                                               multiarch_tuples,
+                                                               pv_multiarch_tuples,
                                                                suffix);
 
           for (j = 0; search_path != NULL && search_path[j] != NULL; j++)
@@ -5576,18 +5445,18 @@ pv_runtime_set_search_paths (PvRuntime *self,
    * of setting LD_LIBRARY_PATH, for better robustness against
    * games that set their own LD_LIBRARY_PATH ignoring what they
    * got from the environment */
-  g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
+  g_assert (pv_multiarch_tuples[PV_N_SUPPORTED_ARCHITECTURES] == NULL);
 
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+  for (i = 0; i < PV_N_SUPPORTED_ARCHITECTURES; i++)
     {
       g_autofree gchar *ld_path = NULL;
       g_autofree gchar *aliases = NULL;
 
       ld_path = g_build_filename (self->overrides_in_container, "lib",
-                                  multiarch_tuples[i], NULL);
+                                  pv_multiarch_tuples[i], NULL);
 
       aliases = g_build_filename (self->overrides_in_container, "lib",
-                                  multiarch_tuples[i], "aliases", NULL);
+                                  pv_multiarch_tuples[i], "aliases", NULL);
 
       pv_search_path_append (ld_library_path, ld_path);
       pv_search_path_append (ld_library_path, aliases);
diff --git a/pressure-vessel/supported-architectures.c b/pressure-vessel/supported-architectures.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d14fcdf00b00a60c9e5507c5843768045e13084
--- /dev/null
+++ b/pressure-vessel/supported-architectures.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "subprojects/libglnx/config.h"
+
+#include "supported-architectures.h"
+
+#include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/utils-internal.h"
+#include "libglnx/libglnx.h"
+
+/*
+ * Supported Debian-style multiarch tuples
+ */
+const char * const pv_multiarch_tuples[PV_N_SUPPORTED_ARCHITECTURES + 1] =
+{
+  "x86_64-linux-gnu",
+  "i386-linux-gnu",
+  NULL
+};
+
+/*
+ * More details, in the same order as pv_multiarch_tuples
+ */
+const PvMultiarchDetails pv_multiarch_details[PV_N_SUPPORTED_ARCHITECTURES] =
+{
+  {
+    .tuple = "x86_64-linux-gnu",
+    .multilib = { "x86_64-pc-linux-gnu/lib", "lib64", NULL },
+    .other_ld_so_cache = { "ld-x86_64-pc-linux-gnu.cache", NULL },
+    .platforms = { "xeon_phi", "haswell", "x86_64", NULL },
+    .gameoverlayrenderer_dir = "ubuntu12_64",
+  },
+  {
+    .tuple = "i386-linux-gnu",
+    .multilib = { "i686-pc-linux-gnu/lib", "lib32", NULL },
+    .other_ld_so_cache = { "ld-i686-pc-linux-gnu.cache", NULL },
+    .platforms = { "i686", "i586", "i486", "i386", NULL },
+    .gameoverlayrenderer_dir = "ubuntu12_32",
+  },
+};
+
+/* Architecture-independent ld.so.cache filenames, other than the
+ * conventional filename /etc/ld.so.cache used upstream and in Debian
+ * (we assume this is also what's used in our runtimes). */
+const char * const pv_other_ld_so_cache[] =
+{
+  /* Clear Linux */
+  "/var/cache/ldconfig/ld.so.cache",
+  NULL
+};
+
+/*
+ * Get the library directories associated with @self, most important or
+ * unambiguous first.
+ *
+ * Returns: (transfer container) (element-type filename):
+ */
+GPtrArray *
+pv_multiarch_details_get_libdirs (const PvMultiarchDetails *self,
+                                  PvMultiarchLibdirsFlags flags)
+{
+  g_autoptr(GPtrArray) dirs = g_ptr_array_new_with_free_func (g_free);
+  gsize j;
+
+  /* Multiarch is the least ambiguous so we put it first.
+   *
+   * We historically searched /usr/lib before /lib, but Debian actually
+   * does the opposite, and we follow that here.
+   *
+   * Arguably we should search /usr/local/lib before /lib before /usr/lib,
+   * but we don't currently try /usr/local/lib. We could add a flag
+   * for that if we don't want to do it unconditionally. */
+  g_ptr_array_add (dirs,
+                   g_build_filename ("/lib", self->tuple, NULL));
+  g_ptr_array_add (dirs,
+                   g_build_filename ("/usr", "lib", self->tuple, NULL));
+
+  if (flags & PV_MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN)
+    g_ptr_array_add (dirs,
+                     g_build_filename ("/usr", "lib", self->tuple, "mesa",
+                                       NULL));
+
+  /* Try other multilib variants next. This includes
+   * Exherbo/cross-compilation-style per-architecture prefixes,
+   * Red-Hat-style lib64 and Arch-style lib32. */
+  for (j = 0; j < G_N_ELEMENTS (self->multilib); j++)
+    {
+      if (self->multilib[j] == NULL)
+        break;
+
+      g_ptr_array_add (dirs,
+                       g_build_filename ("/", self->multilib[j], NULL));
+      g_ptr_array_add (dirs,
+                       g_build_filename ("/usr", self->multilib[j], NULL));
+    }
+
+  /* /lib and /usr/lib are lowest priority because they're the most
+   * ambiguous: we don't know whether they're meant to contain 32- or
+   * 64-bit libraries. */
+  g_ptr_array_add (dirs, g_strdup ("/lib"));
+  g_ptr_array_add (dirs, g_strdup ("/usr/lib"));
+
+  return g_steal_pointer (&dirs);
+}
diff --git a/pressure-vessel/supported-architectures.h b/pressure-vessel/supported-architectures.h
new file mode 100644
index 0000000000000000000000000000000000000000..40991d1dfbc7ac5586ce8f9a77b0ae43dee92c3c
--- /dev/null
+++ b/pressure-vessel/supported-architectures.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib.h>
+
+#define PV_N_SUPPORTED_ARCHITECTURES 2
+
+extern const char * const pv_multiarch_tuples[PV_N_SUPPORTED_ARCHITECTURES + 1];
+
+typedef struct
+{
+  const char *tuple;
+
+  /* Directories other than /usr/lib that we must search for loadable
+   * modules, least-ambiguous first, most-ambiguous last, not including
+   * Debian-style multiarch directories which are automatically derived
+   * from @tuple.
+   * - Exherbo <GNU-tuple>/lib
+   * - Red-Hat- or Arch-style lib<QUAL>
+   * - etc.
+   * Size is completely arbitrary, expand as needed */
+  const char *multilib[3];
+
+  /* Alternative paths for ld.so.cache, other than ld.so.cache itself.
+   * Size is completely arbitrary, expand as needed */
+  const char *other_ld_so_cache[2];
+
+  /* Known values that ${PLATFORM} can expand to.
+   * Refer to sysdeps/x86/cpu-features.c and sysdeps/x86/dl-procinfo.c
+   * in glibc.
+   * Size is completely arbitrary, expand as needed */
+  const char *platforms[5];
+
+  /* Directory used in Steam for gameoverlayrenderer.so. */
+  const char *gameoverlayrenderer_dir;
+} PvMultiarchDetails;
+
+extern const PvMultiarchDetails pv_multiarch_details[PV_N_SUPPORTED_ARCHITECTURES];
+
+extern const char * const pv_other_ld_so_cache[];
+
+/*
+ * PvMultiarchLibdirsFlags:
+ * @PV_MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN:
+ *  Return all library directories from which we might need to delete
+ *  overridden libraries shipped in the runtime.
+ */
+typedef enum
+{
+  PV_MULTIARCH_LIBDIRS_FLAGS_REMOVE_OVERRIDDEN = (1 << 0),
+  PV_MULTIARCH_LIBDIRS_FLAGS_NONE = 0
+} PvMultiarchLibdirsFlags;
+
+GPtrArray *pv_multiarch_details_get_libdirs (const PvMultiarchDetails *self,
+                                             PvMultiarchLibdirsFlags flags);