@@ -4008,74 +4008,96 @@ COMMAND_HANDLER(riscv_set_mem_access)
40084008 return ERROR_OK ;
40094009}
40104010
4011- static int parse_ranges (struct list_head * ranges , const char * tcl_arg , const char * reg_type , unsigned int max_val )
4012- {
4013- char * args = strdup (tcl_arg );
4014- if (!args )
4015- return ERROR_FAIL ;
40164011
4017- /* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */
4018- char * arg = strtok (args , "," );
4019- while (arg ) {
4012+ static bool parse_csr_address (const char * reg_address_str , unsigned int * reg_addr )
4013+ {
4014+ * reg_addr = -1 ;
4015+ /* skip initial spaces */
4016+ while (isspace (reg_address_str [0 ]))
4017+ ++ reg_address_str ;
4018+ /* try to detect if string starts with 0x or 0X */
4019+ bool is_hex_address = strncmp (reg_address_str , "0x" , 2 ) == 0 ||
4020+ strncmp (reg_address_str , "0X" , 2 ) == 0 ;
4021+
4022+ unsigned int scanned_chars ;
4023+ if (is_hex_address ) {
4024+ reg_address_str += 2 ;
4025+ if (sscanf (reg_address_str , "%x%n" , reg_addr , & scanned_chars ) != 1 )
4026+ return false;
4027+ } else {
4028+ /* If we are here and register address string starts with zero, this is
4029+ * an indication that most likely user has an incorrect input because:
4030+ * - decimal numbers typically do not start with "0"
4031+ * - octals are not supported by our interface
4032+ * - hexadecimal numbers should have "0x" prefix
4033+ * Thus such input is rejected. */
4034+ if (reg_address_str [0 ] == '0' && strlen (reg_address_str ) > 1 )
4035+ return false;
4036+ if (sscanf (reg_address_str , "%u%n" , reg_addr , & scanned_chars ) != 1 )
4037+ return false;
4038+ }
4039+ return scanned_chars == strlen (reg_address_str );
4040+ }
4041+
4042+ static int parse_reg_ranges_impl (struct list_head * ranges , char * args ,
4043+ const char * reg_type , unsigned int max_val , char * * const name_buffer )
4044+ {
4045+ /* For backward compatibility, allow multiple parameters within one TCL
4046+ * argument, separated by ',' */
4047+ for (char * arg = strtok (args , "," ); arg ; arg = strtok (NULL , "," )) {
40204048 unsigned int low = 0 ;
40214049 unsigned int high = 0 ;
40224050 char * name = NULL ;
40234051
40244052 char * dash = strchr (arg , '-' );
40254053 char * equals = strchr (arg , '=' );
4026- unsigned int pos ;
40274054
40284055 if (!dash && !equals ) {
40294056 /* Expecting single register number. */
4030- if (sscanf (arg , "%u%n" , & low , & pos ) != 1 || pos != strlen ( arg )) {
4057+ if (! parse_csr_address (arg , & low )) {
40314058 LOG_ERROR ("Failed to parse single register number from '%s'." , arg );
4032- free (args );
40334059 return ERROR_COMMAND_SYNTAX_ERROR ;
40344060 }
40354061 } else if (dash && !equals ) {
40364062 /* Expecting register range - two numbers separated by a dash: ##-## */
4037- * dash = 0 ;
4038- dash ++ ;
4039- if (sscanf (arg , "%u%n" , & low , & pos ) != 1 || pos != strlen (arg )) {
4040- LOG_ERROR ("Failed to parse single register number from '%s'." , arg );
4041- free (args );
4063+ * dash = '\0' ;
4064+ if (!parse_csr_address (arg , & low )) {
4065+ LOG_ERROR ("Failed to parse '%s' - not a valid decimal or hexadecimal number." ,
4066+ arg );
40424067 return ERROR_COMMAND_SYNTAX_ERROR ;
40434068 }
4044- if (sscanf (dash , "%u%n" , & high , & pos ) != 1 || pos != strlen (dash )) {
4045- LOG_ERROR ("Failed to parse single register number from '%s'." , dash );
4046- free (args );
4069+ const char * high_num_in = dash + 1 ;
4070+ if (!parse_csr_address (high_num_in , & high )) {
4071+ LOG_ERROR ("Failed to parse '%s' - not a valid decimal or hexadecimal number." ,
4072+ high_num_in );
40474073 return ERROR_COMMAND_SYNTAX_ERROR ;
40484074 }
40494075 if (high < low ) {
40504076 LOG_ERROR ("Incorrect range encountered [%u, %u]." , low , high );
4051- free (args );
40524077 return ERROR_FAIL ;
40534078 }
40544079 } else if (!dash && equals ) {
40554080 /* Expecting single register number with textual name specified: ##=name */
4056- * equals = 0 ;
4057- equals ++ ;
4058- if (sscanf (arg , "%u%n" , & low , & pos ) != 1 || pos != strlen (arg )) {
4059- LOG_ERROR ("Failed to parse single register number from '%s'." , arg );
4060- free (args );
4081+ * equals = '\0' ;
4082+ if (!parse_csr_address (arg , & low )) {
4083+ LOG_ERROR ("Failed to parse '%s' - not a valid decimal or hexadecimal number." ,
4084+ arg );
40614085 return ERROR_COMMAND_SYNTAX_ERROR ;
40624086 }
40634087
4064- name = calloc (1 , strlen (equals ) + strlen (reg_type ) + 2 );
4088+ const char * const reg_name_in = equals + 1 ;
4089+ * name_buffer = calloc (1 , strlen (reg_name_in ) + strlen (reg_type ) + 2 );
4090+ name = * name_buffer ;
40654091 if (!name ) {
4066- LOG_ERROR ("Failed to allocate register name." );
4067- free (args );
4092+ LOG_ERROR ("Out of memory" );
40684093 return ERROR_FAIL ;
40694094 }
40704095
4071- /* Register prefix: "csr_" or "custom_" */
4072- strcpy (name , reg_type );
4073- name [strlen (reg_type )] = '_' ;
4074-
4075- if (sscanf (equals , "%[_a-zA-Z0-9]%n" , name + strlen (reg_type ) + 1 , & pos ) != 1 || pos != strlen (equals )) {
4076- LOG_ERROR ("Failed to parse register name from '%s'." , equals );
4077- free (args );
4078- free (name );
4096+ unsigned int scanned_chars ;
4097+ char * scan_dst = name + strlen (reg_type ) + 1 ;
4098+ if (sscanf (reg_name_in , "%[_a-zA-Z0-9]%n" , scan_dst , & scanned_chars ) != 1 ||
4099+ scanned_chars != strlen (reg_name_in )) {
4100+ LOG_ERROR ("Invalid characters in register name '%s'." , reg_name_in );
40794101 return ERROR_COMMAND_SYNTAX_ERROR ;
40804102 }
40814103 } else {
@@ -4087,9 +4109,8 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha
40874109 high = MAX (high , low );
40884110
40894111 if (high > max_val ) {
4090- LOG_ERROR ("Cannot expose %s register number %u, maximum allowed value is %u." , reg_type , high , max_val );
4091- free (name );
4092- free (args );
4112+ LOG_ERROR ("Cannot expose %s register number 0x%x, maximum allowed value is 0x%x." ,
4113+ reg_type , high , max_val );
40934114 return ERROR_FAIL ;
40944115 }
40954116
@@ -4107,32 +4128,42 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha
41074128
41084129 if (entry -> name && name && (strcasecmp (entry -> name , name ) == 0 )) {
41094130 LOG_ERROR ("Duplicate register name \"%s\" found." , name );
4110- free (name );
4111- free (args );
41124131 return ERROR_FAIL ;
41134132 }
41144133 }
41154134
41164135 range_list_t * range = calloc (1 , sizeof (range_list_t ));
41174136 if (!range ) {
4118- LOG_ERROR ("Failed to allocate range list." );
4119- free (name );
4120- free (args );
4137+ LOG_ERROR ("Out of memory" );
41214138 return ERROR_FAIL ;
41224139 }
41234140
41244141 range -> low = low ;
41254142 range -> high = high ;
41264143 range -> name = name ;
4144+ /* ownership over name_buffer contents is transferred to list item here */
4145+ * name_buffer = NULL ;
41274146 list_add (& range -> list , ranges );
4128-
4129- arg = strtok (NULL , "," );
41304147 }
41314148
4132- free (args );
41334149 return ERROR_OK ;
41344150}
41354151
4152+ static int parse_reg_ranges (struct list_head * ranges , const char * tcl_arg ,
4153+ const char * reg_type , unsigned int max_val )
4154+ {
4155+ char * args = strdup (tcl_arg );
4156+ if (!args ) {
4157+ LOG_ERROR ("Out of memory" );
4158+ return ERROR_FAIL ;
4159+ }
4160+ char * name_buffer = NULL ;
4161+ int result = parse_reg_ranges_impl (ranges , args , reg_type , max_val , & name_buffer );
4162+ free (name_buffer );
4163+ free (args );
4164+ return result ;
4165+ }
4166+
41364167COMMAND_HANDLER (riscv_set_expose_csrs )
41374168{
41384169 if (CMD_ARGC == 0 )
@@ -4143,7 +4174,7 @@ COMMAND_HANDLER(riscv_set_expose_csrs)
41434174 int ret = ERROR_OK ;
41444175
41454176 for (unsigned int i = 0 ; i < CMD_ARGC ; i ++ ) {
4146- ret = parse_ranges (& info -> expose_csr , CMD_ARGV [i ], "csr" , 0xfff );
4177+ ret = parse_reg_ranges (& info -> expose_csr , CMD_ARGV [i ], "csr" , 0xfff );
41474178 if (ret != ERROR_OK )
41484179 break ;
41494180 }
@@ -4161,7 +4192,7 @@ COMMAND_HANDLER(riscv_set_expose_custom)
41614192 int ret = ERROR_OK ;
41624193
41634194 for (unsigned int i = 0 ; i < CMD_ARGC ; i ++ ) {
4164- ret = parse_ranges (& info -> expose_custom , CMD_ARGV [i ], "custom" , 0x3fff );
4195+ ret = parse_reg_ranges (& info -> expose_custom , CMD_ARGV [i ], "custom" , 0x3fff );
41654196 if (ret != ERROR_OK )
41664197 break ;
41674198 }
@@ -4179,7 +4210,7 @@ COMMAND_HANDLER(riscv_hide_csrs)
41794210 int ret = ERROR_OK ;
41804211
41814212 for (unsigned int i = 0 ; i < CMD_ARGC ; i ++ ) {
4182- ret = parse_ranges (& info -> hide_csr , CMD_ARGV [i ], "csr" , 0xfff );
4213+ ret = parse_reg_ranges (& info -> hide_csr , CMD_ARGV [i ], "csr" , 0xfff );
41834214 if (ret != ERROR_OK )
41844215 break ;
41854216 }
0 commit comments