2121#include " kernel/rtlil.h"
2222#include " libs/json11/json11.hpp"
2323
24+ #ifdef YOSYS_ENABLE_TCL
25+ #include " tclTomMath.h"
26+ #include " tclTomMathDecls.h"
27+ #endif
28+
2429YOSYS_NAMESPACE_BEGIN
2530
2631#ifdef YOSYS_ENABLE_TCL
@@ -145,29 +150,106 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
145150 continue ; \
146151 } \
147152
153+ #define FLAG2 (name ) \
154+ if (!strcmp(Tcl_GetString(objv[i]), " -" #name)) { \
155+ name##_flag = true ; \
156+ continue ; \
157+ } \
158+
148159#define ERROR (str ) \
149160 { \
150161 Tcl_SetResult (interp, (char *)(str), TCL_STATIC); \
151162 return TCL_ERROR; \
152163 }
153164
165+ bool const_to_mp_int (const Const &a, mp_int *b, bool force_signed, bool force_unsigned)
166+ {
167+ if (!a.is_fully_def ())
168+ return false ;
169+
170+ if (mp_init (b))
171+ return false ;
172+
173+ bool negative = ((a.flags & RTLIL::CONST_FLAG_SIGNED) || force_signed) &&
174+ !force_unsigned &&
175+ !a.empty () && (a.back () == RTLIL::S1);
176+
177+ for (int i = a.size () - 1 ; i >= 0 ; i--) {
178+ if (mp_mul_2d (b, 1 , b)) {
179+ mp_clear (b);
180+ return false ;
181+ }
182+
183+ if ((a[i] == RTLIL::S1) ^ negative) {
184+ if (mp_add_d (b, 1 , b)) {
185+ mp_clear (b);
186+ return false ;
187+ }
188+ }
189+ }
190+
191+ if (negative) {
192+ if (mp_add_d (b, 1 , b) || mp_neg (b, b)) {
193+ mp_clear (b);
194+ return false ;
195+ }
196+ }
197+
198+ return true ;
199+ }
200+
201+ bool mp_int_to_const (mp_int *a, Const &b, bool is_signed)
202+ {
203+ bool negative = (mp_cmp_d (a, 0 ) == MP_LT);
204+ if (negative && !is_signed)
205+ return false ;
206+
207+ if (negative) {
208+ mp_neg (a, a);
209+ mp_sub_d (a, 1 , a);
210+ }
211+
212+ std::vector<unsigned char > buf;
213+ buf.resize (mp_ubin_size (a));
214+ size_t written; // dummy
215+ mp_to_ubin (a, buf.data (), buf.size (), &written);
216+
217+ b.bits ().reserve (mp_count_bits (a) + is_signed);
218+ for (int i = 0 ; i < mp_count_bits (a);) {
219+ for (int j = 0 ; j < 8 && i < mp_count_bits (a); j++, i++) {
220+ bool bv = ((buf.back () & (1 << j)) != 0 ) ^ negative;
221+ b.bits ().push_back (bv ? RTLIL::S1 : RTLIL::S0);
222+ }
223+ buf.pop_back ();
224+ }
225+
226+ if (is_signed) {
227+ b.bits ().push_back (negative ? RTLIL::S1 : RTLIL::S0);
228+ }
229+
230+ return true ;
231+ }
232+
154233static int tcl_get_attr (ClientData, Tcl_Interp *interp, int argc, const char *argv[])
155234{
156235 int i;
157- bool mod_flag = false , string_flag = false , int_flag = false , bool_flag = false ;
236+ bool mod_flag = false , string_flag = false , bool_flag = false ;
237+ bool int_flag = false , sint_flag = false , uint_flag = false ;
158238 for (i = 1 ; i < argc; i++) {
159239 FLAG (mod)
160240 FLAG (string)
161241 FLAG (int )
242+ FLAG (sint)
243+ FLAG (uint)
162244 FLAG (bool )
163245 break ;
164246 }
165247
166248 if ((mod_flag && i != argc - 2 ) ||
167249 (!mod_flag && i != argc - 3 ) ||
168- (string_flag + int_flag + bool_flag > 1 ))
169- ERROR (" bad usage: expected \" get_attr -mod [-string|-int|-bool] <module> <attrname>\" "
170- " or \" get_attr [-string|-int|-bool] <module> <identifier> <attrname>\" " )
250+ (string_flag + int_flag + sint_flag + uint_flag + bool_flag > 1 ))
251+ ERROR (" bad usage: expected \" get_attr -mod [-string|-int|-sint|-uint|- bool] <module> <attrname>\" "
252+ " or \" get_attr [-string|-int|-sint|-uint|- bool] <module> <identifier> <attrname>\" " )
171253
172254 IdString mod_id, obj_id, attr_id;
173255 mod_id = RTLIL::escape_id (argv[i++]);
@@ -197,19 +279,17 @@ static int tcl_get_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
197279
198280 if (string_flag) {
199281 Tcl_SetResult (interp, (char *) obj->get_string_attribute (attr_id).c_str (), TCL_VOLATILE);
200- } else if (int_flag) {
282+ } else if (int_flag || uint_flag || sint_flag ) {
201283 if (!obj->has_attribute (attr_id))
202284 ERROR (" attribute missing (required for -int)" );
203-
204285 RTLIL::Const &value = obj->attributes .at (attr_id);
205- if (value.size () > 32 )
206- ERROR (" value too large" )
207286
208- // FIXME: 32'hffffffff will return as negative despite is_signed=false
209- Tcl_SetResult (interp, (char *) std::to_string (value.as_int ()).c_str (), TCL_VOLATILE);
287+ mp_int value_mp;
288+ if (!const_to_mp_int (value, &value_mp, sint_flag, uint_flag))
289+ ERROR (" bignum manipulation failed" );
290+ Tcl_SetObjResult (interp, Tcl_NewBignumObj (&value_mp));
210291 } else if (bool_flag) {
211- bool value = obj->get_bool_attribute (attr_id);
212- Tcl_SetResult (interp, (char *) std::to_string (value).c_str (), TCL_VOLATILE);
292+ Tcl_SetObjResult (interp, Tcl_NewBooleanObj (obj->get_bool_attribute (attr_id)));
213293 } else {
214294 if (!obj->has_attribute (attr_id))
215295 ERROR (" attribute missing (required unless -bool or -string)" )
@@ -264,33 +344,34 @@ static int tcl_has_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
264344 return TCL_OK;
265345}
266346
267- static int tcl_set_attr (ClientData, Tcl_Interp *interp, int argc, const char *argv [])
347+ static int tcl_set_attr (ClientData, Tcl_Interp *interp, int objc, Tcl_Obj * const objv [])
268348{
269349 int i;
270- bool mod_flag = false , string_flag = false , int_flag = false , bool_flag = false ;
271- bool false_flag = false , true_flag = false ;
272- for (i = 1 ; i < argc; i++) {
273- FLAG (mod)
274- FLAG (string)
275- FLAG (int )
276- FLAG (bool )
277- FLAG (false )
278- FLAG (true )
350+ bool mod_flag = false , string_flag = false , bool_flag = false ;
351+ bool true_flag = false , false_flag = false , sint_flag = false , uint_flag = false ;
352+ for (i = 1 ; i < objc; i++) {
353+ FLAG2 (mod)
354+ FLAG2 (string)
355+ FLAG2 (true )
356+ FLAG2 (false )
357+ FLAG2 (sint)
358+ FLAG2 (uint)
359+ FLAG2 (bool )
279360 break ;
280361 }
281362
282- if ((i != argc - (2 + !mod_flag + !(true_flag || false_flag))) ||
283- (string_flag + int_flag + bool_flag + true_flag + false_flag > 1 ))
284- ERROR (" bad usage: expected \" set_attr -mod [-string|-int |-bool] <module> <attrname> <value>\" "
285- " or \" set_attr [-string|-int |-bool] <module> <identifier> <attrname> <value>\" "
363+ if ((i != objc - (2 + !mod_flag + !(true_flag || false_flag))) ||
364+ (string_flag + sint_flag + uint_flag + bool_flag + true_flag + false_flag > 1 ))
365+ ERROR (" bad usage: expected \" set_attr -mod [-string|-sint|-uint |-bool] <module> <attrname> <value>\" "
366+ " or \" set_attr [-string|-sint|-uint |-bool] <module> <identifier> <attrname> <value>\" "
286367 " or \" set_attr [-true|-false] <module> <identifier> <attrname>\" "
287368 " or \" set_attr -mod [-true|-false| <module> <attrname>\" " )
288369
289370 IdString mod_id, obj_id, attr_id;
290- mod_id = RTLIL::escape_id (argv [i++]);
371+ mod_id = RTLIL::escape_id (Tcl_GetString (objv [i++]) );
291372 if (!mod_flag)
292- obj_id = RTLIL::escape_id (argv [i++]);
293- attr_id = RTLIL::escape_id (argv [i++]);
373+ obj_id = RTLIL::escape_id (Tcl_GetString (objv [i++]) );
374+ attr_id = RTLIL::escape_id (Tcl_GetString (objv [i++]) );
294375
295376 RTLIL::Module *mod = yosys_design->module (mod_id);
296377 if (!mod)
@@ -313,17 +394,35 @@ static int tcl_set_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
313394 ERROR (" object not found" )
314395
315396 if (string_flag) {
316- obj->set_string_attribute (attr_id, argv[i++]);
317- } else if (int_flag) {
318- obj->attributes [attr_id] = atoi (argv[i++]);
397+ obj->set_string_attribute (attr_id, Tcl_GetString (objv[i++]));
398+ } else if (sint_flag || uint_flag) {
399+ RTLIL::Const const_;
400+ mp_int value_mp;
401+
402+ if (Tcl_TakeBignumFromObj (interp, objv[i++], &value_mp))
403+ ERROR (" non-integral value" )
404+
405+ if (!mp_int_to_const (&value_mp, const_, sint_flag))
406+ ERROR (" bignum manipulation failed" );
407+
408+ if (sint_flag) {
409+ const_.flags |= RTLIL::CONST_FLAG_SIGNED;
410+ if (const_.size () < 32 )
411+ const_.exts (32 );
412+ } else {
413+ if (const_.size () < 32 )
414+ const_.extu (32 );
415+ }
416+
417+ obj->attributes [attr_id] = const_;
319418 } else if (bool_flag) {
320- obj->set_bool_attribute (attr_id, atoi (argv [i++]) != 0 );
419+ obj->set_bool_attribute (attr_id, atoi (Tcl_GetString (objv [i++]) ) != 0 );
321420 } else if (true_flag) {
322421 obj->set_bool_attribute (attr_id, true );
323422 } else if (false_flag) {
324423 obj->set_bool_attribute (attr_id, false );
325424 } else {
326- obj->attributes [attr_id] = Const::from_string (std::string (argv [i++]));
425+ obj->attributes [attr_id] = Const::from_string (std::string (Tcl_GetString (objv [i++]) ));
327426 }
328427
329428 return TCL_OK;
@@ -332,10 +431,14 @@ static int tcl_set_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
332431static int tcl_get_param (ClientData, Tcl_Interp *interp, int argc, const char *argv[])
333432{
334433 int i;
335- bool string_flag = false , int_flag = false ;
434+ bool string_flag = false , bool_flag = false ;
435+ bool int_flag = false , sint_flag = false , uint_flag = false ;
336436 for (i = 1 ; i < argc; i++) {
337437 FLAG (string)
338438 FLAG (int )
439+ FLAG (sint)
440+ FLAG (uint)
441+ FLAG (bool )
339442 break ;
340443 }
341444
@@ -363,35 +466,36 @@ static int tcl_get_param(ClientData, Tcl_Interp *interp, int argc, const char *a
363466
364467 if (string_flag) {
365468 Tcl_SetResult (interp, (char *) value.decode_string ().c_str (), TCL_VOLATILE);
366- } else if (int_flag) {
367- if (value. size () > 32 )
368- ERROR ( " value too large " )
369-
370- Tcl_SetResult (interp, ( char *) std::to_string (value. as_int ()). c_str (), TCL_VOLATILE );
469+ } else if (int_flag || uint_flag || sint_flag ) {
470+ mp_int value_mp;
471+ if (! const_to_mp_int ( value, &value_mp, sint_flag, uint_flag) )
472+ ERROR ( " bignum manipulation failed " );
473+ Tcl_SetObjResult (interp, Tcl_NewBignumObj (&value_mp) );
371474 } else {
372475 Tcl_SetResult (interp, (char *) value.as_string ().c_str (), TCL_VOLATILE);
373476 }
374477 return TCL_OK;
375478}
376479
377- static int tcl_set_param (ClientData, Tcl_Interp *interp, int argc, const char *argv [])
480+ static int tcl_set_param (ClientData, Tcl_Interp *interp, int objc, Tcl_Obj * const objv [])
378481{
379482 int i;
380- bool string_flag = false , int_flag = false ;
381- for (i = 1 ; i < argc; i++) {
382- FLAG (string)
383- FLAG (int )
483+ bool string_flag = false , sint_flag = false , uint_flag = false ;
484+ for (i = 1 ; i < objc; i++) {
485+ FLAG2 (string)
486+ FLAG2 (sint)
487+ FLAG2 (uint)
384488 break ;
385489 }
386490
387- if ((i != argc - 4 ) ||
388- (string_flag + int_flag > 1 ))
389- ERROR (" bad usage: expected \" get_param [-string|-int ] <module> <cellid> <paramname> <value>" )
491+ if ((i != objc - 4 ) ||
492+ (string_flag + sint_flag + uint_flag > 1 ))
493+ ERROR (" bad usage: expected \" set_param [-string|-sint|-uint ] <module> <cellid> <paramname> <value>" )
390494
391495 IdString mod_id, cell_id, param_id;
392- mod_id = RTLIL::escape_id (argv [i++]);
393- cell_id = RTLIL::escape_id (argv [i++]);
394- param_id = RTLIL::escape_id (argv [i++]);
496+ mod_id = RTLIL::escape_id (Tcl_GetString (objv [i++]) );
497+ cell_id = RTLIL::escape_id (Tcl_GetString (objv [i++]) );
498+ param_id = RTLIL::escape_id (Tcl_GetString (objv [i++]) );
395499
396500 RTLIL::Module *mod = yosys_design->module (mod_id);
397501 if (!mod)
@@ -402,11 +506,29 @@ static int tcl_set_param(ClientData, Tcl_Interp *interp, int argc, const char *a
402506 ERROR (" object not found" )
403507
404508 if (string_flag) {
405- cell->setParam (param_id, Const (std::string (argv[i++])));
406- } else if (int_flag) {
407- cell->setParam (param_id, Const (atoi (argv[i++])));
509+ cell->setParam (param_id, Const (std::string (Tcl_GetString (objv[i++]))));
510+ } else if (sint_flag || uint_flag) {
511+ RTLIL::Const const_;
512+ mp_int value_mp;
513+
514+ if (Tcl_TakeBignumFromObj (interp, objv[i++], &value_mp))
515+ ERROR (" non-integral value" )
516+
517+ if (!mp_int_to_const (&value_mp, const_, sint_flag))
518+ ERROR (" bignum manipulation failed" );
519+
520+ if (sint_flag) {
521+ const_.flags |= RTLIL::CONST_FLAG_SIGNED;
522+ if (const_.size () < 32 )
523+ const_.exts (32 );
524+ } else {
525+ if (const_.size () < 32 )
526+ const_.extu (32 );
527+ }
528+
529+ cell->setParam (param_id, const_);
408530 } else {
409- cell->setParam (param_id, Const::from_string (std::string (argv [i++])));
531+ cell->setParam (param_id, Const::from_string (std::string (Tcl_GetString (objv [i++]) )));
410532 }
411533 return TCL_OK;
412534}
@@ -418,9 +540,9 @@ int yosys_tcl_iterp_init(Tcl_Interp *interp)
418540 Tcl_CreateCommand (interp, " yosys" , tcl_yosys_cmd, NULL , NULL );
419541 Tcl_CreateCommand (interp, " rtlil::get_attr" , tcl_get_attr, NULL , NULL );
420542 Tcl_CreateCommand (interp, " rtlil::has_attr" , tcl_has_attr, NULL , NULL );
421- Tcl_CreateCommand (interp, " rtlil::set_attr" , tcl_set_attr, NULL , NULL );
543+ Tcl_CreateObjCommand (interp, " rtlil::set_attr" , tcl_set_attr, NULL , NULL );
422544 Tcl_CreateCommand (interp, " rtlil::get_param" , tcl_get_param, NULL , NULL );
423- Tcl_CreateCommand (interp, " rtlil::set_param" , tcl_set_param, NULL , NULL );
545+ Tcl_CreateObjCommand (interp, " rtlil::set_param" , tcl_set_param, NULL , NULL );
424546
425547 // TODO:
426548 //
@@ -442,6 +564,10 @@ int yosys_tcl_iterp_init(Tcl_Interp *interp)
442564 // unpack
443565 // pack
444566
567+ // Note (dev jf 24-12-02): Make log_id escape everything that’s not a valid
568+ // verilog identifier before adding any tcl API that returns IdString values
569+ // to avoid -option injection
570+
445571 return TCL_OK ;
446572}
447573#endif
0 commit comments