rtos: Support looking up .lto_priv.0 appended to symbol name 79/7179/10
authorTim Nordell <tnordell@airgain.com>
Wed, 7 Sep 2022 16:59:47 +0000 (11:59 -0500)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 17 Sep 2022 20:58:55 +0000 (20:58 +0000)
When FreeRTOS (at least) is compiled with -flto, this leaves certain
static symbols with .lto_priv.0 appended to their name.  Arguably this
could be considered to be a gdb or gcc bug, but one place to resolve it
for OpenOCD usage is here at symbol lookup time.

Note that the ".0" is for the first such instance of the variable as a
static; additional ones would end up as ".1", ".2", etc, and are not
considered here.

Signed-off-by: Tim Nordell <tnordell@airgain.com>
Change-Id: I03580b45e8ea364392ef4e05c96276416b390cb0
Reviewed-on: https://review.openocd.org/c/openocd/+/7179
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
src/rtos/rtos.c

index ccf15c7c783a094fdfc15df7cb5070cc79c7f2ca..31fd057edb75ce8b93f7d3f3411d3f17c9e83d9a 100644 (file)
@@ -215,6 +215,12 @@ static struct symbol_table_elem *next_symbol(struct rtos *os, char *cur_symbol,
  * specified explicitly, then no further symbol lookup is done. When
  * auto-detecting, the RTOS driver _detect() function must return success.
  *
+ * The symbol is tried twice to handle the -flto case with gcc.  The first
+ * attempt uses the symbol as-is, and the second attempt tries the symbol
+ * with ".lto_priv.0" appended to it.  We only consider the first static
+ * symbol here from the -flto case.  (Each subsequent static symbol with
+ * the same name is exported as .lto_priv.1, .lto_priv.2, etc.)
+ *
  * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
  */
 int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size)
@@ -223,7 +229,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
        uint64_t addr = 0;
        size_t reply_len;
        char reply[GDB_BUFFER_SIZE + 1], cur_sym[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
-       struct symbol_table_elem *next_sym;
+       struct symbol_table_elem *next_sym = NULL;
        struct target *target = get_target_from_connection(connection);
        struct rtos *os = target->rtos;
 
@@ -236,13 +242,34 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
        size_t len = unhexify((uint8_t *)cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1));
        cur_sym[len] = 0;
 
+       const char no_suffix[] = "";
+       const char lto_suffix[] = ".lto_priv.0";
+       const size_t lto_suffix_len = strlen(lto_suffix);
+
+       const char *cur_suffix;
+       const char *next_suffix;
+
+       /* Detect what suffix was used during the previous symbol lookup attempt, and
+        * speculatively determine the next suffix (only used for the unknown address case) */
+       if (len > lto_suffix_len && !strcmp(cur_sym + len - lto_suffix_len, lto_suffix)) {
+               /* Trim the suffix from cur_sym for comparison purposes below */
+               cur_sym[len - lto_suffix_len] = '\0';
+               cur_suffix = lto_suffix;
+               next_suffix = NULL;
+       } else {
+               cur_suffix = no_suffix;
+               next_suffix = lto_suffix;
+       }
+
        if ((strcmp(packet, "qSymbol::") != 0) &&               /* GDB is not offering symbol lookup for the first time */
            (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr))) { /* GDB did not find an address for a symbol */
 
                /* GDB could not find an address for the previous symbol */
                struct symbol_table_elem *sym = find_symbol(os, cur_sym);
 
-               if (sym && !sym->optional) {    /* the symbol is mandatory for this RTOS */
+               if (next_suffix) {
+                       next_sym = sym;
+               } else if (sym && !sym->optional) {     /* the symbol is mandatory for this RTOS */
                        if (!target->rtos_auto_detect) {
                                LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym);
                                goto done;
@@ -259,13 +286,16 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
                }
        }
 
-       LOG_DEBUG("RTOS: Address of symbol '%s' is 0x%" PRIx64, cur_sym, addr);
+       LOG_DEBUG("RTOS: Address of symbol '%s%s' is 0x%" PRIx64, cur_sym, cur_suffix, addr);
 
-       next_sym = next_symbol(os, cur_sym, addr);
+       if (!next_sym) {
+               next_sym = next_symbol(os, cur_sym, addr);
+               next_suffix = no_suffix;
+       }
 
        /* Should never happen unless the debugger misbehaves */
        if (!next_sym) {
-               LOG_WARNING("RTOS: Debugger sent us qSymbol with '%s' that we did not ask for", cur_sym);
+               LOG_WARNING("RTOS: Debugger sent us qSymbol with '%s%s' that we did not ask for", cur_sym, cur_suffix);
                goto done;
        }
 
@@ -287,17 +317,26 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
                }
        }
 
-       if (8 + (strlen(next_sym->symbol_name) * 2) + 1 > sizeof(reply)) {
-               LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym->symbol_name);
+       assert(next_suffix);
+
+       reply_len = 8;                                   /* snprintf(..., "qSymbol:") */
+       reply_len += 2 * strlen(next_sym->symbol_name);  /* hexify(..., next_sym->symbol_name, ...) */
+       reply_len += 2 * strlen(next_suffix);            /* hexify(..., next_suffix, ...) */
+       reply_len += 1;                                  /* Terminating NUL */
+       if (reply_len > sizeof(reply)) {
+               LOG_ERROR("ERROR: RTOS symbol '%s%s' name is too long for GDB!", next_sym->symbol_name, next_suffix);
                goto done;
        }
 
-       LOG_DEBUG("RTOS: Requesting symbol lookup of '%s' from the debugger", next_sym->symbol_name);
+       LOG_DEBUG("RTOS: Requesting symbol lookup of '%s%s' from the debugger", next_sym->symbol_name, next_suffix);
 
        reply_len = snprintf(reply, sizeof(reply), "qSymbol:");
        reply_len += hexify(reply + reply_len,
                (const uint8_t *)next_sym->symbol_name, strlen(next_sym->symbol_name),
                sizeof(reply) - reply_len);
+       reply_len += hexify(reply + reply_len,
+               (const uint8_t *)next_suffix, strlen(next_suffix),
+               sizeof(reply) - reply_len);
 
 done:
        gdb_put_packet(connection, reply, reply_len);

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)