From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 74921 invoked by alias); 17 Nov 2016 19:19:17 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 74900 invoked by uid 89); 17 Nov 2016 19:19:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.3 required=5.0 tests=AWL,BAYES_05,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 spammy=completion, Sync, libibertyh, XNEWVEC X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0b-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.158.5) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 17 Nov 2016 19:19:06 +0000 Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.17/8.16.0.17) with SMTP id uAHJIw1E069274 for ; Thu, 17 Nov 2016 14:19:04 -0500 Received: from e33.co.us.ibm.com (e33.co.us.ibm.com [32.97.110.151]) by mx0b-001b2d01.pphosted.com with ESMTP id 26sef6wnj2-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Thu, 17 Nov 2016 14:19:04 -0500 Received: from localhost by e33.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 17 Nov 2016 12:19:03 -0700 Received: from d03dlp03.boulder.ibm.com (9.17.202.179) by e33.co.us.ibm.com (192.168.1.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 17 Nov 2016 12:19:00 -0700 Received: from b03cxnp07029.gho.boulder.ibm.com (b03cxnp07029.gho.boulder.ibm.com [9.17.130.16]) by d03dlp03.boulder.ibm.com (Postfix) with ESMTP id 7986719D8047; Thu, 17 Nov 2016 12:18:20 -0700 (MST) Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id uAHJIw2A15597890; Thu, 17 Nov 2016 12:18:58 -0700 Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DDF456E03A; Thu, 17 Nov 2016 12:18:57 -0700 (MST) Received: from otta.rchland.ibm.com (unknown [9.10.86.72]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP id 60D386E038; Thu, 17 Nov 2016 12:18:57 -0700 (MST) To: gdb-patches@sourceware.org Cc: Ulrich Weigand , Pedro Alves , Alan Modra , binutils From: Peter Bergner Subject: [PATCH 1/2] Add support for setting disassembler-options in GDB for POWER, ARM and S390 Date: Thu, 17 Nov 2016 19:19:00 -0000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16111719-0008-0000-0000-0000061A4058 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00006095; HX=3.00000240; KW=3.00000007; PH=3.00000004; SC=3.00000189; SDB=6.00782050; UDB=6.00377328; IPR=6.00559556; BA=6.00004889; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00013362; XFM=3.00000011; UTC=2016-11-17 19:19:01 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16111719-0009-0000-0000-00003D196AB8 Message-Id: X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2016-11-17_10:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=3 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1609300000 definitions=main-1611170334 X-IsSubscribed: yes X-SW-Source: 2016-11/txt/msg00491.txt.bz2 Ping. This is the same as my last patch posted here: https://sourceware.org/ml/binutils/2016-11/msg00029.html ...except for that we no longer output "default" for a NULL disassembler_options value, and instead just output ''. I will note that doing "set disassembler-options" does reset the disassembler_options value to NULL. I'll shortly post a follow-on patch that splits the huge ppc disassembly test case into multiple test cases which uses the "set disassembler-options ..." command to correctly choose the disassembly cpu/ISA to disassemble the tests with. Is this version ok? Peter include/ * dis-asm.h (parse_arm_disassembler_option): Remove prototype. (set_arm_regname_option): Likewise. (disassemble_init_s390): New prototype. (disassembler_options_names_powerpc): Likewise. (disassembler_options_names_arm): Likewise. (disassembler_options_desc_arm): Likewise. (disassembler_options_names_s390): Likewise. (disassembler_options_desc_s390): Likewise. opcodes/ * disassemble.c (disassemble_init_for_target): Handle s390 init. * ppc-dis.c: Include "libiberty.h". (ppc_opts): Add "32" and "64" entries. (parse_ppc_dis_option): New function. (disassembler_options_names_powerpc): Likewise. (powerpc_init_dialect): Use parse_ppc_dis_option(). Add break to switch statement. (print_ppc_disassembler_options): Remove printing of "32" and "64". * arm-dis.c: Include "libiberty.h". (struct arm_regname): Add 'long_name' field. (regnames): Initialize it. (set_arm_regname_option): Remove function. (parse_arm_disassembler_option): Make static. (disassembler_options_names_arm): New function. (disassembler_options_desc_arm): Likewise. * s390-dis.c: Include "libiberty.h". (struct options_t): New structure type. (options): New structure. (init_disasm): Rename from this... (disassemble_init_s390): ...to this. Add initializations for current_arch_mask and option_use_insn_len_bits_p. Remove init_flag. (disassembler_options_names_s390): New function. (disassembler_options_desc_s390): Likewise. (print_s390_disassembler_options): Print using information from struct 'options'. gdb/ * gdbarch.sh (gdbarch_disassembler_options): New variable. (gdbarch_disassembler_options_names): Likewise. (gdbarch_disassembler_options_descriptions): Likewise. * gdbarch.c: Regenerate. * gdbarch.h: Likewise. * disasm.c: Include "arch-utils.h", "gdbcmd.h", "gdbcmd.h" and "safe-ctype.h". (gdb_disassemble_info): Initilize di.disassembler_options. (gdb_buffered_insn_length_init_dis): Initilize di->application_data and di->disassembler_options. (cleanup_disassembler_options): New function. (parse_disassembler_options): Likewise. (set_disassembler_options): Likewise. (show_disassembler_options): Likewise. (disassembler_options_completer): Likewise. (_initialize_disasm): Likewise. * disasm.h (set_disassembler_options): New prototype. (show_disassembler_options): Likewise. * rs6000-tdep.c (rs6000_gdbarch_init): Call set_gdbarch_disassembler_options_names. * arm-tdep.c: Include "disasm.h" and "cli/cli-decode.h". (disassembly_style): Delete static variable. (set_disassembly_style): Delete function and prototype. (show_disassembly_style_sfunc): New function. (set_disassembly_style_sfunc): Call set_disassembler_options. (arm_gdbarch_init): Call set_gdbarch_disassembler_options, set_gdbarch_disassembler_options_names and set_gdbarch_disassembler_options_descriptions. (_initialize_arm_tdep): New static variable 'disassembly_style'; Remove calls to parse_arm_disassembler_option & set_arm_regname_option. Pass show_disassembly_style_sfunc to the "disassembler" setshow command. * s390-tdep.c (s390_gdbarch_init): Call functions set_gdbarch_disassembler_options_names and set_gdbarch_disassembler_options_descriptions. diff --git a/include/dis-asm.h b/include/dis-asm.h index 2cefff4..a6b61e2 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -331,14 +331,18 @@ extern void print_ppc_disassembler_options (FILE *); extern void print_riscv_disassembler_options (FILE *); extern void print_arm_disassembler_options (FILE *); extern void print_arc_disassembler_options (FILE *); -extern void parse_arm_disassembler_option (char *); extern void print_s390_disassembler_options (FILE *); extern int get_arm_regname_num_options (void); -extern int set_arm_regname_option (int); extern int get_arm_regnames (int, const char **, const char **, const char *const **); extern bfd_boolean aarch64_symbol_is_valid (asymbol *, struct disassemble_info *); extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *); extern void disassemble_init_powerpc (struct disassemble_info *); +extern void disassemble_init_s390 (struct disassemble_info *); +extern const char **disassembler_options_names_powerpc (void); +extern const char **disassembler_options_names_arm (void); +extern const char **disassembler_options_desc_arm (void); +extern const char **disassembler_options_names_s390 (void); +extern const char **disassembler_options_desc_s390 (void); /* Fetch the disassembler for a given BFD, if that support is available. */ extern disassembler_ftype disassembler (bfd *); diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index e1fb65c..6418ada 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -643,6 +643,11 @@ disassemble_init_for_target (struct disassemble_info * info) disassemble_init_powerpc (info); break; #endif +#ifdef ARCH_s390 + case bfd_arch_s390: + disassemble_init_s390 (info); + break; +#endif default: break; } diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c index da1301e..af8c756 100644 --- a/opcodes/ppc-dis.c +++ b/opcodes/ppc-dis.c @@ -26,6 +26,7 @@ #include "elf/ppc.h" #include "opintl.h" #include "opcode/ppc.h" +#include "libiberty.h" /* This file provides several disassembler functions, all of which use the disassembler interface defined in dis-asm.h. Several functions @@ -172,8 +173,12 @@ struct ppc_mopt ppc_opts[] = { 0 }, { "ppc32", PPC_OPCODE_PPC, 0 }, + { "32", PPC_OPCODE_PPC, + 0 }, { "ppc64", PPC_OPCODE_PPC | PPC_OPCODE_64, 0 }, + { "64", PPC_OPCODE_PPC | PPC_OPCODE_64, + 0 }, { "ppc64bridge", PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE, 0 }, { "ppcps", PPC_OPCODE_PPC | PPC_OPCODE_PPCPS, @@ -271,6 +276,27 @@ ppc_parse_cpu (ppc_cpu_t ppc_cpu, ppc_cpu_t *sticky, const char *arg) return ppc_cpu; } +/* Parse the OPTIONS argument looking for ',' seperated cpu names. + Return the length of the current option, or 0 if there are no more. + Update OPTIONS to point to the next option, or NULL otherwise. */ + +static char * +parse_ppc_dis_option (char *cpu, const char *options) +{ + char *next = strchr (options, ','); + + if (next != NULL) + { + strncpy (cpu, options, (size_t) (next - options)); + cpu[(size_t) (next - options)] = 0; + next++; + } + else + strcpy (cpu, options); + + return next; +} + /* Determine which set of machines to disassemble for. */ static void @@ -324,29 +350,24 @@ powerpc_init_dialect (struct disassemble_info *info) break; default: dialect = ppc_parse_cpu (dialect, &sticky, "power9") | PPC_OPCODE_ANY; + break; } arg = info->disassembler_options; while (arg != NULL) { ppc_cpu_t new_cpu = 0; - char *end = strchr (arg, ','); + char opt[64]; + arg = parse_ppc_dis_option (opt, arg); - if (end != NULL) - *end = 0; - - if ((new_cpu = ppc_parse_cpu (dialect, &sticky, arg)) != 0) - dialect = new_cpu; - else if (strcmp (arg, "32") == 0) + if (strcmp (opt, "32") == 0) dialect &= ~(ppc_cpu_t) PPC_OPCODE_64; - else if (strcmp (arg, "64") == 0) + else if (strcmp (opt, "64") == 0) dialect |= PPC_OPCODE_64; + else if ((new_cpu = ppc_parse_cpu (dialect, &sticky, opt)) != 0) + dialect = new_cpu; else - fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), arg); - - if (end != NULL) - *end++ = ','; - arg = end; + fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), opt); } info->private_data = priv; @@ -767,6 +788,24 @@ print_insn_powerpc (bfd_vma memaddr, return 4; } +const char ** +disassembler_options_names_powerpc (void) +{ + static const char **options = NULL; + + if (options == NULL) + { + size_t i; + size_t num_options = sizeof (ppc_opts) / sizeof (ppc_opts[0]); + options = XNEWVEC (const char *, num_options + 1); + for (i = 0; i < num_options; i++) + options[i] = ppc_opts[i].opt; + options[i] = NULL; + } + + return options; +} + void print_ppc_disassembler_options (FILE *stream) { @@ -785,5 +824,5 @@ the -M switch:\n")); col = 0; } } - fprintf (stream, " 32, 64\n"); + fprintf (stream, "\n"); } diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index 87d4930..939005d 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -26,6 +26,7 @@ #include "opcode/arm.h" #include "opintl.h" #include "safe-ctype.h" +#include "libiberty.h" #include "floatformat.h" /* FIXME: This shouldn't be done here. */ @@ -3164,6 +3165,7 @@ static const char *const arm_shift[] = typedef struct { const char *name; + const char *long_name; const char *description; const char *reg_names[16]; } @@ -3171,17 +3173,17 @@ arm_regname; static const arm_regname regnames[] = { - { "raw" , "Select raw register names", + { "raw" , "reg-names-raw", "Select raw register names", { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, - { "gcc", "Select register names used by GCC", + { "gcc", "reg-names-gcc", "Select register names used by GCC", { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }}, - { "std", "Select register names used in ARM's ISA documentation", + { "std", "reg-names-std", "Select register names used in ARM's ISA documentation", { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }}, - { "apcs", "Select register names used in the APCS", + { "apcs", "reg-names-apcs", "Select register names used in the APCS", { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }}, - { "atpcs", "Select register names used in the ATPCS", + { "atpcs", "reg-names-atpcs", "Select register names used in the ATPCS", { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }}, - { "special-atpcs", "Select special register names used in the ATPCS", + { "special-atpcs", "reg-names-special-atpcs", "Select special register names used in the ATPCS", { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}, }; @@ -3234,14 +3236,6 @@ get_arm_regname_num_options (void) } int -set_arm_regname_option (int option) -{ - int old = regname_selected; - regname_selected = option; - return old; -} - -int get_arm_regnames (int option, const char **setname, const char **setdescription, @@ -6094,7 +6088,7 @@ arm_symbol_is_valid (asymbol * sym, /* Parse an individual disassembler option. */ -void +static void parse_arm_disassembler_option (char *option) { if (option == NULL) @@ -6810,6 +6804,46 @@ print_insn_little_arm (bfd_vma pc, struct disassemble_info *info) return print_insn (pc, info, TRUE); } +const char ** +disassembler_options_names_arm (void) +{ + static const char **options = NULL; + + if (options == NULL) + { + size_t i; + size_t num_options = NUM_ARM_REGNAMES + 2; + options = XNEWVEC (const char *, num_options + 1); + for (i = 0; i < NUM_ARM_REGNAMES; i++) + options[i] = regnames[i].long_name; + options[i++] = "force-thumb"; + options[i++] = "no-force-thumb"; + options[i] = NULL; + } + + return options; +} + +const char ** +disassembler_options_desc_arm (void) +{ + static const char **desc = NULL; + + if (desc == NULL) + { + size_t i; + size_t num_desc = NUM_ARM_REGNAMES + 2; + desc = XNEWVEC (const char *, num_desc + 1); + for (i = 0; i < NUM_ARM_REGNAMES; i++) + desc[i] = regnames[i].description; + desc[i++] = "Assume all insns are Thumb insns"; + desc[i++] = "Examine preceding label to determine an insn's type"; + desc[i] = NULL; + } + + return desc; +} + void print_arm_disassembler_options (FILE *stream) { diff --git a/opcodes/s390-dis.c b/opcodes/s390-dis.c index 8134073..f6e85de 100644 --- a/opcodes/s390-dis.c +++ b/opcodes/s390-dis.c @@ -25,16 +25,30 @@ #include "dis-asm.h" #include "opintl.h" #include "opcode/s390.h" +#include "libiberty.h" -static int init_flag = 0; static int opc_index[256]; static int current_arch_mask = 0; static int option_use_insn_len_bits_p = 0; +typedef struct +{ + const char *name; + const char *description; +} options_t; + +static const options_t options[] = +{ + { "esa" , "Disassemble in ESA architecture mode" }, + { "zarch", "Disassemble in z/Architecture mode" }, + { "insnlength", "Print unknown instructions according to " + "length from first two bits" } +}; + /* Set up index table for first opcode byte. */ -static void -init_disasm (struct disassemble_info *info) +void +disassemble_init_s390 (struct disassemble_info *info) { int i; const char *p; @@ -46,6 +60,9 @@ init_disasm (struct disassemble_info *info) for (i = s390_num_opcodes; i--; ) opc_index[s390_opcodes[i].opcode[0]] = i; + current_arch_mask = 1 << S390_OPCODE_ZARCH; + option_use_insn_len_bits_p = 0; + for (p = info->disassembler_options; p != NULL; ) { if (CONST_STRNEQ (p, "esa")) @@ -61,11 +78,6 @@ init_disasm (struct disassemble_info *info) if (p != NULL) p++; } - - if (!current_arch_mask) - current_arch_mask = 1 << S390_OPCODE_ZARCH; - - init_flag = 1; } /* Derive the length of an instruction from its first byte. */ @@ -266,9 +278,6 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) unsigned int value; int status, opsize, bufsize, bytes_to_dump, i; - if (init_flag == 0) - init_disasm (info); - /* The output looks better if we put 6 bytes on a line. */ info->bytes_per_line = 6; @@ -360,15 +369,58 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) return 0; } +const char ** +disassembler_options_names_s390 (void) +{ + static const char **opts = NULL; + + if (opts == NULL) + { + size_t i, num_options = sizeof (options) / sizeof (options[0]); + opts = XNEWVEC (const char *, num_options); + for (i = 0; i < num_options; i++) + opts[i] = options[i].name; + opts[i] = NULL; + } + + return opts; +} + +const char ** +disassembler_options_desc_s390 (void) +{ + static const char **desc = NULL; + + if (desc == NULL) + { + size_t i, num_options = sizeof (options) / sizeof (options[0]); + desc = XNEWVEC (const char *, num_options + 1); + for (i = 0; i < num_options; i++) + desc[i] = options[i].description; + desc[i] = NULL; + } + + return desc; +} + void print_s390_disassembler_options (FILE *stream) { + unsigned int i, max_len = 0; fprintf (stream, _("\n\ The following S/390 specific disassembler options are supported for use\n\ with the -M switch (multiple options should be separated by commas):\n")); - fprintf (stream, _(" esa Disassemble in ESA architecture mode\n")); - fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n")); - fprintf (stream, _(" insnlength Print unknown instructions according " - "to length from first two bits\n")); + for (i = 0; sizeof (options) / sizeof (options[0]); i++) + { + unsigned int len = strlen (options[i].name); + if (max_len < len) + max_len = len; + } + + for (i = 0, max_len++; sizeof (options) / sizeof (options[0]); i++) + fprintf (stream, " %s%*c %s", + options[i].name, + (int)(max_len - strlen (options[i].name)), ' ', + options[i].description); } diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 28a3478..deba9db 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -1163,6 +1163,11 @@ m:const char *:gnu_triplet_regexp:void:::default_gnu_triplet_regexp::0 # each address in memory. m:int:addressable_memory_unit_size:void:::default_addressable_memory_unit_size::0 +# Functions for allowing a target to modify its disassembler options. +v:char *:disassembler_options:::0:0::0:pstring (gdbarch->disassembler_options) +v:const char **:disassembler_options_names:::0:0::0:pstring (*gdbarch->disassembler_options_names) +v:const char **:disassembler_options_descriptions:::0:0::0:pstring (*gdbarch->disassembler_options_descriptions) + EOF } diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 07b3ce5..7bc9806 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -339,6 +339,9 @@ struct gdbarch gdbarch_gcc_target_options_ftype *gcc_target_options; gdbarch_gnu_triplet_regexp_ftype *gnu_triplet_regexp; gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size; + char * disassembler_options; + const char ** disassembler_options_names; + const char ** disassembler_options_descriptions; }; /* Create a new ``struct gdbarch'' based on information provided by @@ -696,6 +699,9 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of gcc_target_options, invalid_p == 0 */ /* Skip verify of gnu_triplet_regexp, invalid_p == 0 */ /* Skip verify of addressable_memory_unit_size, invalid_p == 0 */ + /* Skip verify of disassembler_options, invalid_p == 0 */ + /* Skip verify of disassembler_options_names, invalid_p == 0 */ + /* Skip verify of disassembler_options_descriptions, invalid_p == 0 */ std::string buf = ui_file_as_string (log); if (!buf.empty ()) internal_error (__FILE__, __LINE__, @@ -881,6 +887,15 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: deprecated_function_start_offset = %s\n", core_addr_to_string_nz (gdbarch->deprecated_function_start_offset)); fprintf_unfiltered (file, + "gdbarch_dump: disassembler_options = %s\n", + pstring (gdbarch->disassembler_options)); + fprintf_unfiltered (file, + "gdbarch_dump: disassembler_options_descriptions = %s\n", + pstring (*gdbarch->disassembler_options_descriptions)); + fprintf_unfiltered (file, + "gdbarch_dump: disassembler_options_names = %s\n", + pstring (*gdbarch->disassembler_options_names)); + fprintf_unfiltered (file, "gdbarch_dump: gdbarch_displaced_step_copy_insn_p() = %d\n", gdbarch_displaced_step_copy_insn_p (gdbarch)); fprintf_unfiltered (file, @@ -4962,6 +4977,57 @@ set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch, gdbarch->addressable_memory_unit_size = addressable_memory_unit_size; } +char * +gdbarch_disassembler_options (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + /* Skip verify of disassembler_options, invalid_p == 0 */ + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options called\n"); + return gdbarch->disassembler_options; +} + +void +set_gdbarch_disassembler_options (struct gdbarch *gdbarch, + char * disassembler_options) +{ + gdbarch->disassembler_options = disassembler_options; +} + +const char ** +gdbarch_disassembler_options_names (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + /* Skip verify of disassembler_options_names, invalid_p == 0 */ + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options_names called\n"); + return gdbarch->disassembler_options_names; +} + +void +set_gdbarch_disassembler_options_names (struct gdbarch *gdbarch, + const char ** disassembler_options_names) +{ + gdbarch->disassembler_options_names = disassembler_options_names; +} + +const char ** +gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + /* Skip verify of disassembler_options_descriptions, invalid_p == 0 */ + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options_descriptions called\n"); + return gdbarch->disassembler_options_descriptions; +} + +void +set_gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch, + const char ** disassembler_options_descriptions) +{ + gdbarch->disassembler_options_descriptions = disassembler_options_descriptions; +} + /* Keep a registry of per-architecture data-pointers required by GDB modules. */ diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index cc95914..ee82677 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1545,6 +1545,17 @@ typedef int (gdbarch_addressable_memory_unit_size_ftype) (struct gdbarch *gdbarc extern int gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch); extern void set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch, gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size); +/* Functions for allowing a target to modify its disassembler options. */ + +extern char * gdbarch_disassembler_options (struct gdbarch *gdbarch); +extern void set_gdbarch_disassembler_options (struct gdbarch *gdbarch, char * disassembler_options); + +extern const char ** gdbarch_disassembler_options_names (struct gdbarch *gdbarch); +extern void set_gdbarch_disassembler_options_names (struct gdbarch *gdbarch, const char ** disassembler_options_names); + +extern const char ** gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch); +extern void set_gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch, const char ** disassembler_options_descriptions); + /* Definition for an unknown syscall, used basically in error-cases. */ #define UNKNOWN_SYSCALL (-1) diff --git a/gdb/disasm.c b/gdb/disasm.c index 07c3abe..cb039bab 100644 --- a/gdb/disasm.c +++ b/gdb/disasm.c @@ -18,13 +18,17 @@ along with this program. If not, see . */ #include "defs.h" +#include "arch-utils.h" #include "target.h" #include "value.h" #include "ui-out.h" #include "disasm.h" #include "gdbcore.h" +#include "gdbcmd.h" #include "dis-asm.h" +#include "cli/cli-decode.h" #include "source.h" +#include "safe-ctype.h" #include /* Disassemble functions. @@ -785,6 +789,7 @@ gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file) di.endian = gdbarch_byte_order (gdbarch); di.endian_code = gdbarch_byte_order_for_code (gdbarch); di.application_data = gdbarch; + di.disassembler_options = gdbarch_disassembler_options (gdbarch); disassemble_init_for_target (&di); return di; } @@ -901,6 +906,8 @@ gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch, di->endian = gdbarch_byte_order (gdbarch); di->endian_code = gdbarch_byte_order_for_code (gdbarch); + di->application_data = gdbarch; + di->disassembler_options = gdbarch_disassembler_options (gdbarch); disassemble_init_for_target (di); } @@ -917,3 +924,222 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch, return gdbarch_print_insn (gdbarch, addr, &di); } + +/* Remove whitespace and consecutive commas from OPTIONS. */ + +char * +cleanup_disassembler_options (char *options) +{ + char *str; + size_t i, len; + + if (options == NULL) + return NULL; + + /* Strip off all trailing whitespace and commas. */ + for (len = strlen (options); len > 0; len--) + { + if (!ISSPACE (options[len - 1]) && options[len - 1] != ',') + break; + options[len - 1] = '\0'; + } + + /* Convert all remaining whitespace to commas. */ + for (i = 0; options[i] != '\0'; i++) + if (ISSPACE (options[i])) + options[i] = ','; + + /* Remove consecutive commas. */ + for (str = options; *str != '\0'; str++) + if (*str == ',' && *(str + 1) == ',') + { + char *next = str++; + while (*next == ',') + next++; + len = strlen (next); + memmove (str, next, len); + next[len - (size_t)(next - str)] = '\0'; + } + return (strlen (options) != 0) ? options : NULL; +} + +/* Parse OPTIONS looking for ',' seperated disassembler options and + verify each option is valid. Return NULL if all options are valid. + Otherwise, return a pointer to the first invalid disassembler option. */ + +static char * +parse_disassembler_options (const char *options, const char **valid_names) +{ + static char opt[256]; + size_t i; + + if (options == NULL) + return NULL; + + while (*options) + { + /* Copy the current disassembler option into OPT. */ + const char *separator = strchr (options, ','); + if (separator != NULL) + { + strncpy (opt, options, (size_t) (separator - options)); + opt[(size_t) (separator - options)] = 0; + options = separator; + /* Skip to the next disassembler option. */ + while (*options == ',') + options++; + } + else + options = stpcpy (opt, options); + + /* Verify OPT is a valid disassembler option. */ + for (i = 0; valid_names[i] != NULL; i++) + if (strcmp (opt, valid_names[i]) == 0) + break; + if (valid_names[i] == NULL) + return opt; + } + + return NULL; +} + +void +set_disassembler_options (char *args, int from_tty, struct cmd_list_element *c) +{ + struct gdbarch *gdbarch = get_current_arch (); + const char **valid_names = gdbarch_disassembler_options_names (gdbarch); + if (valid_names == NULL) + { + fprintf_filtered (gdb_stdlog, _("\ +'set disassembler' is not supported on this architecture.\n")); + return; + } + + char *options = *(char **)c->var; + options = cleanup_disassembler_options (options); + char *opt = parse_disassembler_options (options, valid_names); + if (opt != NULL) + { + fprintf_filtered (gdb_stdlog, + _("Invalid disassembler option value: '%s'.\n"), opt); + return; + } + + free (gdbarch_disassembler_options (gdbarch)); + if (options != NULL) + set_gdbarch_disassembler_options (gdbarch, xstrdup (options)); + else + set_gdbarch_disassembler_options (gdbarch, NULL); +} + +void +show_disassembler_options (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + struct gdbarch *gdbarch = get_current_arch (); + + const char *options = gdbarch_disassembler_options (gdbarch); + if (options == NULL) + options = ""; + + fprintf_filtered (file, _("The current disassembler options are '%s'\n"), + options); + + const char **names = gdbarch_disassembler_options_names (gdbarch); + const char **desc = gdbarch_disassembler_options_descriptions (gdbarch); + + if (names == NULL) + return; + + fprintf_filtered (file, _("\n\ +The following disassembler options are supported for use with\n\ +the 'set disassembler-options