From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20519 invoked by alias); 23 Oct 2010 04:23:11 -0000 Received: (qmail 20373 invoked by uid 22791); 23 Oct 2010 04:23:04 -0000 X-SWARE-Spam-Status: No, hits=-0.5 required=5.0 tests=AWL,BAYES_20,TW_CP,TW_EG,TW_XF,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from e24smtp05.br.ibm.com (HELO e24smtp05.br.ibm.com) (32.104.18.26) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 23 Oct 2010 04:22:50 +0000 Received: from mailhub3.br.ibm.com (mailhub3.br.ibm.com [9.18.232.110]) by e24smtp05.br.ibm.com (8.14.4/8.13.1) with ESMTP id o9N4G23X009446 for ; Sat, 23 Oct 2010 02:16:02 -0200 Received: from d24av05.br.ibm.com (d24av05.br.ibm.com [9.18.232.44]) by mailhub3.br.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o9N4TC3A3014656 for ; Sat, 23 Oct 2010 02:29:12 -0200 Received: from d24av05.br.ibm.com (loopback [127.0.0.1]) by d24av05.br.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id o9N4Mi0M031938 for ; Sat, 23 Oct 2010 02:22:44 -0200 Received: from [9.78.143.137] ([9.78.143.137]) by d24av05.br.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id o9N4Mg5a031911 for ; Sat, 23 Oct 2010 02:22:42 -0200 Subject: Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints From: Thiago Jung Bauermann To: gdb-patches ml In-Reply-To: <1282074110.2606.703.camel@hactar> References: <1282074110.2606.703.camel@hactar> Content-Type: text/plain; charset="UTF-8" Date: Sat, 23 Oct 2010 04:23:00 -0000 Message-ID: <1287807761.10521.423.camel@hactar> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes 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 X-SW-Source: 2010-10/txt/msg00357.txt.bz2 Hi, This is a new version of the patch. It doesn't rely on an old_ops field in struct breakpoint. Instead, it makes the breakpoint_ops methods for ranged watchpoint accept ranged software watchpoints (this was trivial and involved only new cases in some print methods), and adds a works_in_software_mode method which is called by update_watchpoint if it determines that it needs to downgrade a hardware watchpoint to a software watchpoint. In case it can't be done, it'll throw an exception. There are no regressions on ppc32-linux, ppc64-linux and i386-linux. Ok? -- []'s Thiago Jung Bauermann IBM Linux Technology Center 2010-10-23 Sergio Durigan Junior Thiago Jung Bauermann Implement support for PowerPC BookE masked and ranged watchpoints. gdb/ * breakpoint.c (update_watchpoint): Call breakpoint's breakpoint_ops.extra_resources_needed and breakpoint_ops.works_in_software_mode if available. (watchpoints_triggered): Handle the case of a hardware masked watchpoint trigger. (watchpoint_check): Handle the case of a hardware masked watchpoint trigger. (print_one_breakpoint_location): Call breakpoint's breakpoint_ops.print_one_detail if available. (hw_watchpoint_used_count): Call breakpoint's breakpoint_ops.extra_resources_needed if available. (insert_ranged_watchpoint, remove_ranged_watchpoint) (extra_resources_needed_ranged_watchpoint) (print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint) (print_recreate_ranged_watchpoint): New functions. (ranged_watchpoint_breakpoint_ops): New structure. (insert_masked_watchpoint, remove_masked_watchpoint) (extra_resources_needed_masked_watchpoint) (works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint) (print_one_detail_masked_watchpoint, print_mention_masked_watchpoint) (print_recreate_masked_watchpoint, is_masked_watchpoint): New functions. (masked_watchpoint_breakpoint_ops): New structure. (watch_command_1): Check for the existence of the `mask' parameter. Check whether a ranged hardware watchpoint can be used. Set b->ops according to the type of hardware watchpoint being created. (watch_range_command_1, watch_range_command) (awatch_range_command, rwatch_range_command): New functions. (_initialize_breakpoint): Register watch-range, awatch-range and rwatch-range commands. * breakpoint.h (struct ui_out): New opaque declaration. (struct breakpoint_ops) , , : New methods. Initialize them to NULL in all existing breakpoint_ops instances. (struct breakpoint_ops) : Add OLD_VAL parameter. Update all implementations of the method. (enum hw_point_flag): New enumeration. (struct breakpoint) : New field. * findcmd.c (parse_addr_range): New function factored out of parse_find_args. (parse_find_args): Call `parse_addr_range'. * ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function. (ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when ranged watchpoints are available. (ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint) (ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint) (ppc_linux_hw_point_extra_slot_count): New functions. (_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint, to_remove_mask_watchpoint, to_insert_ranged_watchpoint, to_remove_ranged_watchpoint, hw_point_extra_slot_count and to_can_use_special_hw_point. * target.c (update_current_target): Insert to_insert_mask_watchpoint, to_remove_mask_watchpoint, to_insert_ranged_watchpoint, to_remove_ranged_watchpoint, to_hw_point_extra_slot_count and to_can_use_special_hw_point. * target.h (enum hw_point_flag): New opaque declaration. (struct target_ops) , , , , , : New callbacks. (target_insert_mask_watchpoint, target_remove_mask_watchpoint) (target_insert_ranged_watchpoint, target_remove_ranged_watchpoint) (target_hw_point_extra_slot_count, target_can_use_special_hw_point): New defines. * ui-out.c (ui_out_field_range_core_addr): New function. * ui-out.h (ui_out_field_range_core_addr): Declare. * value.h (parse_addr_range): Declare. gdb/doc/ * gdb.texinfo (Set Watchpoints): Document mask parameter. (PowerPC Embedded): Document masked watchpoints and ranged watchpoints. Index: gdb.git/gdb/ada-lang.c =================================================================== --- gdb.git.orig/gdb/ada-lang.c 2010-10-13 15:59:11.000000000 -0300 +++ gdb.git/gdb/ada-lang.c 2010-10-22 18:41:37.000000000 -0200 @@ -10756,7 +10756,7 @@ print_recreate_exception (enum exception /* Virtual table for "catch exception" breakpoints. */ static enum print_stop_action -print_it_catch_exception (struct breakpoint *b) +print_it_catch_exception (struct breakpoint *b, const struct value *old_val) { return print_it_exception (ex_catch_exception, b); } @@ -10784,8 +10784,11 @@ static struct breakpoint_ops catch_excep NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ print_it_catch_exception, print_one_catch_exception, + NULL, /* print_one_detail */ print_mention_catch_exception, print_recreate_catch_exception }; @@ -10793,7 +10796,8 @@ static struct breakpoint_ops catch_excep /* Virtual table for "catch exception unhandled" breakpoints. */ static enum print_stop_action -print_it_catch_exception_unhandled (struct breakpoint *b) +print_it_catch_exception_unhandled (struct breakpoint *b, + const struct value *old_val) { return print_it_exception (ex_catch_exception_unhandled, b); } @@ -10822,8 +10826,11 @@ static struct breakpoint_ops catch_excep NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ print_it_catch_exception_unhandled, print_one_catch_exception_unhandled, + NULL, /* print_one_detail */ print_mention_catch_exception_unhandled, print_recreate_catch_exception_unhandled }; @@ -10831,7 +10838,7 @@ static struct breakpoint_ops catch_excep /* Virtual table for "catch assert" breakpoints. */ static enum print_stop_action -print_it_catch_assert (struct breakpoint *b) +print_it_catch_assert (struct breakpoint *b, const struct value *old_val) { return print_it_exception (ex_catch_assert, b); } @@ -10858,8 +10865,11 @@ static struct breakpoint_ops catch_asser NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ print_it_catch_assert, print_one_catch_assert, + NULL, /* print_one_detail */ print_mention_catch_assert, print_recreate_catch_assert }; Index: gdb.git/gdb/breakpoint.c =================================================================== --- gdb.git.orig/gdb/breakpoint.c 2010-10-22 18:41:34.000000000 -0200 +++ gdb.git/gdb/breakpoint.c 2010-10-22 18:41:37.000000000 -0200 @@ -219,6 +219,8 @@ static void disable_trace_command (char static void trace_pass_command (char *, int); +static int is_masked_watchpoint (const struct breakpoint *b); + /* Assuming we're creating a static tracepoint, does S look like a static tracepoint marker spec ("-m MARKER_ID")? */ #define is_marker_spec(s) \ @@ -1391,27 +1393,52 @@ update_watchpoint (struct breakpoint *b, if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint) && reparse) { - int i, mem_cnt, other_type_used; + int mem_cnt; - /* We need to determine how many resources are already used - for all other hardware watchpoints to see if we still have - enough resources to also fit this watchpoint in as well. - To avoid the hw_watchpoint_used_count call below from counting - this watchpoint, make sure that it is marked as a software - watchpoint. */ - b->type = bp_watchpoint; - i = hw_watchpoint_used_count (bp_hardware_watchpoint, - &other_type_used); mem_cnt = can_use_hardware_watchpoint (val_chain); if (!mem_cnt) - b->type = bp_watchpoint; + { + if (b->type == bp_hardware_watchpoint + && b->ops && b->ops->works_in_software_mode + && !b->ops->works_in_software_mode (b)) + error (_("This watchpoint cannot be used in software mode.")); + else + b->type = bp_watchpoint; + } else { - int target_resources_ok = target_can_use_hardware_watchpoint - (bp_hardware_watchpoint, i + mem_cnt, other_type_used); + int i, other_type_used, target_resources_ok; + enum bptype orig_type; + + if (b->ops && b->ops->extra_resources_needed) + mem_cnt += b->ops->extra_resources_needed (b); + + /* We need to determine how many resources are already used + for all other hardware watchpoints to see if we still have + enough resources to also fit this watchpoint in as well. + To avoid the hw_watchpoint_used_count call below from + counting this watchpoint, make sure that it is marked as a + software watchpoint. */ + orig_type = b->type; + b->type = bp_watchpoint; + i = hw_watchpoint_used_count (bp_hardware_watchpoint, + &other_type_used); + + target_resources_ok = target_can_use_hardware_watchpoint + (bp_hardware_watchpoint, i + mem_cnt, other_type_used) if (target_resources_ok <= 0) - b->type = bp_watchpoint; + { + if (orig_type == bp_hardware_watchpoint + && b->ops && b->ops->works_in_software_mode + && !b->ops->works_in_software_mode (b)) + { + b->type = bp_hardware_watchpoint; + error (_("This watchpoint cannot be used in software mode.")); + } + else + b->type = bp_watchpoint; + } else b->type = bp_hardware_watchpoint; } @@ -3356,7 +3383,7 @@ print_bp_stop_message (bpstat bs) print_it_typical. */ /* FIXME: how breakpoint can ever be NULL here? */ if (b != NULL && b->ops != NULL && b->ops->print_it != NULL) - return b->ops->print_it (b); + return b->ops->print_it (b, bs->old_val); else return print_it_typical (bs); } @@ -3492,15 +3519,30 @@ watchpoints_triggered (struct target_wai b->watchpoint_triggered = watch_triggered_no; for (loc = b->loc; loc; loc = loc->next) - /* Exact match not required. Within range is - sufficient. */ - if (target_watchpoint_addr_within_range (¤t_target, - addr, loc->address, - loc->length)) - { - b->watchpoint_triggered = watch_triggered_yes; - break; - } + { + CORE_ADDR newaddr, start; + + if (is_masked_watchpoint (loc->owner)) + { + newaddr = addr & loc->owner->hw_wp_mask; + start = loc->address & loc->owner->hw_wp_mask; + } + else + { + newaddr = addr; + start = loc->address; + } + + /* Exact match not required. Within range is + sufficient. */ + if (target_watchpoint_addr_within_range (¤t_target, + newaddr, start, + loc->length)) + { + b->watchpoint_triggered = watch_triggered_yes; + break; + } + } } return 1; @@ -3614,6 +3656,11 @@ watchpoint_check (void *p) b->val_valid = 1; return WP_VALUE_CHANGED; } + else if (is_masked_watchpoint (b)) + /* Since we don't know the exact trigger address (from + stopped_data_address) Just tell the user we've triggered + a mask watchpoint. */ + return WP_VALUE_CHANGED; else { /* Nothing changed. */ @@ -4684,9 +4731,12 @@ print_one_breakpoint_location (struct br ui_out_field_int (uiout, "task", b->task); } } - + ui_out_text (uiout, "\n"); - + + if (!part_of_multiple && b->ops && b->ops->print_one_detail) + b->ops->print_one_detail (b, uiout); + if (!part_of_multiple && b->static_trace_marker_id) { gdb_assert (b->type == bp_static_tracepoint); @@ -5857,7 +5907,7 @@ breakpoint_hit_catch_fork (struct breakp /* Implement the "print_it" breakpoint_ops method for fork catchpoints. */ static enum print_stop_action -print_it_catch_fork (struct breakpoint *b) +print_it_catch_fork (struct breakpoint *b, const struct value *old_val) { annotate_catchpoint (b->number); printf_filtered (_("\nCatchpoint %d (forked process %d), "), @@ -5915,8 +5965,11 @@ static struct breakpoint_ops catch_fork_ insert_catch_fork, remove_catch_fork, breakpoint_hit_catch_fork, + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ print_it_catch_fork, print_one_catch_fork, + NULL, /* print_one_detail */ print_mention_catch_fork, print_recreate_catch_fork }; @@ -5949,7 +6002,7 @@ breakpoint_hit_catch_vfork (struct break /* Implement the "print_it" breakpoint_ops method for vfork catchpoints. */ static enum print_stop_action -print_it_catch_vfork (struct breakpoint *b) +print_it_catch_vfork (struct breakpoint *b, const struct value *old_val) { annotate_catchpoint (b->number); printf_filtered (_("\nCatchpoint %d (vforked process %d), "), @@ -6006,8 +6059,11 @@ static struct breakpoint_ops catch_vfork insert_catch_vfork, remove_catch_vfork, breakpoint_hit_catch_vfork, + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ print_it_catch_vfork, print_one_catch_vfork, + NULL, /* print_one_detail */ print_mention_catch_vfork, print_recreate_catch_vfork }; @@ -6127,7 +6183,7 @@ breakpoint_hit_catch_syscall (struct bre catchpoints. */ static enum print_stop_action -print_it_catch_syscall (struct breakpoint *b) +print_it_catch_syscall (struct breakpoint *b, const struct value *old_val) { /* These are needed because we want to know in which state a syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY @@ -6287,8 +6343,11 @@ static struct breakpoint_ops catch_sysca insert_catch_syscall, remove_catch_syscall, breakpoint_hit_catch_syscall, + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ print_it_catch_syscall, print_one_catch_syscall, + NULL, /* print_one_detail */ print_mention_catch_syscall, print_recreate_catch_syscall }; @@ -6390,7 +6449,7 @@ breakpoint_hit_catch_exec (struct breakp } static enum print_stop_action -print_it_catch_exec (struct breakpoint *b) +print_it_catch_exec (struct breakpoint *b, const struct value *old_val) { annotate_catchpoint (b->number); printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number, @@ -6440,8 +6499,11 @@ static struct breakpoint_ops catch_exec_ insert_catch_exec, remove_catch_exec, breakpoint_hit_catch_exec, + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ print_it_catch_exec, print_one_catch_exec, + NULL, /* print_one_detail */ print_mention_catch_exec, print_recreate_catch_exec }; @@ -6489,7 +6551,14 @@ hw_watchpoint_used_count (enum bptype ty if (breakpoint_enabled (b)) { if (b->type == type) - i++; + { + i++; + + /* Special types of hardware watchpoints can use more than + one register. */ + if (b->ops && b->ops->extra_resources_needed) + i += b->ops->extra_resources_needed (b); + } else if (is_hardware_watchpoint (b)) *other_type_used = 1; } @@ -8031,12 +8100,353 @@ static struct breakpoint_ops watchpoint_ insert_watchpoint, remove_watchpoint, NULL, /* breakpoint_hit */ + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ NULL, /* print_it */ NULL, /* print_one */ + NULL, /* print_one_detail */ NULL, /* print_mention */ NULL /* print_recreate */ }; +/* Implement the "insert" breakpoint_ops method for + ranged hardware watchpoints. */ + +static int +insert_ranged_watchpoint (struct bp_location *bpt) +{ + return target_insert_ranged_watchpoint (bpt->address, + bpt->length, + bpt->watchpoint_type); +} + +/* Implement the "remove" breakpoint_ops method for + ranged hardware watchpoints. */ + +static int +remove_ranged_watchpoint (struct bp_location *bpt) +{ + return target_remove_ranged_watchpoint (bpt->address, bpt->length, + bpt->watchpoint_type); +} + +/* Implement the "extra_resources_needed" breakpoint_ops method for + ranged hardware watchpoints. */ + +static int +extra_resources_needed_ranged_watchpoint (const struct breakpoint *b) +{ + return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH); +} + +/* Implement the "print_one_detail" breakpoint_ops method for + ranged hardware watchpoints. */ + +static void +print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout) +{ + /* If there's a separate expression for reparsing, then exp_string is already + a nice text set by watch_range_command_1 and was printed earlier. */ + if (b->exp_string_reparse) + return; + + gdb_assert (b->loc); + + ui_out_text (uiout, "\tmemory range: "); + ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch, + b->loc->address, b->loc->length); + ui_out_text (uiout, "\n"); +} + +/* Implement the "print_mention" breakpoint_ops method for + ranged hardware watchpoints. */ + +static void +print_mention_ranged_watchpoint (struct breakpoint *b) +{ + struct cleanup *ui_out_chain; + + switch (b->type) + { + case bp_watchpoint: + ui_out_text (uiout, "Ranged watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); + break; + case bp_hardware_watchpoint: + ui_out_text (uiout, "Ranged hardware watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); + break; + case bp_read_watchpoint: + ui_out_text (uiout, "Ranged hardware read watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt"); + break; + case bp_access_watchpoint: + ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt"); + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid hardware watchpoint type.")); + } + + ui_out_field_int (uiout, "number", b->number); + ui_out_text (uiout, ": "); + ui_out_field_string (uiout, "exp", b->exp_string); + do_cleanups (ui_out_chain); +} + +static void +print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp) +{ + switch (b->type) + { + case bp_watchpoint: + case bp_hardware_watchpoint: + if (b->exp_string_reparse) + fprintf_unfiltered (fp, "watch-range"); + else + fprintf_unfiltered (fp, "watch"); + break; + case bp_read_watchpoint: + if (b->exp_string_reparse) + fprintf_unfiltered (fp, "rwatch-range"); + else + fprintf_unfiltered (fp, "rwatch"); + break; + case bp_access_watchpoint: + if (b->exp_string_reparse) + fprintf_unfiltered (fp, "awatch-range"); + else + fprintf_unfiltered (fp, "awatch"); + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid hardware watchpoint type.")); + } + + if (b->exp_string_reparse) + { + char start_addr[40], length[40]; + + /* watch_range_command_1 creates the following expression to represent + internally a ranged watchpoint. */ + sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr); + + fprintf_unfiltered (fp, " %s, +%s", start_addr, length); + } + else + fprintf_unfiltered (fp, " %s", b->exp_string); +} + +/* The breakpoint_ops structure to be used in ranged hardware watchpoints. */ + +static struct breakpoint_ops ranged_watchpoint_breakpoint_ops = +{ + insert_ranged_watchpoint, + remove_ranged_watchpoint, + NULL, /* breakpoint_hit */ + extra_resources_needed_ranged_watchpoint, + NULL, /* works_in_software_mode */ + NULL, /* print_it */ + NULL, /* print_one */ + print_one_detail_ranged_watchpoint, + print_mention_ranged_watchpoint, + print_recreate_ranged_watchpoint +}; + +/* Implement the "insert" breakpoint_ops method for + masked hardware watchpoints. */ + +static int +insert_masked_watchpoint (struct bp_location *bpt) +{ + return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask, + bpt->watchpoint_type); +} + +/* Implement the "remove" breakpoint_ops method for + masked hardware watchpoints. */ + +static int +remove_masked_watchpoint (struct bp_location *bpt) +{ + return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask, + bpt->watchpoint_type); +} + +/* Implement the "extra_resources_needed" breakpoint_ops method for + masked hardware watchpoints. */ + +static int +extra_resources_needed_masked_watchpoint (const struct breakpoint *b) +{ + return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH); +} + +/* Implement the "works_in_software_mode_masked_watchpoint" breakpoint_ops + method for masked hardware watchpoints. */ + +static int +works_in_software_mode_masked_watchpoint (const struct breakpoint *b) +{ + return 0; +} + +/* Implement the "print_it" breakpoint_ops method for + masked hardware watchpoints. */ + +static enum print_stop_action +print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val) +{ + struct ui_stream *stb; + struct cleanup *old_chain; + + stb = ui_out_stream_new (uiout); + old_chain = make_cleanup_ui_out_stream_delete (stb); + + switch (b->type) + { + case bp_hardware_watchpoint: + annotate_watchpoint (b->number); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER)); + break; + + case bp_read_watchpoint: + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER)); + break; + + case bp_access_watchpoint: + if (old_val != NULL) + { + annotate_watchpoint (b->number); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); + } + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid hardware watchpoint type.")); + } + + mention (b); + ui_out_text (uiout, "\nCheck the underlying instruction \ +at PC for address and value related to this watchpoint trigger.\n"); + ui_out_text (uiout, "\n"); + + do_cleanups (old_chain); + + /* More than one watchpoint may have been triggered. */ + return PRINT_UNKNOWN; +} + +/* Implement the "print_one_detail" breakpoint_ops method for + masked hardware watchpoints. */ + +static void +print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout) +{ + ui_out_text (uiout, "\tmask "); + + /* I don't know whether it's possible to get here without a b->loc, + but we can handle the situation. */ + if (b->loc) + ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask); + else + ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask)); + + ui_out_text (uiout, "\n"); +} + +/* Implement the "print_mention" breakpoint_ops method for + masked hardware watchpoints. */ + +static void +print_mention_masked_watchpoint (struct breakpoint *b) +{ + struct cleanup *ui_out_chain; + + switch (b->type) + { + case bp_hardware_watchpoint: + ui_out_text (uiout, "Masked hardware watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); + break; + case bp_read_watchpoint: + ui_out_text (uiout, "Masked hardware read watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt"); + break; + case bp_access_watchpoint: + ui_out_text (uiout, "Masked hardware access (read/write) watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt"); + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid hardware watchpoint type.")); + } + + ui_out_field_int (uiout, "number", b->number); + ui_out_text (uiout, ": "); + ui_out_field_string (uiout, "exp", b->exp_string); + do_cleanups (ui_out_chain); +} + +static void +print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp) +{ + char tmp[40]; + + switch (b->type) + { + case bp_hardware_watchpoint: + fprintf_unfiltered (fp, "watch"); + break; + case bp_read_watchpoint: + fprintf_unfiltered (fp, "rwatch"); + break; + case bp_access_watchpoint: + fprintf_unfiltered (fp, "awatch"); + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid hardware watchpoint type.")); + } + + sprintf_vma (tmp, b->hw_wp_mask); + fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp); +} + +/* The breakpoint_ops structure to be used in masked hardware watchpoints. */ + +static struct breakpoint_ops masked_watchpoint_breakpoint_ops = +{ + insert_masked_watchpoint, + remove_masked_watchpoint, + NULL, /* breakpoint_hit */ + extra_resources_needed_masked_watchpoint, + works_in_software_mode_masked_watchpoint, + print_it_masked_watchpoint, + NULL, /* print_one */ + print_one_detail_masked_watchpoint, + print_mention_masked_watchpoint, + print_recreate_masked_watchpoint +}; + +/* Tells whether the given watchpoint is a masked hardware watchpoint. */ + +static int +is_masked_watchpoint (const struct breakpoint *b) +{ + return b->ops == &masked_watchpoint_breakpoint_ops; +} + /* accessflag: hw_write: watch write, hw_read: watch read, hw_access: watch access (read or write) */ @@ -8050,8 +8460,8 @@ watch_command_1 (char *arg, int accessfl struct frame_info *frame; char *exp_start = NULL; char *exp_end = NULL; - char *tok, *id_tok_start, *end_tok; - int toklen; + char *tok, *end_tok; + int toklen = -1; char *cond_start = NULL; char *cond_end = NULL; int i, other_type_used, target_resources_ok = 0; @@ -8059,66 +8469,98 @@ watch_command_1 (char *arg, int accessfl int mem_cnt = 0; int thread = -1; int pc = 0; + /* Flag to indicate whether we are going to use masks for + the hardware watchpoint. */ + int use_mask = 0; + CORE_ADDR hw_wp_mask = 0; + /* Whether we are watching an array or struct and hence we will + try to use ranged hardware watchpoints, if available. */ + int use_ranged = 0; /* Make sure that we actually have parameters to parse. */ if (arg != NULL && arg[0] != '\0') { - toklen = strlen (arg); /* Size of argument list. */ + char *value_start; - /* Points tok to the end of the argument list. */ - tok = arg + toklen - 1; + /* Look for "parameter value" pairs at the end + of the arguments string. */ + for (tok = arg + strlen (arg) - 1; tok > arg; tok--) + { + /* Skip whitespace at the end of the argument list. */ + while (tok > arg && (*tok == ' ' || *tok == '\t')) + tok--; + + /* Find the beginning of the last token. + This is the value of the parameter. */ + while (tok > arg && (*tok != ' ' && *tok != '\t')) + tok--; + value_start = tok + 1; + + /* Skip whitespace. */ + while (tok > arg && (*tok == ' ' || *tok == '\t')) + tok--; + + end_tok = tok; + + /* Find the beginning of the second to last token. + This is the parameter itself. */ + while (tok > arg && (*tok != ' ' && *tok != '\t')) + tok--; + tok++; + toklen = end_tok - tok + 1; + + if (toklen == 6 && !strncmp (tok, "thread", 6)) + { + /* At this point we've found a "thread" token, which means + the user is trying to set a watchpoint that triggers + only in a specific thread. */ + char *endp; + + if (thread != -1) + error(_("You can specify only one thread.")); + + /* Extract the thread ID from the next token. */ + thread = strtol (value_start, &endp, 0); + + /* Check if the user provided a valid numeric value for the + thread ID. */ + if (*endp != ' ' && *endp != '\t' && *endp != '\0') + error (_("Invalid thread ID specification %s."), value_start); + + /* Check if the thread actually exists. */ + if (!valid_thread_id (thread)) + error (_("Unknown thread %d."), thread); + } + else if (toklen == 4 && !strncmp (tok, "mask", 4)) + { + /* We've found a "mask" token, which means the user wants to + create a hardware watchpoint that is going to have the mask + facility. */ + struct value *mask_value, *mark; - /* Go backwards in the parameters list. Skip the last parameter. - If we're expecting a 'thread ' parameter, this should - be the thread identifier. */ - while (tok > arg && (*tok == ' ' || *tok == '\t')) - tok--; - while (tok > arg && (*tok != ' ' && *tok != '\t')) - tok--; - - /* Points end_tok to the beginning of the last token. */ - id_tok_start = tok + 1; - - /* Go backwards in the parameters list. Skip one more parameter. - If we're expecting a 'thread ' parameter, we should - reach a "thread" token. */ - while (tok > arg && (*tok == ' ' || *tok == '\t')) - tok--; + /* Does the target support masked watchpoints? */ + if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH)) + error (_("\ +This target does not support the usage of masks with hardware watchpoints.")); - end_tok = tok; + if (use_mask) + error(_("You can specify only one mask.")); - while (tok > arg && (*tok != ' ' && *tok != '\t')) - tok--; + use_mask = 1; - /* Move the pointer forward to skip the whitespace and - calculate the length of the token. */ - tok++; - toklen = end_tok - tok; + mark = value_mark (); + mask_value = parse_to_comma_and_eval (&value_start); + hw_wp_mask = value_as_address (mask_value); + value_free_to_mark (mark); + } + else + /* We didn't recognize what we found. We should stop here. */ + break; - if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0) - { - /* At this point we've found a "thread" token, which means - the user is trying to set a watchpoint that triggers - only in a specific thread. */ - char *endp; - - /* Extract the thread ID from the next token. */ - thread = strtol (id_tok_start, &endp, 0); - - /* Check if the user provided a valid numeric value for the - thread ID. */ - if (*endp != ' ' && *endp != '\t' && *endp != '\0') - error (_("Invalid thread ID specification %s."), id_tok_start); - - /* Check if the thread actually exists. */ - if (!valid_thread_id (thread)) - error (_("Unknown thread %d."), thread); - - /* Truncate the string and get rid of the thread - parameter before the parameter list is parsed by the - evaluate_expression() function. */ - *tok = '\0'; - } + /* Truncate the string and get rid of the "parameter value" pair before + the arguments string is parsed by the parse_exp_1 function. */ + *tok = '\0'; + } } /* Parse the rest of the arguments. */ @@ -8196,6 +8638,22 @@ watch_command_1 (char *arg, int accessfl error (_("Expression cannot be implemented with read/access watchpoint.")); if (mem_cnt != 0) { + struct type *vtype = check_typedef (value_type (val)); + + /* If we are going to use masks, then we may need more + slots in order to use the hardware watchpoint. */ + if (use_mask) + mem_cnt += target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH); + /* If we are watching an array or struct, we may be able to do it using + a ranged watchpoint. */ + else if ((TYPE_CODE (vtype) == TYPE_CODE_STRUCT + || TYPE_CODE (vtype) == TYPE_CODE_ARRAY) + && target_can_use_special_hw_point (HW_POINT_RANGED_WATCH)) + { + use_ranged = 1; + mem_cnt += target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH); + } + i = hw_watchpoint_used_count (bp_type, &other_type_used); target_resources_ok = target_can_use_hardware_watchpoint (bp_type, i + mem_cnt, @@ -8207,10 +8665,22 @@ watch_command_1 (char *arg, int accessfl error (_("Target can only support one kind of HW watchpoint at a time.")); } - /* Change the type of breakpoint to an ordinary watchpoint if a hardware - watchpoint could not be set. */ if (!mem_cnt || target_resources_ok <= 0) - bp_type = bp_watchpoint; + { + if (use_mask && !mem_cnt) + error (_("Cannot use masks with the given expression.")); + else if (use_mask && target_resources_ok <= 0) + error (_("\ +Cannot use masks without enough available hardware watchpoints (need %d)."), + mem_cnt); + else + { + /* Change the type of breakpoint to an ordinary watchpoint if a + hardware watchpoint could not be set. */ + bp_type = bp_watchpoint; + use_ranged = 0; + } + } frame = block_innermost_frame (exp_valid_block); @@ -8279,7 +8749,16 @@ watch_command_1 (char *arg, int accessfl b->exp_string = savestring (exp_start, exp_end - exp_start); b->val = val; b->val_valid = 1; - b->ops = &watchpoint_breakpoint_ops; + + if (use_mask) + { + b->hw_wp_mask = hw_wp_mask; + b->ops = &masked_watchpoint_breakpoint_ops; + } + else if (use_ranged) + b->ops = &ranged_watchpoint_breakpoint_ops; + else + b->ops = &watchpoint_breakpoint_ops; if (cond_start) b->cond_string = savestring (cond_start, cond_end - cond_start); @@ -8466,6 +8945,92 @@ awatch_command (char *arg, int from_tty) { watch_maybe_just_location (arg, hw_access, from_tty); } + +static void +watch_range_command_1 (char *arg, enum bptype type, int from_tty) +{ + char *exp_string, *string_p; + struct gdbarch *gdbarch = get_current_arch (); + int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0; + CORE_ADDR start_addr; + ULONGEST length; + struct breakpoint *b; + struct expression *exp; + struct symtab_and_line sal; + struct value *val; + struct cleanup *cleanups; + + /* Do we support ranged hardware watchpoints? */ + if (!target_can_use_special_hw_point (HW_POINT_RANGED_WATCH)) + error (_("This target does not support ranged hardware watchpoints.")); + /* Did the user specifically forbid us to use hardware watchpoints? */ + else if (!can_use_hw_watchpoints) + error (_("\ +Hardware watchpoints are disabled (see \"set can-use-hw-watchpoints\").")); + + parse_addr_range (&arg, &start_addr, &length); + + /* We need spaces around the brackets in the expression below so that + print_it_recreate_ranged_watchpoint can use scanf on it. */ + exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length), + paddress (gdbarch, start_addr)); + exp = parse_exp_1 (&string_p, 0, 0); + fetch_subexp_value (exp, &pc, &val, NULL, NULL); + if (val != NULL) + release_value (val); + cleanups = make_cleanup (xfree, exp_string); + + mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1; + + wp_count = hw_watchpoint_used_count (type, &other_type_used); + can_use_wp = target_can_use_hardware_watchpoint (type, wp_count + mem_cnt, + other_type_used); + if (can_use_wp < 0) + error (_("Not enough available hardware watchpoints (need %d)."), mem_cnt); + + init_sal (&sal); /* initialize to zeroes */ + sal.pspace = current_program_space; + + /* Now set up the breakpoint. */ + b = set_raw_breakpoint (gdbarch, sal, type); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->thread = -1; + b->disposition = disp_donttouch; + b->exp = exp; + b->exp_string_reparse = exp_string; + b->exp_string = xstrprintf (_("range [%s, %s]"), + paddress (gdbarch, start_addr), + paddress (gdbarch, start_addr + length - 1)); + b->ops = &ranged_watchpoint_breakpoint_ops; + b->val = val; + b->val_valid = 1; + b->watchpoint_frame = null_frame_id; + + mention (b); + update_global_location_list (1); + + discard_cleanups (cleanups); +} + +static void +watch_range_command (char *arg, int from_tty) +{ + watch_range_command_1 (arg, bp_hardware_watchpoint, from_tty); +} + +static void +awatch_range_command (char *arg, int from_tty) +{ + watch_range_command_1 (arg, bp_access_watchpoint, from_tty); +} + +static void +rwatch_range_command (char *arg, int from_tty) +{ + watch_range_command_1 (arg, bp_read_watchpoint, from_tty); +} + /* Helper routines for the until_command routine in infcmd.c. Here @@ -8703,7 +9268,8 @@ catch_exec_command_1 (char *arg, int fro } static enum print_stop_action -print_exception_catchpoint (struct breakpoint *b) +print_it_exception_catchpoint (struct breakpoint *b, + const struct value *old_val) { int bp_temp, bp_throw; @@ -8792,8 +9358,11 @@ static struct breakpoint_ops gnu_v3_exce NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ - print_exception_catchpoint, + NULL, /* extra_resources_needed */ + NULL, /* works_in_software_mode */ + print_it_exception_catchpoint, print_one_exception_catchpoint, + NULL, /* print_one_detail */ print_mention_exception_catchpoint, print_recreate_exception_catchpoint }; @@ -12183,7 +12752,41 @@ inferior in all-stop mode, gdb behaves a &show_always_inserted_mode, &breakpoint_set_cmdlist, &breakpoint_show_cmdlist); - + + c = add_com ("watch-range", class_breakpoint, watch_range_command, _("\ +Set a hardware watchpoint for an address range.\n\ +The address range should be specified in one of the following formats:\n\ +\n\ + start-address, end-address\n\ + start-address, +length\n\ +\n\ +The watchpoint will stop execution of your program whenever the inferior\n\ +writes to any address within the [start-address, end-address] interval.")); + set_cmd_completer (c, expression_completer); + + c = add_com ("awatch-range", class_breakpoint, awatch_range_command, _("\ +Set an access hardware watchpoint for an address range.\n\ +The address range should be specified in one of the following formats:\n\ +\n\ + start-address, end-address\n\ + start-address, +length\n\ +\n\ +The watchpoint will stop execution of your program whenever the inferior\n\ +accesses (reads from or writes to) any address within the\n\ +[start-address, end-address] interval.")); + set_cmd_completer (c, expression_completer); + + c = add_com ("rwatch-range", class_breakpoint, rwatch_range_command, _("\ +Set a read hardware watchpoint for an address range.\n\ +The address range should be specified in one of the following formats:\n\ +\n\ + start-address, end-address\n\ + start-address, +length\n\ +\n\ +The watchpoint will stop execution of your program whenever the inferior\n\ +reads from any address within the [start-address, end-address] interval.")); + set_cmd_completer (c, expression_completer); + automatic_hardware_breakpoints = 1; observer_attach_about_to_proceed (breakpoint_about_to_proceed); Index: gdb.git/gdb/breakpoint.h =================================================================== --- gdb.git.orig/gdb/breakpoint.h 2010-10-22 18:41:34.000000000 -0200 +++ gdb.git/gdb/breakpoint.h 2010-10-22 18:41:37.000000000 -0200 @@ -26,6 +26,7 @@ struct value; struct block; +struct ui_out; /* This is the maximum number of bytes a breakpoint instruction can take. Feel free to increase it. It's just used in a few places to size @@ -361,13 +362,28 @@ struct breakpoint_ops breakpoint was hit. */ int (*breakpoint_hit) (struct breakpoint *); + /* Tell how many additional hardware resources (debug registers) are needed + for this breakpoint. We always count at least one resource. If this + element is NULL, then no additional resource is accounted for. */ + int (*extra_resources_needed) (const struct breakpoint *); + + /* Tell whether we can downgrade from a hardware watchpoint to a software + one. If not, the user will not be able to enable the watchpoint when + there are not enough hardware resources available. */ + int (*works_in_software_mode) (const struct breakpoint *); + /* The normal print routine for this breakpoint, called when we hit it. */ - enum print_stop_action (*print_it) (struct breakpoint *); + enum print_stop_action (*print_it) (struct breakpoint *, + const struct value *old_val); /* Display information about this breakpoint, for "info breakpoints". */ void (*print_one) (struct breakpoint *, struct bp_location **); + /* Display one line of extra information about this breakpoint, + for "info breakpoints". */ + void (*print_one_detail) (const struct breakpoint *, struct ui_out *); + /* Display information about this breakpoint after setting it (roughly speaking; this is called from "mention"). */ void (*print_mention) (struct breakpoint *); @@ -400,6 +416,12 @@ DEF_VEC_P(bp_location_p); detail to the breakpoints module. */ struct counted_command_line; +/* Special types of hardware breakpoints/watchpoints. */ +enum hw_point_flag { + HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint. */ + HW_POINT_MASKED_WATCH /* Hardware masked watchpoint. */ +}; + /* Note that the ->silent field is not currently used by any commands (though the code is in there if it was to be, and set_raw_breakpoint does set it to 0). I implemented it because I thought it would be @@ -559,6 +581,9 @@ struct breakpoint breakpoints, we will use this index to try to find the same marker again. */ int static_trace_marker_id_idx; + + /* The mask address for a hardware watchpoint. */ + CORE_ADDR hw_wp_mask; }; typedef struct breakpoint *breakpoint_p; Index: gdb.git/gdb/doc/gdb.texinfo =================================================================== --- gdb.git.orig/gdb/doc/gdb.texinfo 2010-10-19 21:04:59.000000000 -0200 +++ gdb.git/gdb/doc/gdb.texinfo 2010-10-22 18:41:37.000000000 -0200 @@ -3711,7 +3711,7 @@ watchpoints, which do not slow down the @table @code @kindex watch -@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} +@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]} Set a watchpoint for an expression. @value{GDBN} will break when the expression @var{expr} is written into by the program and its value changes. The simplest (and the most popular) use of this command is @@ -3728,6 +3728,11 @@ change the value of @var{expr}, @value{G that watchpoints restricted to a single thread in this way only work with Hardware Watchpoints. +The @code{@r{[}mask @var{maskvalue}@r{]}} clause is used to create a masked +watchpoint if the current architecture supports the feature (currently, +only available in the PowerPC Embedded architecture. +See @ref{PowerPC Embedded}). + Ordinarily a watchpoint respects the scope of variables in @var{expr} (see below). The @code{-location} argument tells @value{GDBN} to instead watch the memory referred to by @var{expr}. In this case, @@ -3738,12 +3743,12 @@ result does not have an address, then @v error. @kindex rwatch -@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} +@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]} Set a watchpoint that will break when the value of @var{expr} is read by the program. @kindex awatch -@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} +@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]} Set a watchpoint that will break when @var{expr} is either read from or written into by the program. @@ -18517,9 +18522,41 @@ The DVC register will be automatically u such pattern in a condition expression. This feature is available in native @value{GDBN} running on a Linux kernel version 2.6.34 or newer. +PowerPC embedded processors support additional types of hardware watchpoints, +namely masked watchpoints and ranged watchpoints. + +A @dfn{masked watchpoint} is defined by an address and a mask. It triggers +when the address of a memory access matches the watchpoint address when both +are masked by the watchpoint mask. That is, the bits set in the mask determine +which bits are relevant in the address comparison. To set a masked watchpoint +in @value{GDBN}, use the @code{mask} parameter in the @code{watch} command +(see @ref{Set Watchpoints}), as in: + +@smallexample +(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00 +@end smallexample + +A @dfn{ranged watchpoint} is defined by a start address and an end address +specifying a region of memory inside which any access will trigger the +watchpoint. Both the start and end addresses are within the memory region. +To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command. + @value{GDBN} provides the following PowerPC-specific commands: @table @code +@kindex watch-range +@item watch-range @var{start-address, +length} +@itemx watch-range @var{start-address, end-address} +@item rwatch-range @var{start-address, +length} +@itemx rwatch-range @var{start-address, end-address} +@item awatch-range @var{start-address, +length} +@itemx awatch-range @var{start-address, end-address} +Set a hardware watchpoint for an address range. +The watchpoint will stop execution of your program whenever the inferior +writes, reads, or accesses (respectively for watch-range, awatch-range +and rwatch-range) any address within the @code{[start-address, end-address]} +interval. + @kindex set powerpc @item set powerpc soft-float @itemx show powerpc soft-float Index: gdb.git/gdb/findcmd.c =================================================================== --- gdb.git.orig/gdb/findcmd.c 2010-08-20 16:00:16.000000000 -0300 +++ gdb.git/gdb/findcmd.c 2010-10-22 18:41:37.000000000 -0200 @@ -45,6 +45,79 @@ put_bits (bfd_uint64_t data, char *buf, } } +/* Reads an address range, in one of the following formats: + + start-address, end-address + start-address, +length + + ARGS will be set to the first character after the end-address or length, + or if that character is a comma, the character following it. If a parser + error occurs, an exception is thrown and none of the arguments is + touched. Returns 1 on success, or 0 if an empty address range was given. */ + +int +parse_addr_range (char **args, CORE_ADDR *start_addrp, + ULONGEST *search_space_lenp) +{ + char *s = *args; + CORE_ADDR start_addr; + ULONGEST search_space_len; + struct value *v; + + v = parse_to_comma_and_eval (&s); + start_addr = value_as_address (v); + + if (*s == ',') + ++s; + while (isspace (*s)) + ++s; + + if (*s == '+') + { + LONGEST len; + + ++s; + v = parse_to_comma_and_eval (&s); + len = value_as_long (v); + if (len == 0) + { + printf_filtered (_("Empty search range.\n")); + return 0; + } + if (len < 0) + error (_("Invalid length.")); + /* Watch for overflows. */ + if (len > CORE_ADDR_MAX + || (start_addr + len - 1) < start_addr) + error (_("Search space too large.")); + search_space_len = len; + } + else + { + CORE_ADDR end_addr; + + v = parse_to_comma_and_eval (&s); + end_addr = value_as_address (v); + if (start_addr > end_addr) + error (_("Invalid search space, end preceeds start.")); + search_space_len = end_addr - start_addr + 1; + /* We don't support searching all of memory + (i.e. start=0, end = 0xff..ff). + Bail to avoid overflows later on. */ + if (search_space_len == 0) + error (_("Overflow in address range computation, choose smaller range.")); + } + + if (*s == ',') + ++s; + + *args = s; + *start_addrp = start_addr; + *search_space_lenp = search_space_len; + + return 1; +} + /* Subroutine of find_command to simplify it. Parse the arguments of the "find" command. */ @@ -114,53 +187,8 @@ parse_find_args (char *args, ULONGEST *m } /* Get the search range. */ - - v = parse_to_comma_and_eval (&s); - start_addr = value_as_address (v); - - if (*s == ',') - ++s; - while (isspace (*s)) - ++s; - - if (*s == '+') - { - LONGEST len; - - ++s; - v = parse_to_comma_and_eval (&s); - len = value_as_long (v); - if (len == 0) - { - printf_filtered (_("Empty search range.\n")); - return; - } - if (len < 0) - error (_("Invalid length.")); - /* Watch for overflows. */ - if (len > CORE_ADDR_MAX - || (start_addr + len - 1) < start_addr) - error (_("Search space too large.")); - search_space_len = len; - } - else - { - CORE_ADDR end_addr; - - v = parse_to_comma_and_eval (&s); - end_addr = value_as_address (v); - if (start_addr > end_addr) - error (_("Invalid search space, end preceeds start.")); - search_space_len = end_addr - start_addr + 1; - /* We don't support searching all of memory - (i.e. start=0, end = 0xff..ff). - Bail to avoid overflows later on. */ - if (search_space_len == 0) - error (_("Overflow in address range computation, choose smaller range.")); - } - - if (*s == ',') - ++s; + if (!parse_addr_range (&s, &start_addr, &search_space_len)) + return; /* Fetch the search string. */ Index: gdb.git/gdb/ppc-linux-nat.c =================================================================== --- gdb.git.orig/gdb/ppc-linux-nat.c 2010-08-20 16:00:16.000000000 -0300 +++ gdb.git/gdb/ppc-linux-nat.c 2010-10-22 18:41:37.000000000 -0200 @@ -1478,6 +1478,28 @@ ppc_linux_can_use_hw_breakpoint (int typ } static int +ppc_linux_can_use_special_hw_point (enum hw_point_flag flag) +{ + uint64_t features; + + if (!have_ptrace_booke_interface ()) + return 0; + + features = booke_debug_info.features; + + switch (flag) + { + case HW_POINT_RANGED_WATCH: + return features & PPC_DEBUG_FEATURE_DATA_BP_RANGE; + case HW_POINT_MASKED_WATCH: + return features & PPC_DEBUG_FEATURE_DATA_BP_MASK; + default: + internal_error (__FILE__, __LINE__, + _("Unknown hardware breakpoint/watchpoint type.")); + } +} + +static int ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) { /* Handle sub-8-byte quantities. */ @@ -1489,9 +1511,15 @@ ppc_linux_region_ok_for_hw_watchpoint (C to determine the hardcoded watchable region for watchpoints. */ if (have_ptrace_booke_interface ()) { - if (booke_debug_info.data_bp_alignment - && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1)) - + booke_debug_info.data_bp_alignment)) + /* DAC-based processors (i.e., embedded processors), like the PowerPC 440 + have ranged watchpoints and can watch any access within an arbitrary + memory region. This is useful to watch arrays and structs, for + instance. It takes two hardware watchpoints though. */ + if (ppc_linux_can_use_special_hw_point (HW_POINT_RANGED_WATCH)) + return 1; + else if (booke_debug_info.data_bp_alignment + && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1)) + + booke_debug_info.data_bp_alignment)) return 0; } /* addr+len must fall in the 8 byte watchable region for DABR-based @@ -1685,6 +1713,106 @@ get_trigger_type (int rw) return t; } +static int +ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw) +{ + ptid_t ptid; + struct lwp_info *lp; + struct ppc_hw_breakpoint p; + + gdb_assert (have_ptrace_booke_interface ()); + + if ((mask & 0xC0000000) != 0xC0000000) + error (_("\ +The given mask covers kernel address space and cannot be used.\n\ +You have to delete the masked watchpoint to continue the debugging session.")); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = get_trigger_type (rw); + p.addr_mode = PPC_BREAKPOINT_MODE_MASK; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) addr; + p.addr2 = (uint64_t) mask; + p.condition_value = 0; + + ALL_LWPS (lp, ptid) + booke_insert_point (&p, TIDGET (ptid)); + + return 0; +} + +static int +ppc_linux_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw) +{ + ptid_t ptid; + struct lwp_info *lp; + struct ppc_hw_breakpoint p; + + gdb_assert (have_ptrace_booke_interface ()); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = get_trigger_type (rw); + p.addr_mode = PPC_BREAKPOINT_MODE_MASK; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) addr; + p.addr2 = (uint64_t) mask; + p.condition_value = 0; + + ALL_LWPS (lp, ptid) + booke_remove_point (&p, TIDGET (ptid)); + + return 0; +} + +static int +ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw) +{ + ptid_t ptid; + struct lwp_info *lp; + struct ppc_hw_breakpoint p; + + gdb_assert (have_ptrace_booke_interface ()); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = get_trigger_type (rw); + p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.condition_value = 0; + + /* The watchpoint will trigger if the address of the memory access is + within the defined range, as follows: p.addr <= address < p.addr2. */ + p.addr = (uint64_t) addr; + p.addr2 = (uint64_t) addr + len; + + ALL_LWPS (lp, ptid) + booke_insert_point (&p, TIDGET (ptid)); + + return 0; +} + +static int +ppc_linux_remove_ranged_watchpoint (CORE_ADDR addr, int len, int rw) +{ + ptid_t ptid; + struct lwp_info *lp; + struct ppc_hw_breakpoint p; + + gdb_assert (have_ptrace_booke_interface ()); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = get_trigger_type (rw); + p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) addr; + p.addr2 = (uint64_t) addr + len; + p.condition_value = 0; + + ALL_LWPS (lp, ptid) + booke_remove_point (&p, TIDGET (ptid)); + + return 0; +} + /* Check whether we have at least one free DVC register. */ static int can_use_watchpoint_cond_accel (void) @@ -2136,6 +2264,14 @@ ppc_linux_watchpoint_addr_within_range ( return start <= addr + mask && start + length - 1 >= addr; } +static int +ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag) +{ + gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH); + + return 1; +} + static void ppc_linux_store_inferior_registers (struct target_ops *ops, struct regcache *regcache, int regno) @@ -2347,12 +2483,18 @@ _initialize_ppc_linux_nat (void) t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint; t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint; t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint; + t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point; t->to_insert_watchpoint = ppc_linux_insert_watchpoint; t->to_remove_watchpoint = ppc_linux_remove_watchpoint; + t->to_insert_ranged_watchpoint = ppc_linux_insert_ranged_watchpoint; + t->to_remove_ranged_watchpoint = ppc_linux_remove_ranged_watchpoint; + t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint; + t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint; t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint; t->to_stopped_data_address = ppc_linux_stopped_data_address; t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range; t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition; + t->to_hw_point_extra_slot_count = ppc_linux_hw_point_extra_slot_count; t->to_read_description = ppc_linux_read_description; t->to_auxv_parse = ppc_linux_auxv_parse; Index: gdb.git/gdb/target.c =================================================================== --- gdb.git.orig/gdb/target.c 2010-10-22 18:41:34.000000000 -0200 +++ gdb.git/gdb/target.c 2010-10-22 18:41:37.000000000 -0200 @@ -601,11 +601,16 @@ update_current_target (void) INHERIT (to_files_info, t); INHERIT (to_insert_breakpoint, t); INHERIT (to_remove_breakpoint, t); + INHERIT (to_can_use_special_hw_point, t); INHERIT (to_can_use_hw_breakpoint, t); INHERIT (to_insert_hw_breakpoint, t); INHERIT (to_remove_hw_breakpoint, t); INHERIT (to_insert_watchpoint, t); INHERIT (to_remove_watchpoint, t); + INHERIT (to_insert_ranged_watchpoint, t); + INHERIT (to_remove_ranged_watchpoint, t); + INHERIT (to_insert_mask_watchpoint, t); + INHERIT (to_remove_mask_watchpoint, t); INHERIT (to_stopped_data_address, t); INHERIT (to_have_steppable_watchpoint, t); INHERIT (to_have_continuable_watchpoint, t); @@ -613,6 +618,7 @@ update_current_target (void) INHERIT (to_watchpoint_addr_within_range, t); INHERIT (to_region_ok_for_hw_watchpoint, t); INHERIT (to_can_accel_watchpoint_condition, t); + INHERIT (to_hw_point_extra_slot_count, t); INHERIT (to_terminal_init, t); INHERIT (to_terminal_inferior, t); INHERIT (to_terminal_ours_for_output, t); @@ -727,6 +733,9 @@ update_current_target (void) de_fault (to_can_use_hw_breakpoint, (int (*) (int, int, int)) return_zero); + de_fault (to_can_use_special_hw_point, + (int (*) (enum hw_point_flag)) + return_zero); de_fault (to_insert_hw_breakpoint, (int (*) (struct gdbarch *, struct bp_target_info *)) return_minus_one); @@ -739,6 +748,18 @@ update_current_target (void) de_fault (to_remove_watchpoint, (int (*) (CORE_ADDR, int, int, struct expression *)) return_minus_one); + de_fault (to_insert_ranged_watchpoint, + (int (*) (CORE_ADDR, int, int)) + return_minus_one); + de_fault (to_remove_ranged_watchpoint, + (int (*) (CORE_ADDR, int, int)) + return_minus_one); + de_fault (to_insert_mask_watchpoint, + (int (*) (CORE_ADDR, CORE_ADDR, int)) + return_minus_one); + de_fault (to_remove_mask_watchpoint, + (int (*) (CORE_ADDR, CORE_ADDR, int)) + return_minus_one); de_fault (to_stopped_by_watchpoint, (int (*) (void)) return_zero); @@ -752,6 +773,9 @@ update_current_target (void) de_fault (to_can_accel_watchpoint_condition, (int (*) (CORE_ADDR, int, int, struct expression *)) return_zero); + de_fault (to_hw_point_extra_slot_count, + (int (*) (enum hw_point_flag)) + return_zero); de_fault (to_terminal_init, (void (*) (void)) target_ignore); Index: gdb.git/gdb/target.h =================================================================== --- gdb.git.orig/gdb/target.h 2010-10-22 18:41:34.000000000 -0200 +++ gdb.git/gdb/target.h 2010-10-22 18:41:37.000000000 -0200 @@ -39,6 +39,8 @@ struct static_tracepoint_marker; struct expression; +enum hw_point_flag; + /* This include file defines the interface between the main part of the debugger, and the part which is target-specific, or specific to the communications interface between us and the @@ -438,6 +440,7 @@ struct target_ops int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *); int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *); int (*to_can_use_hw_breakpoint) (int, int, int); + int (*to_can_use_special_hw_point) (enum hw_point_flag); int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *); int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *); @@ -446,6 +449,10 @@ struct target_ops int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *); int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *); + int (*to_insert_ranged_watchpoint) (CORE_ADDR, int, int); + int (*to_remove_ranged_watchpoint) (CORE_ADDR, int, int); + int (*to_insert_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int); + int (*to_remove_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int); int (*to_stopped_by_watchpoint) (void); int to_have_steppable_watchpoint; int to_have_continuable_watchpoint; @@ -455,6 +462,7 @@ struct target_ops int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int); int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int, struct expression *); + int (*to_hw_point_extra_slot_count) (enum hw_point_flag); void (*to_terminal_init) (void); void (*to_terminal_inferior) (void); void (*to_terminal_ours_for_output) (void); @@ -1314,6 +1322,11 @@ extern char *normal_pid_to_str (ptid_t p #define target_region_ok_for_hw_watchpoint(addr, len) \ (*current_target.to_region_ok_for_hw_watchpoint) (addr, len) +/* Returns non-zero if the target supports the special type of hardware + breakpoint/watchpoint represented by FLAG. */ +#define target_can_use_special_hw_point(flag) \ + (*current_target.to_can_use_special_hw_point) (flag) + /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes. TYPE is 0 for write, 1 for read, and 2 for read/write accesses. @@ -1327,6 +1340,20 @@ extern char *normal_pid_to_str (ptid_t p #define target_remove_watchpoint(addr, len, type, cond) \ (*current_target.to_remove_watchpoint) (addr, len, type, cond) +/* Hardware ranged watchpoints. */ +#define target_insert_ranged_watchpoint(addr, len, type) \ + (*current_target.to_insert_ranged_watchpoint) (addr, len, type) + +#define target_remove_ranged_watchpoint(addr, len, type) \ + (*current_target.to_remove_ranged_watchpoint) (addr, len, type) + +/* Hardware watchpoints with an associated address mask. */ +#define target_insert_mask_watchpoint(addr, mask, type) \ + (*current_target.to_insert_mask_watchpoint) (addr, mask, type) + +#define target_remove_mask_watchpoint(addr, mask, type) \ + (*current_target.to_remove_mask_watchpoint) (addr, mask, type) + #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \ (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt) @@ -1355,6 +1382,9 @@ extern char *normal_pid_to_str (ptid_t p #define target_can_accel_watchpoint_condition(addr, len, type, cond) \ (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond) +#define target_hw_point_extra_slot_count(flag) \ + (*current_target.to_hw_point_extra_slot_count) (flag) + /* Target can execute in reverse? */ #define target_can_execute_reverse \ (current_target.to_can_execute_reverse ? \ Index: gdb.git/gdb/ui-out.c =================================================================== --- gdb.git.orig/gdb/ui-out.c 2010-08-20 16:00:16.000000000 -0300 +++ gdb.git/gdb/ui-out.c 2010-10-22 18:41:37.000000000 -0200 @@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uio } void +ui_out_field_range_core_addr (struct ui_out *uiout, + const char *fldname, + struct gdbarch *gdbarch, + CORE_ADDR address_start, + CORE_ADDR length) +{ + char addstr[80]; + int addr_bit = gdbarch_addr_bit (gdbarch); + CORE_ADDR address_end = address_start + length - 1; + + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + { + address_start &= ((CORE_ADDR) 1 << addr_bit) - 1; + address_end &= ((CORE_ADDR) 1 << addr_bit) - 1; + } + + /* FIXME: cagney/2002-05-03: Need local_address_string() function + that returns the language localized string formatted to a width + based on gdbarch_addr_bit. */ + if (addr_bit <= 32) + { + strcpy (addstr, "["); + strcat (addstr, hex_string_custom (address_start, 8)); + strcat (addstr, ", "); + strcat (addstr, hex_string_custom (address_end, 8)); + strcat (addstr, "]"); + } + else + { + strcpy (addstr, "["); + strcat (addstr, hex_string_custom (address_start, 16)); + strcat (addstr, ", "); + strcat (addstr, hex_string_custom (address_end, 16)); + strcat (addstr, "]"); + } + + ui_out_field_string (uiout, fldname, addstr); +} + +void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname, struct gdbarch *gdbarch, Index: gdb.git/gdb/ui-out.h =================================================================== --- gdb.git.orig/gdb/ui-out.h 2010-08-20 16:00:16.000000000 -0300 +++ gdb.git/gdb/ui-out.h 2010-10-22 18:41:37.000000000 -0200 @@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct enum ui_align align, const char *fldname, int value); +extern void ui_out_field_range_core_addr (struct ui_out *uiout, + const char *fldname, + struct gdbarch *gdbarch, + CORE_ADDR address_start, + CORE_ADDR length); + extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname, struct gdbarch *gdbarch, CORE_ADDR address); Index: gdb.git/gdb/value.h =================================================================== --- gdb.git.orig/gdb/value.h 2010-10-19 21:05:00.000000000 -0200 +++ gdb.git/gdb/value.h 2010-10-22 18:41:37.000000000 -0200 @@ -559,6 +559,9 @@ extern CORE_ADDR parse_and_eval_address_ extern LONGEST parse_and_eval_long (char *exp); +int parse_addr_range (char **args, CORE_ADDR *start_addrp, + ULONGEST *search_space_lenp); + extern void unop_promote (const struct language_defn *language, struct gdbarch *gdbarch, struct value **arg1);