1 /* The common simulator framework for GDB, the GNU Debugger.
2 
3    Copyright 2002-2024 Free Software Foundation, Inc.
4 
5    Contributed by Andrew Cagney and Red Hat.
6 
7    This file is part of GDB.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 /* This must come before any other includes.  */
23 #include "defs.h"
24 
25 #include <string.h>
26 
27 #include "hw-main.h"
28 #include "hw-base.h"
29 
30 #include "sim-io.h"
31 #include "sim-assert.h"
32 
33 /* property entries */
34 
35 struct hw_property_data
36 {
37   struct hw_property_data *next;
38   struct hw_property *property;
39   const void *init_array;
40   unsigned sizeof_init_array;
41 };
42 
43 void
create_hw_property_data(struct hw * me)44 create_hw_property_data (struct hw *me)
45 {
46 }
47 
48 void
delete_hw_property_data(struct hw * me)49 delete_hw_property_data (struct hw *me)
50 {
51 }
52 
53 
54 /* Device Properties: */
55 
56 static struct hw_property_data *
find_property_data(struct hw * me,const char * property)57 find_property_data (struct hw *me,
58                         const char *property)
59 {
60   struct hw_property_data *entry;
61   ASSERT (property != NULL);
62   entry = me->properties_of_hw;
63   while (entry != NULL)
64     {
65       if (strcmp (entry->property->name, property) == 0)
66           return entry;
67       entry = entry->next;
68     }
69   return NULL;
70 }
71 
72 
73 static void
hw_add_property(struct hw * me,const char * property,hw_property_type type,const void * init_array,unsigned sizeof_init_array,const void * array,unsigned sizeof_array,const struct hw_property * original,object_disposition disposition)74 hw_add_property (struct hw *me,
75                      const char *property,
76                      hw_property_type type,
77                      const void *init_array,
78                      unsigned sizeof_init_array,
79                      const void *array,
80                      unsigned sizeof_array,
81                      const struct hw_property *original,
82                      object_disposition disposition)
83 {
84   struct hw_property_data *new_entry = NULL;
85   struct hw_property *new_value = NULL;
86 
87   /* find the list end */
88   struct hw_property_data **insertion_point = &me->properties_of_hw;
89   while (*insertion_point != NULL)
90     {
91       if (strcmp ((*insertion_point)->property->name, property) == 0)
92           return;
93       insertion_point = &(*insertion_point)->next;
94     }
95 
96   /* create a new value */
97   new_value = HW_ZALLOC (me, struct hw_property);
98   new_value->name = (char *) strdup (property);
99   new_value->type = type;
100   if (sizeof_array > 0)
101     {
102       void *new_array = hw_zalloc (me, sizeof_array);
103       memcpy (new_array, array, sizeof_array);
104       new_value->array = new_array;
105       new_value->sizeof_array = sizeof_array;
106     }
107   new_value->owner = me;
108   new_value->original = original;
109   new_value->disposition = disposition;
110 
111   /* insert the value into the list */
112   new_entry = HW_ZALLOC (me, struct hw_property_data);
113   *insertion_point = new_entry;
114   if (sizeof_init_array > 0)
115     {
116       void *new_init_array = hw_zalloc (me, sizeof_init_array);
117       memcpy (new_init_array, init_array, sizeof_init_array);
118       new_entry->init_array = new_init_array;
119       new_entry->sizeof_init_array = sizeof_init_array;
120     }
121   new_entry->property = new_value;
122 }
123 
124 
125 static void
hw_set_property(struct hw * me,const char * property,hw_property_type type,const void * array,int sizeof_array)126 hw_set_property (struct hw *me,
127                      const char *property,
128                      hw_property_type type,
129                      const void *array,
130                      int sizeof_array)
131 {
132   /* find the property */
133   struct hw_property_data *entry = find_property_data (me, property);
134   if (entry != NULL)
135     {
136       /* existing property - update it */
137       void *new_array = 0;
138       struct hw_property *value = entry->property;
139       /* check the type matches */
140       if (value->type != type)
141           hw_abort (me, "conflict between type of new and old value for property %s", property);
142       /* replace its value */
143       if (value->array != NULL)
144           hw_free (me, (void*)value->array);
145       new_array = (sizeof_array > 0
146                        ? hw_zalloc (me, sizeof_array)
147                        : (void*)0);
148       value->array = new_array;
149       value->sizeof_array = sizeof_array;
150       if (sizeof_array > 0)
151           memcpy (new_array, array, sizeof_array);
152       return;
153     }
154   else
155     {
156       /* new property - create it */
157       hw_add_property (me, property, type,
158                            NULL, 0, array, sizeof_array,
159                            NULL, temporary_object);
160     }
161 }
162 
163 
164 #if 0
165 static void
166 clean_hw_properties (struct hw *me)
167 {
168   struct hw_property_data **delete_point = &me->properties_of_hw;
169   while (*delete_point != NULL)
170     {
171       struct hw_property_data *current = *delete_point;
172       switch (current->property->disposition)
173           {
174           case permanent_object:
175             /* zap the current value, will be initialized later */
176             ASSERT (current->init_array != NULL);
177             if (current->property->array != NULL)
178               {
179                 hw_free (me, (void*)current->property->array);
180                 current->property->array = NULL;
181               }
182             delete_point = &(*delete_point)->next;
183             break;
184           case temporary_object:
185             /* zap the actual property, was created during simulation run */
186             ASSERT (current->init_array == NULL);
187             *delete_point = current->next;
188             if (current->property->array != NULL)
189               hw_free (me, (void*)current->property->array);
190             hw_free (me, current->property);
191             hw_free (me, current);
192             break;
193           }
194     }
195 }
196 #endif
197 
198 #if 0
199 void
200 hw_init_static_properties (SIM_DESC sd,
201                                  struct hw *me,
202                                  void *data)
203 {
204   struct hw_property_data *property;
205   for (property = me->properties_of_hw;
206        property != NULL;
207        property = property->next)
208     {
209       ASSERT (property->init_array != NULL);
210       ASSERT (property->property->array == NULL);
211       ASSERT (property->property->disposition == permanent_object);
212       switch (property->property->type)
213           {
214           case array_property:
215           case boolean_property:
216           case range_array_property:
217           case reg_array_property:
218           case string_property:
219           case string_array_property:
220           case integer_property:
221             /* delete the property, and replace it with the original */
222             hw_set_property (me, property->property->name,
223                                  property->property->type,
224                                  property->init_array,
225                                  property->sizeof_init_array);
226             break;
227 #if 0
228           case ihandle_property:
229             break;
230 #endif
231           }
232     }
233 }
234 #endif
235 
236 
237 #if 0
238 void
239 hw_init_runtime_properties (SIM_DESC sd,
240                                   struct hw *me,
241                                   void *data)
242 {
243   struct hw_property_data *property;
244   for (property = me->properties_of_hw;
245        property != NULL;
246        property = property->next)
247     {
248       switch (property->property->disposition)
249           {
250           case permanent_object:
251             switch (property->property->type)
252               {
253 #if 0
254               case ihandle_property:
255                 {
256                     struct hw_instance *ihandle;
257                     ihandle_runtime_property_spec spec;
258                     ASSERT (property->init_array != NULL);
259                     ASSERT (property->property->array == NULL);
260                     hw_find_ihandle_runtime_property (me, property->property->name, &spec);
261                     ihandle = tree_instance (me, spec.full_path);
262                     hw_set_ihandle_property (me, property->property->name, ihandle);
263                     break;
264                 }
265 #endif
266               case array_property:
267               case boolean_property:
268               case range_array_property:
269               case integer_property:
270               case reg_array_property:
271               case string_property:
272               case string_array_property:
273                 ASSERT (property->init_array != NULL);
274                 ASSERT (property->property->array != NULL);
275                 break;
276               }
277             break;
278           case temporary_object:
279             ASSERT (property->init_array == NULL);
280             ASSERT (property->property->array != NULL);
281             break;
282           }
283     }
284 }
285 #endif
286 
287 
288 
289 const struct hw_property *
hw_next_property(const struct hw_property * property)290 hw_next_property (const struct hw_property *property)
291 {
292   /* find the property in the list */
293   struct hw *owner = property->owner;
294   struct hw_property_data *entry = owner->properties_of_hw;
295   while (entry != NULL && entry->property != property)
296     entry = entry->next;
297   /* now return the following property */
298   ASSERT (entry != NULL); /* must be a member! */
299   if (entry->next != NULL)
300     return entry->next->property;
301   else
302     return NULL;
303 }
304 
305 
306 const struct hw_property *
hw_find_property(struct hw * me,const char * property)307 hw_find_property (struct hw *me,
308                       const char *property)
309 {
310   if (me == NULL)
311     {
312       return NULL;
313     }
314   else if (property == NULL || strcmp (property, "") == 0)
315     {
316       if (me->properties_of_hw == NULL)
317           return NULL;
318       else
319           return me->properties_of_hw->property;
320     }
321   else
322     {
323       struct hw_property_data *entry = find_property_data (me, property);
324       if (entry != NULL)
325           return entry->property;
326     }
327   return NULL;
328 }
329 
330 
331 void
hw_add_array_property(struct hw * me,const char * property,const void * array,int sizeof_array)332 hw_add_array_property (struct hw *me,
333                            const char *property,
334                            const void *array,
335                            int sizeof_array)
336 {
337   hw_add_property (me, property, array_property,
338                        array, sizeof_array, array, sizeof_array,
339                        NULL, permanent_object);
340 }
341 
342 void
hw_set_array_property(struct hw * me,const char * property,const void * array,int sizeof_array)343 hw_set_array_property (struct hw *me,
344                            const char *property,
345                            const void *array,
346                            int sizeof_array)
347 {
348   hw_set_property (me, property, array_property, array, sizeof_array);
349 }
350 
351 const struct hw_property *
hw_find_array_property(struct hw * me,const char * property)352 hw_find_array_property (struct hw *me,
353                               const char *property)
354 {
355   const struct hw_property *node;
356   node = hw_find_property (me, property);
357   if (node == NULL)
358     hw_abort (me, "property \"%s\" not found", property);
359   if (node->type != array_property)
360     hw_abort (me, "property \"%s\" of wrong type (array)", property);
361   return node;
362 }
363 
364 
365 
366 void
hw_add_boolean_property(struct hw * me,const char * property,int boolean)367 hw_add_boolean_property (struct hw *me,
368                                const char *property,
369                                int boolean)
370 {
371   int32_t new_boolean = (boolean ? -1 : 0);
372   hw_add_property (me, property, boolean_property,
373                        &new_boolean, sizeof (new_boolean),
374                        &new_boolean, sizeof (new_boolean),
375                        NULL, permanent_object);
376 }
377 
378 int
hw_find_boolean_property(struct hw * me,const char * property)379 hw_find_boolean_property (struct hw *me,
380                                 const char *property)
381 {
382   const struct hw_property *node;
383   unsigned_cell boolean;
384   node = hw_find_property (me, property);
385   if (node == NULL)
386     hw_abort (me, "property \"%s\" not found", property);
387   if (node->type != boolean_property)
388     hw_abort (me, "property \"%s\" of wrong type (boolean)", property);
389   ASSERT (sizeof (boolean) == node->sizeof_array);
390   memcpy (&boolean, node->array, sizeof (boolean));
391   return boolean;
392 }
393 
394 
395 
396 #if 0
397 void
398 hw_add_ihandle_runtime_property (struct hw *me,
399                                          const char *property,
400                                          const ihandle_runtime_property_spec *ihandle)
401 {
402   /* enter the full path as the init array */
403   hw_add_property (me, property, ihandle_property,
404                        ihandle->full_path, strlen (ihandle->full_path) + 1,
405                        NULL, 0,
406                        NULL, permanent_object);
407 }
408 #endif
409 
410 #if 0
411 void
412 hw_find_ihandle_runtime_property (struct hw *me,
413                                           const char *property,
414                                           ihandle_runtime_property_spec *ihandle)
415 {
416   struct hw_property_data *entry = find_property_data (me, property);
417   if (entry == NULL)
418     hw_abort (me, "property \"%s\" not found", property);
419   if (entry->property->type != ihandle_property
420       || entry->property->disposition != permanent_object)
421     hw_abort (me, "property \"%s\" of wrong type", property);
422   ASSERT (entry->init_array != NULL);
423   /* the full path */
424   ihandle->full_path = entry->init_array;
425 }
426 #endif
427 
428 
429 
430 #if 0
431 void
432 hw_set_ihandle_property (struct hw *me,
433                                const char *property,
434                                hw_instance *ihandle)
435 {
436   unsigned_cell cells;
437   cells = H2BE_cell (hw_instance_to_external (ihandle));
438   hw_set_property (me, property, ihandle_property,
439                        &cells, sizeof (cells));
440 
441 }
442 #endif
443 
444 #if 0
445 hw_instance *
446 hw_find_ihandle_property (struct hw *me,
447                                 const char *property)
448 {
449   const hw_property_data *node;
450   unsigned_cell ihandle;
451   hw_instance *instance;
452 
453   node = hw_find_property (me, property);
454   if (node == NULL)
455     hw_abort (me, "property \"%s\" not found", property);
456   if (node->type != ihandle_property)
457     hw_abort (me, "property \"%s\" of wrong type (ihandle)", property);
458   if (node->array == NULL)
459     hw_abort (me, "runtime property \"%s\" not yet initialized", property);
460 
461   ASSERT (sizeof (ihandle) == node->sizeof_array);
462   memcpy (&ihandle, node->array, sizeof (ihandle));
463   instance = external_to_hw_instance (me, BE2H_cell (ihandle));
464   ASSERT (instance != NULL);
465   return instance;
466 }
467 #endif
468 
469 
470 void
hw_add_integer_property(struct hw * me,const char * property,signed_cell integer)471 hw_add_integer_property (struct hw *me,
472                                const char *property,
473                                signed_cell integer)
474 {
475   H2BE (integer);
476   hw_add_property (me, property, integer_property,
477                        &integer, sizeof (integer),
478                        &integer, sizeof (integer),
479                        NULL, permanent_object);
480 }
481 
482 signed_cell
hw_find_integer_property(struct hw * me,const char * property)483 hw_find_integer_property (struct hw *me,
484                                 const char *property)
485 {
486   const struct hw_property *node;
487   signed_cell integer;
488   node = hw_find_property (me, property);
489   if (node == NULL)
490     hw_abort (me, "property \"%s\" not found", property);
491   if (node->type != integer_property)
492     hw_abort (me, "property \"%s\" of wrong type (integer)", property);
493   ASSERT (sizeof (integer) == node->sizeof_array);
494   memcpy (&integer, node->array, sizeof (integer));
495   return BE2H_cell (integer);
496 }
497 
498 int
hw_find_integer_array_property(struct hw * me,const char * property,unsigned index,signed_cell * integer)499 hw_find_integer_array_property (struct hw *me,
500                                         const char *property,
501                                         unsigned index,
502                                         signed_cell *integer)
503 {
504   const struct hw_property *node;
505   int sizeof_integer = sizeof (*integer);
506   signed_cell *cell;
507 
508   /* check things sane */
509   node = hw_find_property (me, property);
510   if (node == NULL)
511     hw_abort (me, "property \"%s\" not found", property);
512   if (node->type != integer_property
513       && node->type != array_property)
514     hw_abort (me, "property \"%s\" of wrong type (integer or array)", property);
515   if ((node->sizeof_array % sizeof_integer) != 0)
516     hw_abort (me, "property \"%s\" contains an incomplete number of cells", property);
517   if (node->sizeof_array <= sizeof_integer * index)
518     return 0;
519 
520   /* Find and convert the value */
521   cell = ((signed_cell*)node->array) + index;
522   *integer = BE2H_cell (*cell);
523 
524   return node->sizeof_array / sizeof_integer;
525 }
526 
527 
528 static unsigned_cell *
unit_address_to_cells(const hw_unit * unit,unsigned_cell * cell,int nr_cells)529 unit_address_to_cells (const hw_unit *unit,
530                            unsigned_cell *cell,
531                            int nr_cells)
532 {
533   int i;
534   ASSERT (nr_cells == unit->nr_cells);
535   for (i = 0; i < unit->nr_cells; i++)
536     {
537       *cell = H2BE_cell (unit->cells[i]);
538       cell += 1;
539     }
540   return cell;
541 }
542 
543 
544 static const unsigned_cell *
cells_to_unit_address(const unsigned_cell * cell,hw_unit * unit,int nr_cells)545 cells_to_unit_address (const unsigned_cell *cell,
546                            hw_unit *unit,
547                            int nr_cells)
548 {
549   int i;
550   memset (unit, 0, sizeof (*unit));
551   unit->nr_cells = nr_cells;
552   for (i = 0; i < unit->nr_cells; i++)
553     {
554       unit->cells[i] = BE2H_cell (*cell);
555       cell += 1;
556     }
557   return cell;
558 }
559 
560 
561 static unsigned
nr_range_property_cells(struct hw * me,int nr_ranges)562 nr_range_property_cells (struct hw *me,
563                                int nr_ranges)
564 {
565   return ((hw_unit_nr_address_cells (me)
566              + hw_unit_nr_address_cells (hw_parent (me))
567              + hw_unit_nr_size_cells (me))
568             ) * nr_ranges;
569 }
570 
571 void
hw_add_range_array_property(struct hw * me,const char * property,const range_property_spec * ranges,unsigned nr_ranges)572 hw_add_range_array_property (struct hw *me,
573                                    const char *property,
574                                    const range_property_spec *ranges,
575                                    unsigned nr_ranges)
576 {
577   unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges)
578                                  * sizeof (unsigned_cell));
579   unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
580   unsigned_cell *cell;
581   int i;
582 
583   /* copy the property elements over */
584   cell = cells;
585   for (i = 0; i < nr_ranges; i++)
586     {
587       const range_property_spec *range = &ranges[i];
588       /* copy the child address */
589       cell = unit_address_to_cells (&range->child_address, cell,
590                                             hw_unit_nr_address_cells (me));
591       /* copy the parent address */
592       cell = unit_address_to_cells (&range->parent_address, cell,
593                                             hw_unit_nr_address_cells (hw_parent (me)));
594       /* copy the size */
595       cell = unit_address_to_cells (&range->size, cell,
596                                             hw_unit_nr_size_cells (me));
597     }
598   ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]);
599 
600   /* add it */
601   hw_add_property (me, property, range_array_property,
602                        cells, sizeof_cells,
603                        cells, sizeof_cells,
604                        NULL, permanent_object);
605 
606   hw_free (me, cells);
607 }
608 
609 int
hw_find_range_array_property(struct hw * me,const char * property,unsigned index,range_property_spec * range)610 hw_find_range_array_property (struct hw *me,
611                                     const char *property,
612                                     unsigned index,
613                                     range_property_spec *range)
614 {
615   const struct hw_property *node;
616   unsigned sizeof_entry = (nr_range_property_cells (me, 1)
617                                  * sizeof (unsigned_cell));
618   const unsigned_cell *cells;
619 
620   /* locate the property */
621   node = hw_find_property (me, property);
622   if (node == NULL)
623     hw_abort (me, "property \"%s\" not found", property);
624   if (node->type != range_array_property)
625     hw_abort (me, "property \"%s\" of wrong type (range array)", property);
626 
627   /* aligned ? */
628   if ((node->sizeof_array % sizeof_entry) != 0)
629     hw_abort (me, "property \"%s\" contains an incomplete number of entries",
630                 property);
631 
632   /* within bounds? */
633   if (node->sizeof_array < sizeof_entry * (index + 1))
634     return 0;
635 
636   /* find the range of interest */
637   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
638 
639   /* copy the child address out - converting as we go */
640   cells = cells_to_unit_address (cells, &range->child_address,
641                                          hw_unit_nr_address_cells (me));
642 
643   /* copy the parent address out - converting as we go */
644   cells = cells_to_unit_address (cells, &range->parent_address,
645                                          hw_unit_nr_address_cells (hw_parent (me)));
646 
647   /* copy the size - converting as we go */
648   cells = cells_to_unit_address (cells, &range->size,
649                                          hw_unit_nr_size_cells (me));
650 
651   return node->sizeof_array / sizeof_entry;
652 }
653 
654 
655 static unsigned
nr_reg_property_cells(struct hw * me,int nr_regs)656 nr_reg_property_cells (struct hw *me,
657                            int nr_regs)
658 {
659   return (hw_unit_nr_address_cells (hw_parent (me))
660             + hw_unit_nr_size_cells (hw_parent (me))
661             ) * nr_regs;
662 }
663 
664 void
hw_add_reg_array_property(struct hw * me,const char * property,const reg_property_spec * regs,unsigned nr_regs)665 hw_add_reg_array_property (struct hw *me,
666                                  const char *property,
667                                  const reg_property_spec *regs,
668                                  unsigned nr_regs)
669 {
670   unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs)
671                                  * sizeof (unsigned_cell));
672   unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
673   unsigned_cell *cell;
674   int i;
675 
676   /* copy the property elements over */
677   cell = cells;
678   for (i = 0; i < nr_regs; i++)
679     {
680       const reg_property_spec *reg = &regs[i];
681       /* copy the address */
682       cell = unit_address_to_cells (&reg->address, cell,
683                                             hw_unit_nr_address_cells (hw_parent (me)));
684       /* copy the size */
685       cell = unit_address_to_cells (&reg->size, cell,
686                                             hw_unit_nr_size_cells (hw_parent (me)));
687     }
688   ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]);
689 
690   /* add it */
691   hw_add_property (me, property, reg_array_property,
692                        cells, sizeof_cells,
693                        cells, sizeof_cells,
694                        NULL, permanent_object);
695 
696   hw_free (me, cells);
697 }
698 
699 int
hw_find_reg_array_property(struct hw * me,const char * property,unsigned index,reg_property_spec * reg)700 hw_find_reg_array_property (struct hw *me,
701                                   const char *property,
702                                   unsigned index,
703                                   reg_property_spec *reg)
704 {
705   const struct hw_property *node;
706   unsigned sizeof_entry = (nr_reg_property_cells (me, 1)
707                                  * sizeof (unsigned_cell));
708   const unsigned_cell *cells;
709 
710   /* locate the property */
711   node = hw_find_property (me, property);
712   if (node == NULL)
713     hw_abort (me, "property \"%s\" not found", property);
714   if (node->type != reg_array_property)
715     hw_abort (me, "property \"%s\" of wrong type (reg array)", property);
716 
717   /* aligned ? */
718   if ((node->sizeof_array % sizeof_entry) != 0)
719     hw_abort (me, "property \"%s\" contains an incomplete number of entries",
720                 property);
721 
722   /* within bounds? */
723   if (node->sizeof_array < sizeof_entry * (index + 1))
724     return 0;
725 
726   /* find the range of interest */
727   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
728 
729   /* copy the address out - converting as we go */
730   cells = cells_to_unit_address (cells, &reg->address,
731                                          hw_unit_nr_address_cells (hw_parent (me)));
732 
733   /* copy the size out - converting as we go */
734   cells = cells_to_unit_address (cells, &reg->size,
735                                          hw_unit_nr_size_cells (hw_parent (me)));
736 
737   return node->sizeof_array / sizeof_entry;
738 }
739 
740 
741 void
hw_add_string_property(struct hw * me,const char * property,const char * string)742 hw_add_string_property (struct hw *me,
743                               const char *property,
744                               const char *string)
745 {
746   hw_add_property (me, property, string_property,
747                        string, strlen (string) + 1,
748                        string, strlen (string) + 1,
749                        NULL, permanent_object);
750 }
751 
752 const char *
hw_find_string_property(struct hw * me,const char * property)753 hw_find_string_property (struct hw *me,
754                                const char *property)
755 {
756   const struct hw_property *node;
757   const char *string;
758   node = hw_find_property (me, property);
759   if (node == NULL)
760     hw_abort (me, "property \"%s\" not found", property);
761   if (node->type != string_property)
762     hw_abort (me, "property \"%s\" of wrong type (string)", property);
763   string = node->array;
764   ASSERT (strlen (string) + 1 == node->sizeof_array);
765   return string;
766 }
767 
768 void
hw_add_string_array_property(struct hw * me,const char * property,const string_property_spec * strings,unsigned nr_strings)769 hw_add_string_array_property (struct hw *me,
770                                     const char *property,
771                                     const string_property_spec *strings,
772                                     unsigned nr_strings)
773 {
774   int sizeof_array;
775   int string_nr;
776   char *array;
777   char *chp;
778   if (nr_strings == 0)
779     hw_abort (me, "property \"%s\" must be non-null", property);
780   /* total up the size of the needed array */
781   for (sizeof_array = 0, string_nr = 0;
782        string_nr < nr_strings;
783        string_nr ++)
784     {
785       sizeof_array += strlen (strings[string_nr]) + 1;
786     }
787   /* create the array */
788   array = (char*) hw_zalloc (me, sizeof_array);
789   chp = array;
790   for (string_nr = 0;
791        string_nr < nr_strings;
792        string_nr++)
793     {
794       strcpy (chp, strings[string_nr]);
795       chp += strlen (chp) + 1;
796     }
797   ASSERT (chp == array + sizeof_array);
798   /* now enter it */
799   hw_add_property (me, property, string_array_property,
800                        array, sizeof_array,
801                        array, sizeof_array,
802                        NULL, permanent_object);
803 }
804 
805 int
hw_find_string_array_property(struct hw * me,const char * property,unsigned index,string_property_spec * string)806 hw_find_string_array_property (struct hw *me,
807                                      const char *property,
808                                      unsigned index,
809                                      string_property_spec *string)
810 {
811   const struct hw_property *node;
812   node = hw_find_property (me, property);
813   if (node == NULL)
814     hw_abort (me, "property \"%s\" not found", property);
815   switch (node->type)
816     {
817     default:
818       hw_abort (me, "property \"%s\" of wrong type", property);
819       break;
820     case string_property:
821       if (index == 0)
822           {
823             *string = node->array;
824             ASSERT (strlen (*string) + 1 == node->sizeof_array);
825             return 1;
826           }
827       break;
828     case array_property:
829       if (node->sizeof_array == 0
830             || ((char*)node->array)[node->sizeof_array - 1] != '\0')
831           hw_abort (me, "property \"%s\" invalid for string array", property);
832       ATTRIBUTE_FALLTHROUGH;
833     case string_array_property:
834       ASSERT (node->sizeof_array > 0);
835       ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0');
836       {
837           const char *chp = node->array;
838           int nr_entries = 0;
839           /* count the number of strings, keeping an eye out for the one
840              we're looking for */
841           *string = chp;
842           do
843             {
844               if (*chp == '\0')
845                 {
846                     /* next string */
847                     nr_entries++;
848                     chp++;
849                     if (nr_entries == index)
850                       *string = chp;
851                 }
852               else
853                 {
854                     chp++;
855                 }
856             } while (chp < (char*)node->array + node->sizeof_array);
857           if (index < nr_entries)
858             return nr_entries;
859           else
860             {
861               *string = NULL;
862               return 0;
863             }
864       }
865       break;
866     }
867   return 0;
868 }
869 
870 void
hw_add_duplicate_property(struct hw * me,const char * property,const struct hw_property * original)871 hw_add_duplicate_property (struct hw *me,
872                                  const char *property,
873                                  const struct hw_property *original)
874 {
875   struct hw_property_data *master;
876   if (original->disposition != permanent_object)
877     hw_abort (me, "Can only duplicate permanent objects");
878   /* find the original's master */
879   master = original->owner->properties_of_hw;
880   while (master->property != original)
881     {
882       master = master->next;
883       ASSERT (master != NULL);
884     }
885   /* now duplicate it */
886   hw_add_property (me, property,
887                        original->type,
888                        master->init_array, master->sizeof_init_array,
889                        original->array, original->sizeof_array,
890                        original, permanent_object);
891 }
892