@@ -4086,74 +4086,96 @@ COMMAND_HANDLER(riscv_set_mem_access)
40864086 return ERROR_OK ;
40874087}
40884088
4089- static int parse_ranges (struct list_head * ranges , const char * tcl_arg , const char * reg_type , unsigned int max_val )
4090- {
4091- char * args = strdup (tcl_arg );
4092- if (!args )
4093- return ERROR_FAIL ;
40944089
4095- /* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */
4096- char * arg = strtok (args , "," );
4097- while (arg ) {
4090+ static bool parse_csr_address (const char * reg_address_str , unsigned int * reg_addr )
4091+ {
4092+ * reg_addr = -1 ;
4093+ /* skip initial spaces */
4094+ while (isspace (reg_address_str [0 ]))
4095+ ++ reg_address_str ;
4096+ /* try to detect if string starts with 0x or 0X */
4097+ bool is_hex_address = strncmp (reg_address_str , "0x" , 2 ) == 0 ||
4098+ strncmp (reg_address_str , "0X" , 2 ) == 0 ;
4099+
4100+ unsigned int scanned_chars ;
4101+ if (is_hex_address ) {
4102+ reg_address_str += 2 ;
4103+ if (sscanf (reg_address_str , "%x%n" , reg_addr , & scanned_chars ) != 1 )
4104+ return false;
4105+ } else {
4106+ /* If we are here and register address string starts with zero, this is
4107+ * an indication that most likely user has an incorrect input because:
4108+ * - decimal numbers typically do not start with "0"
4109+ * - octals are not supported by our interface
4110+ * - hexadecimal numbers should have "0x" prefix
4111+ * Thus such input is rejected. */
4112+ if (reg_address_str [0 ] == '0' && strlen (reg_address_str ) > 1 )
4113+ return false;
4114+ if (sscanf (reg_address_str , "%u%n" , reg_addr , & scanned_chars ) != 1 )
4115+ return false;
4116+ }
4117+ return scanned_chars == strlen (reg_address_str );
4118+ }
4119+
4120+ static int parse_reg_ranges_impl (struct list_head * ranges , char * args ,
4121+ const char * reg_type , unsigned int max_val , char * * const name_buffer )
4122+ {
4123+ /* For backward compatibility, allow multiple parameters within one TCL
4124+ * argument, separated by ',' */
4125+ for (char * arg = strtok (args , "," ); arg ; arg = strtok (NULL , "," )) {
40984126 unsigned int low = 0 ;
40994127 unsigned int high = 0 ;
41004128 char * name = NULL ;
41014129
41024130 char * dash = strchr (arg , '-' );
41034131 char * equals = strchr (arg , '=' );
4104- unsigned int pos ;
41054132
41064133 if (!dash && !equals ) {
41074134 /* Expecting single register number. */
4108- if (sscanf (arg , "%u%n" , & low , & pos ) != 1 || pos != strlen ( arg )) {
4135+ if (! parse_csr_address (arg , & low )) {
41094136 LOG_ERROR ("Failed to parse single register number from '%s'." , arg );
4110- free (args );
41114137 return ERROR_COMMAND_SYNTAX_ERROR ;
41124138 }
41134139 } else if (dash && !equals ) {
41144140 /* Expecting register range - two numbers separated by a dash: ##-## */
4115- * dash = 0 ;
4116- dash ++ ;
4117- if (sscanf (arg , "%u%n" , & low , & pos ) != 1 || pos != strlen (arg )) {
4118- LOG_ERROR ("Failed to parse single register number from '%s'." , arg );
4119- free (args );
4141+ * dash = '\0' ;
4142+ if (!parse_csr_address (arg , & low )) {
4143+ LOG_ERROR ("Failed to parse '%s' - not a valid decimal or hexadecimal number." ,
4144+ arg );
41204145 return ERROR_COMMAND_SYNTAX_ERROR ;
41214146 }
4122- if (sscanf (dash , "%u%n" , & high , & pos ) != 1 || pos != strlen (dash )) {
4123- LOG_ERROR ("Failed to parse single register number from '%s'." , dash );
4124- free (args );
4147+ const char * high_num_in = dash + 1 ;
4148+ if (!parse_csr_address (high_num_in , & high )) {
4149+ LOG_ERROR ("Failed to parse '%s' - not a valid decimal or hexadecimal number." ,
4150+ high_num_in );
41254151 return ERROR_COMMAND_SYNTAX_ERROR ;
41264152 }
41274153 if (high < low ) {
41284154 LOG_ERROR ("Incorrect range encountered [%u, %u]." , low , high );
4129- free (args );
41304155 return ERROR_FAIL ;
41314156 }
41324157 } else if (!dash && equals ) {
41334158 /* Expecting single register number with textual name specified: ##=name */
4134- * equals = 0 ;
4135- equals ++ ;
4136- if (sscanf (arg , "%u%n" , & low , & pos ) != 1 || pos != strlen (arg )) {
4137- LOG_ERROR ("Failed to parse single register number from '%s'." , arg );
4138- free (args );
4159+ * equals = '\0' ;
4160+ if (!parse_csr_address (arg , & low )) {
4161+ LOG_ERROR ("Failed to parse '%s' - not a valid decimal or hexadecimal number." ,
4162+ arg );
41394163 return ERROR_COMMAND_SYNTAX_ERROR ;
41404164 }
41414165
4142- name = calloc (1 , strlen (equals ) + strlen (reg_type ) + 2 );
4166+ const char * const reg_name_in = equals + 1 ;
4167+ * name_buffer = calloc (1 , strlen (reg_name_in ) + strlen (reg_type ) + 2 );
4168+ name = * name_buffer ;
41434169 if (!name ) {
4144- LOG_ERROR ("Failed to allocate register name." );
4145- free (args );
4170+ LOG_ERROR ("Out of memory" );
41464171 return ERROR_FAIL ;
41474172 }
41484173
4149- /* Register prefix: "csr_" or "custom_" */
4150- strcpy (name , reg_type );
4151- name [strlen (reg_type )] = '_' ;
4152-
4153- if (sscanf (equals , "%[_a-zA-Z0-9]%n" , name + strlen (reg_type ) + 1 , & pos ) != 1 || pos != strlen (equals )) {
4154- LOG_ERROR ("Failed to parse register name from '%s'." , equals );
4155- free (args );
4156- free (name );
4174+ unsigned int scanned_chars ;
4175+ char * scan_dst = name + strlen (reg_type ) + 1 ;
4176+ if (sscanf (reg_name_in , "%[_a-zA-Z0-9]%n" , scan_dst , & scanned_chars ) != 1 ||
4177+ scanned_chars != strlen (reg_name_in )) {
4178+ LOG_ERROR ("Invalid characters in register name '%s'." , reg_name_in );
41574179 return ERROR_COMMAND_SYNTAX_ERROR ;
41584180 }
41594181 } else {
@@ -4165,9 +4187,8 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha
41654187 high = MAX (high , low );
41664188
41674189 if (high > max_val ) {
4168- LOG_ERROR ("Cannot expose %s register number %u, maximum allowed value is %u." , reg_type , high , max_val );
4169- free (name );
4170- free (args );
4190+ LOG_ERROR ("Cannot expose %s register number 0x%x, maximum allowed value is 0x%x." ,
4191+ reg_type , high , max_val );
41714192 return ERROR_FAIL ;
41724193 }
41734194
@@ -4185,32 +4206,42 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha
41854206
41864207 if (entry -> name && name && (strcasecmp (entry -> name , name ) == 0 )) {
41874208 LOG_ERROR ("Duplicate register name \"%s\" found." , name );
4188- free (name );
4189- free (args );
41904209 return ERROR_FAIL ;
41914210 }
41924211 }
41934212
41944213 range_list_t * range = calloc (1 , sizeof (range_list_t ));
41954214 if (!range ) {
4196- LOG_ERROR ("Failed to allocate range list." );
4197- free (name );
4198- free (args );
4215+ LOG_ERROR ("Out of memory" );
41994216 return ERROR_FAIL ;
42004217 }
42014218
42024219 range -> low = low ;
42034220 range -> high = high ;
42044221 range -> name = name ;
4222+ /* ownership over name_buffer contents is transferred to list item here */
4223+ * name_buffer = NULL ;
42054224 list_add (& range -> list , ranges );
4206-
4207- arg = strtok (NULL , "," );
42084225 }
42094226
4210- free (args );
42114227 return ERROR_OK ;
42124228}
42134229
4230+ static int parse_reg_ranges (struct list_head * ranges , const char * tcl_arg ,
4231+ const char * reg_type , unsigned int max_val )
4232+ {
4233+ char * args = strdup (tcl_arg );
4234+ if (!args ) {
4235+ LOG_ERROR ("Out of memory" );
4236+ return ERROR_FAIL ;
4237+ }
4238+ char * name_buffer = NULL ;
4239+ int result = parse_reg_ranges_impl (ranges , args , reg_type , max_val , & name_buffer );
4240+ free (name_buffer );
4241+ free (args );
4242+ return result ;
4243+ }
4244+
42144245COMMAND_HANDLER (riscv_set_expose_csrs )
42154246{
42164247 if (CMD_ARGC == 0 )
@@ -4221,7 +4252,7 @@ COMMAND_HANDLER(riscv_set_expose_csrs)
42214252 int ret = ERROR_OK ;
42224253
42234254 for (unsigned int i = 0 ; i < CMD_ARGC ; i ++ ) {
4224- ret = parse_ranges (& info -> expose_csr , CMD_ARGV [i ], "csr" , 0xfff );
4255+ ret = parse_reg_ranges (& info -> expose_csr , CMD_ARGV [i ], "csr" , 0xfff );
42254256 if (ret != ERROR_OK )
42264257 break ;
42274258 }
@@ -4239,7 +4270,7 @@ COMMAND_HANDLER(riscv_set_expose_custom)
42394270 int ret = ERROR_OK ;
42404271
42414272 for (unsigned int i = 0 ; i < CMD_ARGC ; i ++ ) {
4242- ret = parse_ranges (& info -> expose_custom , CMD_ARGV [i ], "custom" , 0x3fff );
4273+ ret = parse_reg_ranges (& info -> expose_custom , CMD_ARGV [i ], "custom" , 0x3fff );
42434274 if (ret != ERROR_OK )
42444275 break ;
42454276 }
@@ -4257,7 +4288,7 @@ COMMAND_HANDLER(riscv_hide_csrs)
42574288 int ret = ERROR_OK ;
42584289
42594290 for (unsigned int i = 0 ; i < CMD_ARGC ; i ++ ) {
4260- ret = parse_ranges (& info -> hide_csr , CMD_ARGV [i ], "csr" , 0xfff );
4291+ ret = parse_reg_ranges (& info -> hide_csr , CMD_ARGV [i ], "csr" , 0xfff );
42614292 if (ret != ERROR_OK )
42624293 break ;
42634294 }
0 commit comments