From: Jan Beulich Date: Fri, 14 Mar 2025 09:32:20 +0000 (+0100) Subject: gas: permit LEB128 operands for .cfi_escape X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9f42fb05256ad5731baf307dcdd321dd5d6b0828;p=thirdparty%2Fbinutils-gdb.git gas: permit LEB128 operands for .cfi_escape Many DW_CFA_* and DW_OP_* take LEB128 operands. Having to hand-encode such when needing to resort to .cfi_escape isn't very helpful. --- diff --git a/gas/doc/as.texi b/gas/doc/as.texi index afe1737f4ce..edb498ac2f3 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -5176,7 +5176,18 @@ SPARC register window has been saved. @subsection @code{.cfi_escape} @var{expression}[, @dots{}] Allows the user to add arbitrary bytes to the unwind info. One might use this to add OS-specific CFI opcodes, or generic CFI -opcodes that GAS does not yet support. +opcodes that GAS does not yet support. To emit multi-byte data one may +also use extended kind-of-expression forms: + +@itemize @bullet + +@item @code{sleb128(@var{expression})} +to emit a SLEB128 item, + +@item @code{uleb128(@var{expression})} +to emit a ULEB128 item. + +@end itemize @subsection @code{.cfi_val_encoded_addr @var{register}, @var{encoding}, @var{label}} The current value of @var{register} is @var{label}. The value of @var{label} diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index 310cb56a34e..45d2830f3db 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -941,7 +941,7 @@ dot_cfi (int arg) static void dot_cfi_escape (int ignored ATTRIBUTE_UNUSED) { - struct cfi_escape_data *head, **tail, *e; + struct cfi_escape_data *head, **tail; struct cfi_insn_data *insn; if (frchain_now->frch_cfi_data == NULL) @@ -960,8 +960,39 @@ dot_cfi_escape (int ignored ATTRIBUTE_UNUSED) tail = &head; do { - e = notes_alloc (sizeof (*e)); - e->reloc = do_parse_cons_expression (&e->exp, 1); + struct cfi_escape_data *e = notes_alloc (sizeof (*e)); + char *id, *ilp_save = input_line_pointer; + char c = get_symbol_name (&id); + + if (strcmp (id, "sleb128") == 0) + e->type = CFI_ESC_sleb128; + else if (strcmp (id, "uleb128") == 0) + e->type = CFI_ESC_uleb128; + else + e->type = CFI_ESC_byte; + + c = restore_line_pointer (c); + + if (e->type != CFI_ESC_byte) + { + if (is_whitespace (c)) + c = *++input_line_pointer; + if (c != '(') + { + input_line_pointer = ilp_save; + e->type = CFI_ESC_byte; + } + } + + if (e->type == CFI_ESC_sleb128 || e->type == CFI_ESC_uleb128) + { + /* We're still at the opening parenthesis. Leave it to expression() + to parse it and find the matching closing one. */ + expression (&e->exp); + } + else + e->reloc = do_parse_cons_expression (&e->exp, 1); + *tail = e; tail = &e->next; } @@ -1778,7 +1809,12 @@ output_cfi_insn (struct cfi_insn_data *insn) { struct cfi_escape_data *e; for (e = insn->u.esc; e ; e = e->next) - emit_expr_with_reloc (&e->exp, 1, e->reloc); + { + if (e->type == CFI_ESC_sleb128 || e->type == CFI_ESC_uleb128) + emit_leb128_expr (&e->exp, e->type == CFI_ESC_sleb128); + else + emit_expr_with_reloc (&e->exp, 1, e->reloc); + } break; } diff --git a/gas/dw2gencfi.h b/gas/dw2gencfi.h index e9eec434573..c741f8f33ef 100644 --- a/gas/dw2gencfi.h +++ b/gas/dw2gencfi.h @@ -97,6 +97,11 @@ struct cfi_escape_data { struct cfi_escape_data *next; expressionS exp; + enum { + CFI_ESC_byte, + CFI_ESC_sleb128, + CFI_ESC_uleb128, + } type; TC_PARSE_CONS_RETURN_TYPE reloc; }; diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index 15133cb698e..5b5e7b14b3a 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -1345,6 +1345,7 @@ sframe_xlate_do_escape_expr (const struct sframe_xlate_ctx *xlate_ctx, || i >= CFI_ESC_NUM_EXP || (i < 2 && (e->exp.X_op != O_constant + || e->type != CFI_ESC_byte || e->reloc != TC_PARSE_CONS_RETURN_NONE))) goto warn_and_exit; items[i] = e->exp.X_add_number; @@ -1409,6 +1410,7 @@ sframe_xlate_do_escape_val_offset (const struct sframe_xlate_ctx *xlate_ctx, { e = e->next; if (i >= CFI_ESC_NUM_EXP || e->exp.X_op != O_constant + || e->type != CFI_ESC_byte || e->reloc != TC_PARSE_CONS_RETURN_NONE) goto warn_and_exit; items[i] = e->exp.X_add_number; @@ -1483,7 +1485,9 @@ sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx, if (!e) return SFRAME_XLATE_ERR_INVAL; - if (e->exp.X_op != O_constant || e->reloc != TC_PARSE_CONS_RETURN_NONE) + if (e->exp.X_op != O_constant + || e->type != CFI_ESC_byte + || e->reloc != TC_PARSE_CONS_RETURN_NONE) return SFRAME_XLATE_ERR_NOTREPRESENTED; firstop = e->exp.X_add_number; @@ -1495,6 +1499,7 @@ sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx, { e = e->next; if (e->exp.X_op != O_constant || e->exp.X_add_number != DW_CFA_nop + || e->type != CFI_ESC_byte || e->reloc != TC_PARSE_CONS_RETURN_NONE) { warn_p = true; diff --git a/gas/testsuite/gas/cfi/listing.l b/gas/testsuite/gas/cfi/listing.l index b15c6ca605c..b30f1143020 100644 --- a/gas/testsuite/gas/cfi/listing.l +++ b/gas/testsuite/gas/cfi/listing.l @@ -20,8 +20,20 @@ [ ]*[0-9]*[ ]+([0-9a-f]{4} [0 ]+)?\.cfi_endproc [ ]*[0-9]*[ ]* [ ]*[0-9]*[ ]+func2: -[ ]*[0-9]*[ ]+[0-9a-f]{4} (1[048]00 ?0000|0000 ?001[048])[ ]+\.cfi_startproc +[ ]*[0-9]*[ ]+[0-9a-f]{4} ((1C|2[048])00 ?0000|0000 ?00(1C|2[048]))[ ]+\.cfi_startproc [ ]*[0-9]*[ ]+(4[048]00 ?0000|0000 ?004[048]) * [ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop +[ ]*[0-9]*[ ]+/\* DW_CFA_register reg127, reg129. \*/ +[ ]*[0-9]*[ ]+[0-9a-f]{4} 4.09 ?7F81[ ]+\.cfi_escape 0x09, uleb128\(127\), uleb128\(129\) +[ ]*[0-9]*[ ]+01 +[ ]*[0-9]*[ ]+/\* DW_CFA_val_expression reg250, ... \*/ +[ ]*[0-9]*[ ]+[0-9a-f]{4} 16FA ?01[ ]+\.cfi_escape 0x16, uleb128\(250\) +[ ]*[0-9]*[ ]+/\* ... . \*/ +[ ]*[0-9]*[ ]+[0-9a-f]{4} 03[ ]+\.cfi_escape uleb128\(.LE0e - .LE0s\) +[ ]*[0-9]*[ ]+\.cfi_label .LE0s +[ ]*[0-9]*[ ]+/\* DW_OP_breg3. \*/ +[ ]*[0-9]*[ ]+[0-9a-f]{4} 7380 ?78[ ]+\.cfi_escape 0x73, sleb128\(-1024\) +[ ]*[0-9]*[ ]+\.cfi_label .LE0e +[ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop [ ]*[0-9]*[ ]+([0-9a-f]{4} [0 ]+)?\.cfi_endproc #pass diff --git a/gas/testsuite/gas/cfi/listing.s b/gas/testsuite/gas/cfi/listing.s index e091c54fa56..449ac8970ef 100644 --- a/gas/testsuite/gas/cfi/listing.s +++ b/gas/testsuite/gas/cfi/listing.s @@ -19,4 +19,15 @@ func: func2: .cfi_startproc .nop + /* DW_CFA_register reg127, reg129. */ + .cfi_escape 0x09, uleb128(127), uleb128(129) + /* DW_CFA_val_expression reg250, ... */ + .cfi_escape 0x16, uleb128(250) + /* ... . */ + .cfi_escape uleb128(.LE0e - .LE0s) + .cfi_label .LE0s + /* DW_OP_breg3. */ + .cfi_escape 0x73, sleb128(-1024) + .cfi_label .LE0e + .nop .cfi_endproc