~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/parse-events.y

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 %define api.pure full
  2 %parse-param {void *_parse_state}
  3 %parse-param {void *scanner}
  4 %lex-param {void* scanner}
  5 %locations
  6 
  7 %{
  8 
  9 #ifndef NDEBUG
 10 #define YYDEBUG 1
 11 #endif
 12 
 13 #include <errno.h>
 14 #include <linux/compiler.h>
 15 #include <linux/types.h>
 16 #include "pmu.h"
 17 #include "pmus.h"
 18 #include "evsel.h"
 19 #include "parse-events.h"
 20 #include "parse-events-bison.h"
 21 
 22 int parse_events_lex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void *yyscanner);
 23 void parse_events_error(YYLTYPE *loc, void *parse_state, void *scanner, char const *msg);
 24 
 25 #define PE_ABORT(val) \
 26 do { \
 27         if (val == -ENOMEM) \
 28                 YYNOMEM; \
 29         YYABORT; \
 30 } while (0)
 31 
 32 static struct list_head* alloc_list(void)
 33 {
 34         struct list_head *list;
 35 
 36         list = malloc(sizeof(*list));
 37         if (!list)
 38                 return NULL;
 39 
 40         INIT_LIST_HEAD(list);
 41         return list;
 42 }
 43 
 44 static void free_list_evsel(struct list_head* list_evsel)
 45 {
 46         struct evsel *evsel, *tmp;
 47 
 48         list_for_each_entry_safe(evsel, tmp, list_evsel, core.node) {
 49                 list_del_init(&evsel->core.node);
 50                 evsel__delete(evsel);
 51         }
 52         free(list_evsel);
 53 }
 54 
 55 %}
 56 
 57 %token PE_START_EVENTS PE_START_TERMS
 58 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM
 59 %token PE_VALUE_SYM_TOOL
 60 %token PE_EVENT_NAME
 61 %token PE_RAW PE_NAME
 62 %token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH
 63 %token PE_LEGACY_CACHE
 64 %token PE_PREFIX_MEM
 65 %token PE_ERROR
 66 %token PE_DRV_CFG_TERM
 67 %token PE_TERM_HW
 68 %type <num> PE_VALUE
 69 %type <num> PE_VALUE_SYM_HW
 70 %type <num> PE_VALUE_SYM_SW
 71 %type <num> PE_VALUE_SYM_TOOL
 72 %type <mod> PE_MODIFIER_EVENT
 73 %type <term_type> PE_TERM
 74 %type <num> value_sym
 75 %type <str> PE_RAW
 76 %type <str> PE_NAME
 77 %type <str> PE_LEGACY_CACHE
 78 %type <str> PE_MODIFIER_BP
 79 %type <str> PE_EVENT_NAME
 80 %type <str> PE_DRV_CFG_TERM
 81 %type <str> name_or_raw
 82 %destructor { free ($$); } <str>
 83 %type <term> event_term
 84 %destructor { parse_events_term__delete ($$); } <term>
 85 %type <list_terms> event_config
 86 %type <list_terms> opt_event_config
 87 %type <list_terms> opt_pmu_config
 88 %destructor { parse_events_terms__delete ($$); } <list_terms>
 89 %type <list_evsel> event_pmu
 90 %type <list_evsel> event_legacy_symbol
 91 %type <list_evsel> event_legacy_cache
 92 %type <list_evsel> event_legacy_mem
 93 %type <list_evsel> event_legacy_tracepoint
 94 %type <list_evsel> event_legacy_numeric
 95 %type <list_evsel> event_legacy_raw
 96 %type <list_evsel> event_def
 97 %type <list_evsel> event_mod
 98 %type <list_evsel> event_name
 99 %type <list_evsel> event
100 %type <list_evsel> events
101 %type <list_evsel> group_def
102 %type <list_evsel> group
103 %type <list_evsel> groups
104 %destructor { free_list_evsel ($$); } <list_evsel>
105 %type <tracepoint_name> tracepoint_name
106 %destructor { free ($$.sys); free ($$.event); } <tracepoint_name>
107 %type <hardware_term> PE_TERM_HW
108 %destructor { free ($$.str); } <hardware_term>
109 
110 %union
111 {
112         char *str;
113         u64 num;
114         struct parse_events_modifier mod;
115         enum parse_events__term_type term_type;
116         struct list_head *list_evsel;
117         struct parse_events_terms *list_terms;
118         struct parse_events_term *term;
119         struct tracepoint_name {
120                 char *sys;
121                 char *event;
122         } tracepoint_name;
123         struct hardware_term {
124                 char *str;
125                 u64 num;
126         } hardware_term;
127 }
128 %%
129 
130  /*
131   * Entry points. We are either parsing events or terminals. Just terminal
132   * parsing is used for parsing events in sysfs.
133   */
134 start:
135 PE_START_EVENTS start_events
136 |
137 PE_START_TERMS  start_terms
138 
139 start_events: groups
140 {
141         /* Take the parsed events, groups.. and place into parse_state. */
142         struct list_head *groups  = $1;
143         struct parse_events_state *parse_state = _parse_state;
144 
145         list_splice_tail(groups, &parse_state->list);
146         free(groups);
147 }
148 
149 groups: /* A list of groups or events. */
150 groups ',' group
151 {
152         /* Merge group into the list of events/groups. */
153         struct list_head *groups  = $1;
154         struct list_head *group  = $3;
155 
156         list_splice_tail(group, groups);
157         free(group);
158         $$ = groups;
159 }
160 |
161 groups ',' event
162 {
163         /* Merge event into the list of events/groups. */
164         struct list_head *groups  = $1;
165         struct list_head *event = $3;
166 
167 
168         list_splice_tail(event, groups);
169         free(event);
170         $$ = groups;
171 }
172 |
173 group
174 |
175 event
176 
177 group:
178 group_def ':' PE_MODIFIER_EVENT
179 {
180         /* Apply the modifier to the events in the group_def. */
181         struct list_head *list = $1;
182         int err;
183 
184         err = parse_events__modifier_group(_parse_state, &@3, list, $3);
185         if (err)
186                 YYABORT;
187         $$ = list;
188 }
189 |
190 group_def
191 
192 group_def:
193 PE_NAME '{' events '}'
194 {
195         struct list_head *list = $3;
196 
197         /*
198          * Set the first entry of list to be the leader. Set the group name on
199          * the leader to $1 taking ownership.
200          */
201         parse_events__set_leader($1, list);
202         $$ = list;
203 }
204 |
205 '{' events '}'
206 {
207         struct list_head *list = $2;
208 
209         /* Set the first entry of list to be the leader clearing the group name. */
210         parse_events__set_leader(NULL, list);
211         $$ = list;
212 }
213 
214 events:
215 events ',' event
216 {
217         struct list_head *events  = $1;
218         struct list_head *event = $3;
219 
220         list_splice_tail(event, events);
221         free(event);
222         $$ = events;
223 }
224 |
225 event
226 
227 event: event_mod
228 
229 event_mod:
230 event_name PE_MODIFIER_EVENT
231 {
232         struct list_head *list = $1;
233         int err;
234 
235         /*
236          * Apply modifier on all events added by single event definition
237          * (there could be more events added for multiple tracepoint
238          * definitions via '*?'.
239          */
240         err = parse_events__modifier_event(_parse_state, &@2, list, $2);
241         if (err)
242                 YYABORT;
243         $$ = list;
244 }
245 |
246 event_name
247 
248 event_name:
249 PE_EVENT_NAME event_def
250 {
251         /*
252          * When an event is parsed the text is rewound and the entire text of
253          * the event is set to the str of PE_EVENT_NAME token matched here. If
254          * no name was on an event via a term, set the name to the entire text
255          * taking ownership of the allocation.
256          */
257         int err = parse_events__set_default_name($2, $1);
258 
259         if (err) {
260                 free_list_evsel($2);
261                 YYNOMEM;
262         }
263         $$ = $2;
264 }
265 |
266 event_def
267 
268 event_def: event_pmu |
269            event_legacy_symbol |
270            event_legacy_cache sep_dc |
271            event_legacy_mem sep_dc |
272            event_legacy_tracepoint sep_dc |
273            event_legacy_numeric sep_dc |
274            event_legacy_raw sep_dc
275 
276 event_pmu:
277 PE_NAME opt_pmu_config
278 {
279         /* List of created evsels. */
280         struct list_head *list = NULL;
281         int err = parse_events_multi_pmu_add_or_add_pmu(_parse_state, $1, $2, &list, &@1);
282 
283         parse_events_terms__delete($2);
284         free($1);
285         if (err)
286                 PE_ABORT(err);
287         $$ = list;
288 }
289 |
290 PE_NAME sep_dc
291 {
292         struct list_head *list;
293         int err;
294 
295         err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1);
296         if (err < 0) {
297                 struct parse_events_state *parse_state = _parse_state;
298                 struct parse_events_error *error = parse_state->error;
299                 char *help;
300 
301                 if (asprintf(&help, "Unable to find event on a PMU of '%s'", $1) < 0)
302                         help = NULL;
303                 parse_events_error__handle(error, @1.first_column, strdup("Bad event name"), help);
304                 free($1);
305                 PE_ABORT(err);
306         }
307         free($1);
308         $$ = list;
309 }
310 
311 value_sym:
312 PE_VALUE_SYM_HW
313 |
314 PE_VALUE_SYM_SW
315 
316 event_legacy_symbol:
317 value_sym '/' event_config '/'
318 {
319         struct list_head *list;
320         int type = $1 >> 16;
321         int config = $1 & 255;
322         int err;
323         bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
324 
325         list = alloc_list();
326         if (!list)
327                 YYNOMEM;
328         err = parse_events_add_numeric(_parse_state, list, type, config, $3, wildcard);
329         parse_events_terms__delete($3);
330         if (err) {
331                 free_list_evsel(list);
332                 PE_ABORT(err);
333         }
334         $$ = list;
335 }
336 |
337 value_sym sep_slash_slash_dc
338 {
339         struct list_head *list;
340         int type = $1 >> 16;
341         int config = $1 & 255;
342         bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
343         int err;
344 
345         list = alloc_list();
346         if (!list)
347                 YYNOMEM;
348         err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard);
349         if (err)
350                 PE_ABORT(err);
351         $$ = list;
352 }
353 |
354 PE_VALUE_SYM_TOOL sep_slash_slash_dc
355 {
356         struct list_head *list;
357         int err;
358 
359         list = alloc_list();
360         if (!list)
361                 YYNOMEM;
362         err = parse_events_add_tool(_parse_state, list, $1);
363         if (err)
364                 YYNOMEM;
365         $$ = list;
366 }
367 
368 event_legacy_cache:
369 PE_LEGACY_CACHE opt_event_config
370 {
371         struct parse_events_state *parse_state = _parse_state;
372         struct list_head *list;
373         int err;
374 
375         list = alloc_list();
376         if (!list)
377                 YYNOMEM;
378 
379         err = parse_events_add_cache(list, &parse_state->idx, $1, parse_state, $2);
380 
381         parse_events_terms__delete($2);
382         free($1);
383         if (err) {
384                 free_list_evsel(list);
385                 PE_ABORT(err);
386         }
387         $$ = list;
388 }
389 
390 event_legacy_mem:
391 PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
392 {
393         struct list_head *list;
394         int err;
395 
396         list = alloc_list();
397         if (!list)
398                 YYNOMEM;
399 
400         err = parse_events_add_breakpoint(_parse_state, list,
401                                           $2, $6, $4, $7);
402         parse_events_terms__delete($7);
403         free($6);
404         if (err) {
405                 free(list);
406                 PE_ABORT(err);
407         }
408         $$ = list;
409 }
410 |
411 PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE opt_event_config
412 {
413         struct list_head *list;
414         int err;
415 
416         list = alloc_list();
417         if (!list)
418                 YYNOMEM;
419 
420         err = parse_events_add_breakpoint(_parse_state, list,
421                                           $2, NULL, $4, $5);
422         parse_events_terms__delete($5);
423         if (err) {
424                 free(list);
425                 PE_ABORT(err);
426         }
427         $$ = list;
428 }
429 |
430 PE_PREFIX_MEM PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
431 {
432         struct list_head *list;
433         int err;
434 
435         list = alloc_list();
436         if (!list)
437                 YYNOMEM;
438 
439         err = parse_events_add_breakpoint(_parse_state, list,
440                                           $2, $4, 0, $5);
441         parse_events_terms__delete($5);
442         free($4);
443         if (err) {
444                 free(list);
445                 PE_ABORT(err);
446         }
447         $$ = list;
448 }
449 |
450 PE_PREFIX_MEM PE_VALUE opt_event_config
451 {
452         struct list_head *list;
453         int err;
454 
455         list = alloc_list();
456         if (!list)
457                 YYNOMEM;
458         err = parse_events_add_breakpoint(_parse_state, list,
459                                           $2, NULL, 0, $3);
460         parse_events_terms__delete($3);
461         if (err) {
462                 free(list);
463                 PE_ABORT(err);
464         }
465         $$ = list;
466 }
467 
468 event_legacy_tracepoint:
469 tracepoint_name opt_event_config
470 {
471         struct parse_events_state *parse_state = _parse_state;
472         struct parse_events_error *error = parse_state->error;
473         struct list_head *list;
474         int err;
475 
476         list = alloc_list();
477         if (!list)
478                 YYNOMEM;
479 
480         err = parse_events_add_tracepoint(parse_state, list, $1.sys, $1.event,
481                                         error, $2, &@1);
482 
483         parse_events_terms__delete($2);
484         free($1.sys);
485         free($1.event);
486         if (err) {
487                 free(list);
488                 PE_ABORT(err);
489         }
490         $$ = list;
491 }
492 
493 tracepoint_name:
494 PE_NAME ':' PE_NAME
495 {
496         struct tracepoint_name tracepoint = {$1, $3};
497 
498         $$ = tracepoint;
499 }
500 
501 event_legacy_numeric:
502 PE_VALUE ':' PE_VALUE opt_event_config
503 {
504         struct list_head *list;
505         int err;
506 
507         list = alloc_list();
508         if (!list)
509                 YYNOMEM;
510         err = parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4,
511                                        /*wildcard=*/false);
512         parse_events_terms__delete($4);
513         if (err) {
514                 free(list);
515                 PE_ABORT(err);
516         }
517         $$ = list;
518 }
519 
520 event_legacy_raw:
521 PE_RAW opt_event_config
522 {
523         struct list_head *list;
524         int err;
525         u64 num;
526 
527         list = alloc_list();
528         if (!list)
529                 YYNOMEM;
530         errno = 0;
531         num = strtoull($1 + 1, NULL, 16);
532         /* Given the lexer will only give [a-fA-F0-9]+ a failure here should be impossible. */
533         if (errno)
534                 YYABORT;
535         free($1);
536         err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, num, $2,
537                                        /*wildcard=*/false);
538         parse_events_terms__delete($2);
539         if (err) {
540                 free(list);
541                 PE_ABORT(err);
542         }
543         $$ = list;
544 }
545 
546 opt_event_config:
547 '/' event_config '/'
548 {
549         $$ = $2;
550 }
551 |
552 '/' '/'
553 {
554         $$ = NULL;
555 }
556 |
557 {
558         $$ = NULL;
559 }
560 
561 opt_pmu_config:
562 '/' event_config '/'
563 {
564         $$ = $2;
565 }
566 |
567 '/' '/'
568 {
569         $$ = NULL;
570 }
571 
572 start_terms: event_config
573 {
574         struct parse_events_state *parse_state = _parse_state;
575         if (parse_state->terms) {
576                 parse_events_terms__delete ($1);
577                 YYABORT;
578         }
579         parse_state->terms = $1;
580 }
581 
582 event_config:
583 event_config ',' event_term
584 {
585         struct parse_events_terms *head = $1;
586         struct parse_events_term *term = $3;
587 
588         if (!head) {
589                 parse_events_term__delete(term);
590                 YYABORT;
591         }
592         list_add_tail(&term->list, &head->terms);
593         $$ = $1;
594 }
595 |
596 event_term
597 {
598         struct parse_events_terms *head = malloc(sizeof(*head));
599         struct parse_events_term *term = $1;
600 
601         if (!head)
602                 YYNOMEM;
603         parse_events_terms__init(head);
604         list_add_tail(&term->list, &head->terms);
605         $$ = head;
606 }
607 
608 name_or_raw: PE_RAW | PE_NAME | PE_LEGACY_CACHE
609 |
610 PE_TERM_HW
611 {
612         $$ = $1.str;
613 }
614 
615 event_term:
616 PE_RAW
617 {
618         struct parse_events_term *term;
619         int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW,
620                                          strdup("raw"), $1, &@1, &@1);
621 
622         if (err) {
623                 free($1);
624                 PE_ABORT(err);
625         }
626         $$ = term;
627 }
628 |
629 name_or_raw '=' name_or_raw
630 {
631         struct parse_events_term *term;
632         int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $3, &@1, &@3);
633 
634         if (err) {
635                 free($1);
636                 free($3);
637                 PE_ABORT(err);
638         }
639         $$ = term;
640 }
641 |
642 name_or_raw '=' PE_VALUE
643 {
644         struct parse_events_term *term;
645         int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
646                                          $1, $3, /*novalue=*/false, &@1, &@3);
647 
648         if (err) {
649                 free($1);
650                 PE_ABORT(err);
651         }
652         $$ = term;
653 }
654 |
655 PE_LEGACY_CACHE
656 {
657         struct parse_events_term *term;
658         int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE,
659                                          $1, /*num=*/1, /*novalue=*/true, &@1, /*loc_val=*/NULL);
660 
661         if (err) {
662                 free($1);
663                 PE_ABORT(err);
664         }
665         $$ = term;
666 }
667 |
668 PE_NAME
669 {
670         struct parse_events_term *term;
671         int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
672                                          $1, /*num=*/1, /*novalue=*/true, &@1, /*loc_val=*/NULL);
673 
674         if (err) {
675                 free($1);
676                 PE_ABORT(err);
677         }
678         $$ = term;
679 }
680 |
681 PE_TERM_HW
682 {
683         struct parse_events_term *term;
684         int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_HARDWARE,
685                                          $1.str, $1.num & 255, /*novalue=*/false,
686                                          &@1, /*loc_val=*/NULL);
687 
688         if (err) {
689                 free($1.str);
690                 PE_ABORT(err);
691         }
692         $$ = term;
693 }
694 |
695 PE_TERM '=' name_or_raw
696 {
697         struct parse_events_term *term;
698         int err = parse_events_term__str(&term, $1, /*config=*/NULL, $3, &@1, &@3);
699 
700         if (err) {
701                 free($3);
702                 PE_ABORT(err);
703         }
704         $$ = term;
705 }
706 |
707 PE_TERM '=' PE_TERM
708 {
709         struct parse_events_term *term;
710         int err = parse_events_term__term(&term, $1, $3, &@1, &@3);
711 
712         if (err)
713                 PE_ABORT(err);
714 
715         $$ = term;
716 }
717 |
718 PE_TERM '=' PE_VALUE
719 {
720         struct parse_events_term *term;
721         int err = parse_events_term__num(&term, $1,
722                                          /*config=*/NULL, $3, /*novalue=*/false,
723                                          &@1, &@3);
724 
725         if (err)
726                 PE_ABORT(err);
727 
728         $$ = term;
729 }
730 |
731 PE_TERM
732 {
733         struct parse_events_term *term;
734         int err = parse_events_term__num(&term, $1,
735                                          /*config=*/NULL, /*num=*/1, /*novalue=*/true,
736                                          &@1, /*loc_val=*/NULL);
737 
738         if (err)
739                 PE_ABORT(err);
740 
741         $$ = term;
742 }
743 |
744 PE_DRV_CFG_TERM
745 {
746         struct parse_events_term *term;
747         char *config = strdup($1);
748         int err;
749 
750         if (!config)
751                 YYNOMEM;
752         err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, config, $1, &@1, NULL);
753         if (err) {
754                 free($1);
755                 free(config);
756                 PE_ABORT(err);
757         }
758         $$ = term;
759 }
760 
761 sep_dc: ':' |
762 
763 sep_slash_slash_dc: '/' '/' | ':' |
764 
765 %%
766 
767 void parse_events_error(YYLTYPE *loc, void *_parse_state,
768                         void *scanner __maybe_unused,
769                         char const *msg __maybe_unused)
770 {
771         struct parse_events_state *parse_state = _parse_state;
772 
773         if (!parse_state->error || !list_empty(&parse_state->error->list))
774                 return;
775 
776         parse_events_error__handle(parse_state->error, loc->last_column,
777                                    strdup("Unrecognized input"), NULL);
778 }

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php