diff --git a/Makefile.am b/Makefile.am
index 10c56b2..b421706 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,20 +55,22 @@ EXTRA_DIST = \
 	tests/test_driver.sh \
 	$(PDBG_TESTS)
 
-if TARGET_ARM
 DT_ARM = p8-fsi.dts p8-i2c.dts p8-kernel.dts \
 	 p9w-fsi.dts p9r-fsi.dts p9z-fsi.dts p9-kernel.dts
+
+if TARGET_ARM
 ARCH_FLAGS="-DTARGET_ARM=1"
 endif
 
-if TARGET_PPC
 DT_PPC = p8-host.dts p9-host.dts
+
+if TARGET_PPC
 ARCH_FLAGS="-DTARGET_PPC=1"
 endif
 
 DT = fake.dts $(DT_ARM) $(DT_PPC)
 
-DT_objects = $(DT:.dts=.dtb.o)
+DT_objects = $(DT:.dts=.dtb.lo)
 DT_headers = $(DT:.dts=.dt.h)
 
 optcmd_test_SOURCES = src/optcmd.c src/parsers.c src/tests/optcmd_test.c
@@ -127,6 +129,7 @@ pdbg_CFLAGS += -DDISABLE_GDBSERVER
 endif
 
 src/main.c: $(DT_headers)
+libpdbg/dtb.c: $(DT_headers)
 
 src/pdbg-gdb_parser.$(OBJEXT): CFLAGS+=-Wno-unused-const-variable
 
@@ -149,6 +152,7 @@ libpdbg_la_SOURCES = \
 	libpdbg/debug.c \
 	libpdbg/debug.h \
 	libpdbg/device.c \
+	libpdbg/dtb.c \
 	libpdbg/fake.c \
 	libpdbg/host.c \
 	libpdbg/htm.c \
@@ -166,8 +170,10 @@ libpdbg_la_SOURCES = \
 	libpdbg/target.h \
 	libpdbg/xbus.c
 
+libpdbg_la_LIBADD = $(DT_objects)
+
 if BUILD_LIBFDT
-libpdbg_la_LIBADD = libfdt/libfdt.la
+libpdbg_la_LIBADD += libfdt/libfdt.la
 endif
 
 include_HEADERS = libpdbg/libpdbg.h
@@ -242,8 +248,10 @@ p9z-fsi.dts: p9z-fsi.dts.m4 p9-fsi.dtsi
 %.dt.h: %.dts
 	$(GEN_V)$(srcdir)/generate_dt_header.sh $< > $@
 
-%.dtb.o: %.dtb
-	$(AM_V_CC)$(CC) -c $(srcdir)/template.S -DSYMBOL_PREFIX=$(shell basename $@ | tr '.-' '_') -DFILENAME=\"$<\" -o $@
+%.dtb.lo: %.dtb
+	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) -c $(srcdir)/template.S \
+	-DSYMBOL_PREFIX=$(shell basename $@ | tr '.-' '_' | sed 's/lo/o/') -DFILENAME=\"$<\" -o $@
 
 %.c: %.rl
 	$(RAGEL_V)$(RAGEL) -o $@ $<
diff --git a/libpdbg/device.c b/libpdbg/device.c
index b7fd49f..ba9e05e 100644
--- a/libpdbg/device.c
+++ b/libpdbg/device.c
@@ -638,7 +638,17 @@ uint64_t pdbg_target_address(struct pdbg_target *target, uint64_t *out_size)
 
 void pdbg_targets_init(void *fdt)
 {
+	/* Root node needs to be valid when this function returns */
 	pdbg_dt_root = dt_new_node("", NULL, 0);
+
+	if (!fdt)
+		fdt = pdbg_default_dtb();
+
+	if (!fdt) {
+		pdbg_log(PDBG_ERROR, "Could not find a system device tree\n");
+		return;
+	}
+
 	dt_expand(fdt);
 }
 
diff --git a/libpdbg/dtb.c b/libpdbg/dtb.c
new file mode 100644
index 0000000..145b497
--- /dev/null
+++ b/libpdbg/dtb.c
@@ -0,0 +1,216 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include "libpdbg.h"
+
+#include "fake.dt.h"
+
+#include "p8-i2c.dt.h"
+#include "p8-fsi.dt.h"
+#include "p8-kernel.dt.h"
+#include "p9w-fsi.dt.h"
+#include "p9r-fsi.dt.h"
+#include "p9z-fsi.dt.h"
+#include "p9-kernel.dt.h"
+#include "p8-host.dt.h"
+#include "p9-host.dt.h"
+
+#define AMI_BMC "/proc/ractrends/Helper/FwInfo"
+#define OPENFSI_BMC "/sys/bus/platform/devices/gpio-fsi/fsi0/"
+#define FSI_CFAM_ID "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/cfam_id"
+#define XSCOM_BASE_PATH "/sys/kernel/debug/powerpc/scom"
+
+#define CHIP_ID_P8  0xea
+#define CHIP_ID_P8P 0xd3
+#define CHIP_ID_P9  0xd1
+
+enum backend { FSI, I2C, KERNEL, FAKE, HOST };
+
+/* Determines the most appropriate backend for the host system we are
+ * running on. */
+static enum backend default_backend(void)
+{
+	int rc;
+
+	rc = access(XSCOM_BASE_PATH, F_OK);
+	if (rc == 0) /* PowerPC Host System */
+		return HOST;
+
+	rc = access(AMI_BMC, F_OK);
+	if (rc == 0) /* AMI BMC */
+		return I2C;
+
+	rc = access(OPENFSI_BMC, F_OK);
+	if (rc == 0) /* Kernel interface. OpenBMC */
+		return KERNEL;
+
+	return FAKE;
+}
+
+/* Try and determine what system type we are on by reading
+ * /proc/cpuinfo */
+static void *ppc_target(void)
+{
+	const char *pos = NULL;
+	char line[256];
+	FILE *cpuinfo;
+
+	cpuinfo = fopen("/proc/cpuinfo", "r");
+	if (!cpuinfo)
+		return NULL;
+
+	while ((pos = fgets(line, sizeof(line), cpuinfo)))
+		if (strncmp(line, "cpu", 3) == 0)
+			break;
+	fclose(cpuinfo);
+
+	if (!pos) {
+		/* Got to EOF without a break */
+		pdbg_log(PDBG_ERROR, "Unable to parse /proc/cpuinfo\n");
+		return NULL;
+	}
+
+	pos = strchr(line, ':');
+	if (!pos || (*(pos + 1) == '\0')) {
+		pdbg_log(PDBG_ERROR, "Unable to parse /proc/cpuinfo\n");
+		return NULL;
+	}
+
+	pos += 2;
+
+	if (strncmp(pos, "POWER8", 6) == 0) {
+		pdbg_log(PDBG_INFO, "Found a POWER8 PPC host system\n");
+		return &_binary_p8_host_dtb_o_start;
+	}
+
+	if (strncmp(pos, "POWER9", 6) == 0) {
+		pdbg_log(PDBG_INFO, "Found a POWER9 PPC host system\n");
+		return &_binary_p9_host_dtb_o_start;
+	}
+
+	pdbg_log(PDBG_ERROR, "Unsupported CPU type '%s'\n", pos);
+	return NULL;
+}
+
+static void *bmc_target(void)
+{
+	FILE *cfam_id_file;
+	uint32_t cfam_id = 0;
+	int rc;
+
+	/* Try and determine the correct device type */
+	cfam_id_file = fopen(FSI_CFAM_ID, "r");
+	if (!cfam_id_file) {
+		pdbg_log(PDBG_ERROR, "Unabled to open CFAM ID file\n");
+		return NULL;
+	}
+
+	rc = fscanf(cfam_id_file, "0x%" PRIx32, &cfam_id);
+	if (rc != 1) {
+		pdbg_log(PDBG_ERROR, "Unable to read CFAM ID: %s", strerror(errno));
+	}
+	fclose(cfam_id_file);
+
+	switch((cfam_id >> 4) & 0xff) {
+	case CHIP_ID_P9:
+		pdbg_log(PDBG_INFO, "Found a POWER9 OpenBMC based system\n");
+		return &_binary_p9_kernel_dtb_o_start;
+		break;
+
+	case CHIP_ID_P8:
+	case CHIP_ID_P8P:
+		pdbg_log(PDBG_INFO, "Found a POWER8/8+ OpenBMC based system\n");
+		return &_binary_p8_kernel_dtb_o_start;
+		break;
+	}
+
+	pdbg_log(PDBG_ERROR, "Unrecognised CFAM ID register 0x%08" PRIx32 "\n", cfam_id);
+	return NULL;
+}
+
+/* Opens a dtb at the given path */
+static void *mmap_dtb(char *file)
+{
+	int fd;
+	void *dtb;
+	struct stat statbuf;
+
+	fd = open(file, O_RDONLY);
+	if (fd < 0) {
+		pdbg_log(PDBG_ERROR, "Unable to open dtb file '%s'\n", file);
+		return NULL;
+	}
+
+	if (fstat(fd, &statbuf) == -1) {
+		pdbg_log(PDBG_ERROR, "Failed to stat file '%s'\n", file);
+		goto fail;
+	}
+
+	dtb = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (dtb == MAP_FAILED) {
+		pdbg_log(PDBG_ERROR, "Failed top mmap file '%s'\n", file);
+		goto fail;
+	}
+
+	return dtb;
+
+fail:
+	close(fd);
+	return NULL;
+}
+
+/* Determines what platform we are running on and returns a pointer to
+ * the fdt that is most likely to work on the system. */
+void *pdbg_default_dtb(void)
+{
+	char *dtb = getenv("LPDBG_DTB");
+
+	if (dtb)
+		return mmap_dtb(dtb);
+
+	switch(default_backend()) {
+	case HOST:
+		return ppc_target();
+		break;
+
+	case I2C:
+		/* I2C is only supported on POWER8 */
+		pdbg_log(PDBG_INFO, "Found a POWER8 AMI BMC based system\n");
+		return &_binary_p8_i2c_dtb_o_start;
+		break;
+
+	case KERNEL:
+		return bmc_target();
+		break;
+
+	default:
+		pdbg_log(PDBG_WARNING, "Unable to determine a valid default backend, using a fake one for testing purposes\n");
+		return &_binary_fake_dtb_o_start;
+		break;
+	}
+}
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index 14a41ab..7030139 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -103,6 +103,7 @@ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target);
 void pdbg_target_release(struct pdbg_target *target);
 enum pdbg_target_status pdbg_target_status(struct pdbg_target *target);
 void pdbg_target_status_set(struct pdbg_target *target, enum pdbg_target_status status);
+void *pdbg_default_dtb(void);
 uint32_t pdbg_target_index(struct pdbg_target *target);
 char *pdbg_target_path(const struct pdbg_target *target);
 struct pdbg_target *pdbg_target_from_path(struct pdbg_target *target, const char *path);
