sandbox: Improve debugging in initcall_run_list()
authorSimon Glass <sjg@chromium.org>
Mon, 8 Apr 2019 19:20:41 +0000 (13:20 -0600)
committerSimon Glass <sjg@chromium.org>
Wed, 24 Apr 2019 02:26:43 +0000 (20:26 -0600)
At present if one of the initcalls fails on sandbox the address printing
is not help, e.g.:

  initcall sequence 0000557678967c80 failed at call 00005576709dfe1f (err=-96)

This is because U-Boot gets relocated high into memory and the relocation
offset (gd->reloc_off) does not work correctly for sandbox.

Add support for finding the base address of the text region (at least on
Linux) and use that to set the relocation offset. This makes the output
better:

  initcall sequence 0000560775957c80 failed at call 0000000000048134 (err=-96)

Then you use can use grep to see which init call failed, e.g.:

   $ grep 0000000000048134 u-boot.map
   stdio_add_devices

Of course another option is to run it with a debugger such as gdb:

   $ gdb u-boot
   ...
   (gdb) br initcall.h:41
   Breakpoint 1 at 0x4db9d: initcall.h:41. (2 locations)

Note that two locations are reported, since this function is used in both
board_init_f() and board_init_r().

   (gdb) r
   Starting program: /tmp/b/sandbox/u-boot
   [Thread debugging using libthread_db enabled]
   Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

   U-Boot 2018.09-00264-ge0c2ba9814-dirty (Sep 22 2018 - 12:21:46 -0600)

   DRAM:  128 MiB
   MMC:

Breakpoint 1, initcall_run_list (init_sequence=0x5555559619e0 <init_sequence_f>)
    at /scratch/sglass/cosarm/src/third_party/u-boot/files/include/initcall.h:41
41 printf("initcall sequence %p failed at call %p (err=%d)\n",
   (gdb) print *init_fnc_ptr
   $1 = (const init_fnc_t) 0x55555559c114 <stdio_add_devices>
   (gdb)

Signed-off-by: Simon Glass <sjg@chromium.org>
arch/sandbox/cpu/os.c
arch/sandbox/cpu/start.c
arch/sandbox/include/asm/global_data.h
board/sandbox/README.sandbox
common/board_f.c
include/initcall.h
include/os.h

index a8d01e40011ac1d3119b5a3afe611597ab60e434..c20491493fc37a8903b6fb12eafd9bc752ac7329 100644 (file)
@@ -786,3 +786,40 @@ int os_mprotect_allow(void *start, size_t len)
 
        return mprotect(start, len, PROT_READ | PROT_WRITE);
 }
+
+void *os_find_text_base(void)
+{
+       char line[500];
+       void *base = NULL;
+       int len;
+       int fd;
+
+       /*
+        * This code assumes that the first line of /proc/self/maps holds
+        * information about the text, for example:
+        *
+        * 5622d9907000-5622d9a55000 r-xp 00000000 08:01 15067168   u-boot
+        *
+        * The first hex value is assumed to be the address.
+        *
+        * This is tested in Linux 4.15.
+        */
+       fd = open("/proc/self/maps", O_RDONLY);
+       if (fd == -1)
+               return NULL;
+       len = read(fd, line, sizeof(line));
+       if (len > 0) {
+               char *end = memchr(line, '-', len);
+
+               if (end) {
+                       unsigned long long addr;
+
+                       *end = '\0';
+                       if (sscanf(line, "%llx", &addr) == 1)
+                               base = (void *)addr;
+               }
+       }
+       close(fd);
+
+       return base;
+}
index 2f5e6e95182631d7d2cfc03ea43edb5e1d46ecb1..e22d65f6d9e59a5c27cb15ee682dcf6666a9170f 100644 (file)
@@ -328,6 +328,10 @@ int main(int argc, char *argv[])
        gd_t data;
        int ret;
 
+       memset(&data, '\0', sizeof(data));
+       gd = &data;
+       gd->arch.text_base = os_find_text_base();
+
        ret = state_init();
        if (ret)
                goto err;
@@ -340,8 +344,6 @@ int main(int argc, char *argv[])
        if (ret)
                goto err;
 
-       memset(&data, '\0', sizeof(data));
-       gd = &data;
 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
        gd->malloc_base = CONFIG_MALLOC_F_ADDR;
 #endif
@@ -350,6 +352,12 @@ int main(int argc, char *argv[])
 #endif
        setup_ram_buf(state);
 
+       /*
+        * Set up the relocation offset here, since sandbox symbols are always
+        * relocated by the OS before sandbox is entered.
+        */
+       gd->reloc_off = (ulong)gd->arch.text_base;
+
        /* Do pre- and post-relocation init */
        board_init_f(0);
 
index f6a6a343d25d84fc8a877c7e9f0b8d01f6b39164..f4ce72d56602c0b166ccf9a0beaf61852c142c90 100644 (file)
@@ -12,6 +12,7 @@
 /* Architecture-specific global data */
 struct arch_global_data {
        uint8_t         *ram_buf;       /* emulated RAM buffer */
+       void            *text_base;     /* pointer to base of text region */
 };
 
 #include <asm-generic/global_data.h>
index 9b0940429431cbe3d7a5ba12c82fbb45cd354352..ed8fac6f786cc5ae3510c6d6e54068f6ca2d19e6 100644 (file)
@@ -392,6 +392,49 @@ state_setprop() which does this automatically and avoids running out of
 space. See existing code for examples.
 
 
+Debugging the init sequence
+---------------------------
+
+If you get a failure in the initcall sequence, like this:
+
+   initcall sequence 0000560775957c80 failed at call 0000000000048134 (err=-96)
+
+Then you use can use grep to see which init call failed, e.g.:
+
+   $ grep 0000000000048134 u-boot.map
+   stdio_add_devices
+
+Of course another option is to run it with a debugger such as gdb:
+
+   $ gdb u-boot
+   ...
+   (gdb) br initcall.h:41
+   Breakpoint 1 at 0x4db9d: initcall.h:41. (2 locations)
+
+Note that two locations are reported, since this function is used in both
+board_init_f() and board_init_r().
+
+   (gdb) r
+   Starting program: /tmp/b/sandbox/u-boot
+   [Thread debugging using libthread_db enabled]
+   Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
+
+   U-Boot 2018.09-00264-ge0c2ba9814-dirty (Sep 22 2018 - 12:21:46 -0600)
+
+   DRAM:  128 MiB
+   MMC:
+
+   Breakpoint 1, initcall_run_list (init_sequence=0x5555559619e0 <init_sequence_f>)
+       at /scratch/sglass/cosarm/src/third_party/u-boot/files/include/initcall.h:41
+   41                              printf("initcall sequence %p failed at call %p (err=%d)\n",
+   (gdb) print *init_fnc_ptr
+   $1 = (const init_fnc_t) 0x55555559c114 <stdio_add_devices>
+   (gdb)
+
+
+This approach can be used on normal boards as well as sandbox.
+
+
 Testing
 -------
 
index 149a7229e8fa982d53ce003c67ddb2db7d45e2e1..7ef20f204231335088c0c8ec7f191987d7416b09 100644 (file)
@@ -714,7 +714,7 @@ static int setup_reloc(void)
         * just after the default vector table location, so at 0x400
         */
        gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400);
-#else
+#elif !defined(CONFIG_SANDBOX)
        gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
 #endif
 #endif
index 3ac01aa2cd2ce4420d4805dc2ccd982b3c9aa230..a38c83efa441d87d7e4c8efcd77db701056e061e 100644 (file)
@@ -22,13 +22,17 @@ static inline int initcall_run_list(const init_fnc_t init_sequence[])
                unsigned long reloc_ofs = 0;
                int ret;
 
-               if (gd->flags & GD_FLG_RELOC)
+               /*
+                * Sandbox is relocated by the OS, so symbols always appear at
+                * the relocated address.
+                */
+               if (IS_ENABLED(CONFIG_SANDBOX) || (gd->flags & GD_FLG_RELOC))
                        reloc_ofs = gd->reloc_off;
 #ifdef CONFIG_EFI_APP
                reloc_ofs = (unsigned long)image_base;
 #endif
                debug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs);
-               if (gd->flags & GD_FLG_RELOC)
+               if (reloc_ofs)
                        debug(" (relocated to %p)\n", (char *)*init_fnc_ptr);
                else
                        debug("\n");
index 6f33b08cf0b11aa5f6f386804c346d50d631895b..7a4f78b9b1fa7919e4a37940831ee976be323e89 100644 (file)
@@ -364,4 +364,15 @@ int os_write_file(const char *name, const void *buf, int size);
  */
 int os_read_file(const char *name, void **bufp, int *sizep);
 
+/*
+ * os_find_text_base() - Find the text section in this running process
+ *
+ * This tries to find the address of the text section in this running process.
+ * It can be useful to map the address of functions to the address listed in
+ * the u-boot.map file.
+ *
+ * @return address if found, else NULL
+ */
+void *os_find_text_base(void);
+
 #endif