From patchwork Fri Jan 6 16:41:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Machado X-Patchwork-Id: 18812 Received: (qmail 114825 invoked by alias); 6 Jan 2017 16:42:10 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 114794 invoked by uid 89); 6 Jan 2017 16:42:07 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, SPF_PASS, URIBL_RED autolearn=ham version=3.3.2 spammy=sectors, baton X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 06 Jan 2017 16:41:56 +0000 Received: from svr-orw-fem-02x.mgc.mentorg.com ([147.34.96.206] helo=SVR-ORW-FEM-02.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1cPXaV-000594-Cb from Luis_Gustavo@mentor.com for gdb-patches@sourceware.org; Fri, 06 Jan 2017 08:41:55 -0800 Received: from Opsys.world.mentorg.com (147.34.91.1) by svr-orw-fem-02.mgc.mentorg.com (147.34.96.168) with Microsoft SMTP Server id 14.3.224.2; Fri, 6 Jan 2017 08:41:54 -0800 From: Luis Machado To: Subject: [PATCH] Add -verify option to load command Date: Fri, 6 Jan 2017 10:41:52 -0600 Message-ID: <1483720912-6563-1-git-send-email-lgustavo@codesourcery.com> MIME-Version: 1.0 X-IsSubscribed: yes This is also a leftover bit from flash programming that can also be used by other targets as needed. GDB already has some minimal memory verification functionality. The following patch adds a new -verify parameter to the load command that forces GDB to verify all the memory written during the load operation. This is useful to make sure bare-metal targets have had the program and data loaded successfully. I wouldn't say this is too useful for hosted environments, but not harmful either. What do you think? gdb/doc/ChangeLog: 2017-01-05 Mike Wrighton Luis Machado gdb/doc/ * gdb.texinfo (load): Added verify flag to load command description. gdb/ChangeLog: 2017-01-05 Mike Wrighton Luis Machado * symfile.c (generic_load): Add -verify arg. (_initialize_symfile): Document new -verify option in the load command's help text. * target-memory.c (target_write_memory_blocks): Add verify parameter and handle it. * target.h (target_write_memory_blocks): Add verify argument and document it. --- gdb/doc/gdb.texinfo | 5 ++++- gdb/symfile.c | 35 ++++++++++++++++++++++++----------- gdb/target-memory.c | 20 +++++++++++++++++++- gdb/target.h | 5 ++++- 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 44ae068..39de23c 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -19592,7 +19592,7 @@ Show the current status of displaying communications between @table @code @kindex load @var{filename} -@item load @var{filename} +@item load @var{filename} [-verify] @anchor{load} Depending on what remote debugging facilities are configured into @value{GDBN}, the @code{load} command may be available. Where it exists, it @@ -19614,6 +19614,9 @@ specifies a fixed address. Depending on the remote side capabilities, @value{GDBN} may be able to load programs into flash memory. +The optional @code{-verify} argument enables verification of the data that was +loaded to the target's memory. + @code{load} does not repeat if you press @key{RET} again after using it. @end table diff --git a/gdb/symfile.c b/gdb/symfile.c index 0af1900..4fdde17 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -2080,6 +2080,8 @@ generic_load (const char *args, int from_tty) struct load_section_data cbdata; struct load_progress_data total_progress; struct ui_out *uiout = current_uiout; + int arg_idx; + int verify = 0; CORE_ADDR entry; char **argv; @@ -2099,19 +2101,30 @@ generic_load (const char *args, int from_tty) filename = tilde_expand (argv[0]); make_cleanup (xfree, filename); - if (argv[1] != NULL) + arg_idx = 1; + if (argv[arg_idx] != NULL) { const char *endptr; - cbdata.load_offset = strtoulst (argv[1], &endptr, 0); + if (strcmp (argv[arg_idx], "-verify") == 0) + { + verify = 1; + arg_idx++; + } + + if (argv[arg_idx] != NULL) + { + cbdata.load_offset = strtoul ((const char *) argv[arg_idx], + (char **) &endptr, 0); - /* If the last word was not a valid number then - treat it as a file name with spaces in. */ - if (argv[1] == endptr) - error (_("Invalid download offset:%s."), argv[1]); + /* If the last word was not a valid number then + treat it as a file name with spaces in. */ + if (argv[arg_idx] == endptr) + error (_("Invalid download offset:%s."), argv[arg_idx]); - if (argv[2] != NULL) - error (_("Too many parameters.")); + if (argv[arg_idx + 1] != NULL) + error (_("Too many parameters.")); + } } /* Open the file for loading. */ @@ -2140,7 +2153,7 @@ generic_load (const char *args, int from_tty) steady_clock::time_point start_time = steady_clock::now (); if (target_write_memory_blocks (cbdata.requests, flash_discard, - load_progress) != 0) + load_progress, verify) != 0) error (_("Load failed")); steady_clock::time_point end_time = steady_clock::now (); @@ -3952,8 +3965,8 @@ that lies within the boundaries of this symbol file in memory."), c = add_cmd ("load", class_files, load_command, _("\ Dynamically load FILE into the running program, and record its symbols\n\ for access from GDB.\n\ -A load offset may also be given.\n\ -Usage: load [FILE] [offset expression]"), &cmdlist); +A load offset and write verification option may also be given.\n\ +Usage: load [FILE] [-verify] [offset expression]"), &cmdlist); set_cmd_completer (c, filename_completer); add_prefix_cmd ("overlay", class_support, overlay_command, diff --git a/gdb/target-memory.c b/gdb/target-memory.c index 1c8faa8..615bab8 100644 --- a/gdb/target-memory.c +++ b/gdb/target-memory.c @@ -310,7 +310,8 @@ cleanup_write_requests_vector (void *p) int target_write_memory_blocks (VEC(memory_write_request_s) *requests, enum flash_preserve_mode preserve_flash_p, - void (*progress_cb) (ULONGEST, void *)) + void (*progress_cb) (ULONGEST, void *), + int verify) { struct cleanup *back_to = make_cleanup (null_cleanup, NULL); VEC(memory_write_request_s) *blocks = VEC_copy (memory_write_request_s, @@ -433,6 +434,23 @@ target_write_memory_blocks (VEC(memory_write_request_s) *requests, target_flash_done (); } + + /* Do we need to verify if the data was properly written to the target's + memory? */ + if (verify) + { + /* Go through all memory regions that GDB wrote to and verify the + contents. */ + for (i = 0; VEC_iterate (memory_write_request_s, blocks, i, r); ++i) + if (target_verify_memory (r->data, r->begin, r->end - r->begin) <= 0) + error ("Load verification failed for region starting at 0x%x", + (unsigned int) r->begin); + else + current_uiout->message ("Verified load, size 0x%x lma 0x%x\n", + (unsigned int) (r->end - r->begin), + (unsigned int) r->begin); + } + out: do_cleanups (back_to); diff --git a/gdb/target.h b/gdb/target.h index e239c2c..6fc89d4 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -1497,11 +1497,14 @@ enum flash_preserve_mode feedback to user. It will be called with the baton corresponding to the request currently being written. It may also be called with a NULL baton, when preserved flash sectors are being rewritten. + VERIFY is non-zero if verification should be performed for the data written + to the target's memory and zero if no verification should be performed. The function returns 0 on success, and error otherwise. */ int target_write_memory_blocks (VEC(memory_write_request_s) *requests, enum flash_preserve_mode preserve_flash_p, - void (*progress_cb) (ULONGEST, void *)); + void (*progress_cb) (ULONGEST, void *), + int verify); /* Print a line about the current target. */