Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: tm_api.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | /* | |
22 | * Copyright (C) 1991, 2001 Sun Microsystems, Inc. | |
23 | * All rights reserved. | |
24 | */ | |
25 | #pragma ident "@(#)1.4 01/11/06 tm_api.cc" | |
26 | ||
27 | /* | |
28 | * Copyright (c) 1989, Sun Microsystems, Inc. All Rights Reserved. Sun | |
29 | * considers its source code as an unpublished, proprietary trade secret, and | |
30 | * it is available only under strict license provisions. This copyright | |
31 | * notice is placed here only to protect Sun in the event the source is | |
32 | * deemed a published work. Disassembly, decompilation, or other means of | |
33 | * reducing the object code to human readable form is prohibited by the | |
34 | * license agreement under which this code is provided to the user or company | |
35 | * in possession of this copy | |
36 | * | |
37 | * RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the | |
38 | * Government is subject to restrictions as set forth in subparagraph | |
39 | * (c) (1) (ii) of the Rights in Technical Data and Computer Software clause | |
40 | * at DFARS 52.227-7013 and in similar clauses in the FAR and NASA FAR | |
41 | * Supplement | |
42 | */ | |
43 | ||
44 | #include <sys/types.h> | |
45 | #include <assert.h> | |
46 | #include <stdio.h> | |
47 | #include <stdlib.h> | |
48 | #include <string.h> | |
49 | #include <strings.h> | |
50 | #include <synch.h> | |
51 | #include <dlfcn.h> | |
52 | #include <limits.h> | |
53 | ||
54 | #include "types.h" | |
55 | #include "blaze_globals.h" | |
56 | #include "system.h" | |
57 | ||
58 | typedef void* TM_OPAQUE_DATA; | |
59 | #include "tracemod.h" | |
60 | ||
61 | #include "ui.h" | |
62 | #include "tm_impl.h" | |
63 | ||
64 | LdmNode *head_ldm = NULL; // The head of tracing LDM's | |
65 | LdmNode *head_spec_ldm = NULL; // The head of the list of BLAZE extensions | |
66 | ||
67 | uint64_t tm_time_target = 0xffffffffffffffffLLU; // Is used for global time interval event handler | |
68 | uint64_t tm_time_interval = 0; // Is used for global time interval event handler | |
69 | ||
70 | static LdmCmdNode *head_ldm_cmd = NULL; | |
71 | static char help_string [] = "usage : mod load <type> <sofile> [<arglist>] | mod unload <name>\n\ | |
72 | type ::= analyzer | py | remote\n"; | |
73 | ||
74 | static char mmi_help_string_1 [] = "usage : ldm <dev name> <instance name> [<sofile><arglist>]"; | |
75 | static char mmi_help_string_2 [] = "usage : uldm <instance name>"; | |
76 | static char mmi_help_string_3 [] = "usage : ioa <ADDR1> <ADDR2> "; | |
77 | static char mmi_help_string_4 [] = "usage : sysconf [-p <modpath> ] <modname> " | |
78 | "[ <instance_name> [ args... ] ]"; | |
79 | static char mmi_help_string_5 [] = "usage : module [<modname> ...]"; | |
80 | ||
81 | ////////////////////////////////////////////////// | |
82 | ||
83 | ||
84 | ||
85 | // | |
86 | //TODO: commands which require STOP | |
87 | // | |
88 | ////////////////////////////////////////////////// | |
89 | ||
90 | Ldm * ldm_add_spec (char * name, const char *soname) | |
91 | { | |
92 | int ii; | |
93 | Ldm *pldm; | |
94 | LdmNode *pnode; | |
95 | ||
96 | if (soname) { | |
97 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
98 | ||
99 | pldm = pnode->GetData (); | |
100 | if (strcmp (name, pldm->name) == NULL) { | |
101 | ui->error("module %s - %s is already loaded !\n", name, soname); | |
102 | return NULL; | |
103 | } | |
104 | if (pldm->soname && (strcmp(soname, pldm->soname) == NULL )) { | |
105 | ui->error("module %s - %s is already loaded !\n", name, soname); | |
106 | return NULL; | |
107 | } | |
108 | ||
109 | } | |
110 | } | |
111 | else { | |
112 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
113 | pldm = pnode->GetData (); | |
114 | if (strcmp (name, pldm->name) == NULL) { | |
115 | return NULL; | |
116 | } | |
117 | } | |
118 | } | |
119 | ||
120 | pnode = LdmNode::CreateInstance ("MOD list"); | |
121 | if (pnode == NULL) { | |
122 | ui->error("Unable to load %s-%s : unable to allocate memory\n", | |
123 | soname ? soname : "**", name); | |
124 | return NULL; | |
125 | } | |
126 | pldm = pnode->GetData (); | |
127 | ||
128 | pldm->name = (char*)strdup(name); | |
129 | pldm->soname = soname ? (char*)strdup(soname) : NULL; | |
130 | pldm->mode = TM_CBMODE; | |
131 | ||
132 | for (ii = 0; ii < MAX_MP; ii++) | |
133 | pldm->memop[ii] = TM_CONST_BADMEM; | |
134 | ||
135 | pldm->type = TM_TYPE_EXT_UNKNOWN; | |
136 | ||
137 | LdmNode::AddTail (&head_spec_ldm, pnode); | |
138 | return pldm; | |
139 | } // ldm_add_spec() | |
140 | ||
141 | ////////////////////////////////////////////////// | |
142 | ||
143 | static Ldm * ldm_add (char * name, const char *soname) | |
144 | { | |
145 | int ii; | |
146 | ||
147 | LdmNode *pnode; | |
148 | for (pnode=head_ldm; pnode; pnode=pnode->Next()) { | |
149 | Ldm * pldm = pnode->GetData(); | |
150 | ||
151 | if ((strcmp (name, pldm->name) == NULL) || (strcmp (soname, pldm->soname) == NULL)) { | |
152 | ui->error("module %s - %s is already loaded !\n", name, soname); | |
153 | return NULL; | |
154 | } | |
155 | } | |
156 | ||
157 | pnode = LdmNode::CreateInstance ("MOD list"); | |
158 | if (pnode == NULL) { | |
159 | ui->error("Unable to register MODULE <%s>\n", name); | |
160 | return NULL; | |
161 | } | |
162 | ||
163 | Ldm * pldm = pnode->GetData (); | |
164 | ||
165 | pldm->name = (char*)strdup(name); | |
166 | pldm->soname = (char*)strdup(soname); | |
167 | pldm->mode = TM_CBMODE; | |
168 | for (ii = 0; ii < MAX_MP; ii++) | |
169 | pldm->memop[ii] = TM_CONST_BADMEM; | |
170 | pldm->type = TM_TYPE_LDM; | |
171 | ||
172 | LdmNode::AddTail (&head_ldm, pnode); | |
173 | ||
174 | ||
175 | return pldm; | |
176 | } | |
177 | ||
178 | ////////////////////////////////////////////////////// | |
179 | ||
180 | static void ldm_delete_head () | |
181 | { | |
182 | LdmNode::DeleteHead(&head_ldm); | |
183 | } | |
184 | ||
185 | ////////////////////////////////////////////////////// | |
186 | ||
187 | void ldm_delete_head_spec () | |
188 | { | |
189 | LdmNode::DeleteHead(&head_spec_ldm); | |
190 | } | |
191 | ||
192 | ////////////////////////////////////////////////// | |
193 | ||
194 | static LdmCmd * ldm_cmd_add (const char * name, fn_ui_1 action1, fn_ui_2 action2) | |
195 | { | |
196 | LdmCmd *pldm_cmd; | |
197 | LdmCmdNode *pnode = LdmCmdNode::CreateInstance ("CMD list"); | |
198 | ||
199 | if (pnode == NULL) { | |
200 | ui->error("Unable to register UI CMD <%s>\n", name); | |
201 | return NULL; | |
202 | } | |
203 | pldm_cmd = pnode->GetData (); | |
204 | ||
205 | pldm_cmd->name = (char*)strdup(name); | |
206 | pldm_cmd->cmd_action_1 = action1; | |
207 | pldm_cmd->cmd_action_2 = action2; | |
208 | ||
209 | LdmCmdNode::AddHead (&head_ldm_cmd, pnode); | |
210 | return pldm_cmd; | |
211 | } | |
212 | ||
213 | ////////////////////////////////////////////////// | |
214 | ||
215 | ||
216 | // ---------------------------------------------------------------------------- | |
217 | ||
218 | struct mod_list { | |
219 | char * name; | |
220 | struct mod_list * next; | |
221 | } mod_list = {"$ORIGIN/../lib/", NULL}; /* $ORIGIN always at end of search */ | |
222 | ||
223 | ||
224 | void mod_setdefault (char * subdir) /* change "../lib/" to "../lib-obp/" */ | |
225 | { /* in the $origin search path */ | |
226 | static char new_default[PATH_MAX]; | |
227 | ||
228 | sprintf (new_default, "$ORIGIN/../%s/", subdir); | |
229 | mod_list.name = new_default; | |
230 | } | |
231 | ||
232 | ||
233 | struct mod_list * mod_head = & mod_list; | |
234 | struct mod_list * mod_tail = & mod_list; | |
235 | ||
236 | ||
237 | // hmmm, shouldn't mod_addpath() do a "push" rather than an "insert"... | |
238 | ||
239 | void mod_addpath (char * path) /* subsequent dirs are inserted in */ | |
240 | { /* front of the $ORIGIN last entry */ | |
241 | struct mod_list * p; | |
242 | p = (struct mod_list*) malloc (sizeof (struct mod_list)); | |
243 | p->name = strdup (path); | |
244 | p->next = mod_tail; | |
245 | if (mod_head == mod_tail) { | |
246 | mod_head = p; | |
247 | } else { | |
248 | struct mod_list * q = mod_head; | |
249 | while (q->next != mod_tail) q = q->next; | |
250 | q->next = p; | |
251 | } | |
252 | } | |
253 | ||
254 | ||
255 | void * mod_dlopen (char * pathp, char * fname, int flags) | |
256 | { | |
257 | void * result = NULL; | |
258 | char temp[PATH_MAX]; | |
259 | ||
260 | const char * dlerr; | |
261 | ||
262 | if ( (fname[0] == '/') /* don't mess with absolute file paths */ | |
263 | ||(fname[0] == '.' && fname[1] == '/') | |
264 | ||(fname[0] == '.' && fname[1] == '.' && fname[2] == '/')) { | |
265 | sprintf (temp, "%s", fname); | |
266 | result = dlopen (temp, flags); | |
267 | if (result == NULL) { | |
268 | dlerr = dlerror(); | |
269 | if (dlerr != NULL) { | |
270 | ui->error("dlopen(%s)...\n %s\n", temp, dlerr); | |
271 | } | |
272 | } | |
273 | ||
274 | } else if (pathp != NULL) { /* use explicit path if provided */ | |
275 | sprintf (temp, "%s/%s", pathp, fname); | |
276 | result = dlopen (temp, flags); | |
277 | ||
278 | if (result == NULL) { | |
279 | dlerr = dlerror(); | |
280 | if (dlerr != NULL) { | |
281 | ui->error("dlopen(%s)...\n %s\n", temp, dlerr); | |
282 | } | |
283 | } | |
284 | ||
285 | } else { /* otherwise use searchlist */ | |
286 | for (struct mod_list * p = mod_head; p != NULL; p = p->next) { | |
287 | ||
288 | sprintf (temp, "%s/%s", p->name, fname); | |
289 | result = dlopen (temp, flags); | |
290 | ||
291 | if (result == NULL) { | |
292 | dlerr = dlerror(); | |
293 | if(dlerr) { | |
294 | ui->output("dlopen(%s): trying path %s...\n %s\n", fname, temp, dlerr); | |
295 | } | |
296 | } else | |
297 | break; /* <-- found it ! */ | |
298 | } | |
299 | } | |
300 | ||
301 | if (result != NULL) | |
302 | ui->verbose("dlopen(%s): loaded successfully\n", temp); | |
303 | else { | |
304 | ui->error("dlopen(%s): failed (unresolved symbols or sysconf search path incorrect)\n",fname); | |
305 | } | |
306 | ||
307 | return result; | |
308 | } | |
309 | ||
310 | // ---------------------------------------------------------------------------- | |
311 | ||
312 | ||
313 | ||
314 | ||
315 | ||
316 | // the following mod commands are currently supported: | |
317 | // mod load <modname> <module.so> | |
318 | // mod unload <modname> | |
319 | // | |
320 | const char mod_cmd_usage[] = "Usage: mod <load|unload> <analyzer|py> [path/lib_name.so]\n"; | |
321 | // | |
322 | static void * dlhandle = NULL; | |
323 | // | |
324 | void *(*vtracer_initfn)(const char *) = NULL; | |
325 | void (*vtracer_finifn)() = NULL; | |
326 | // | |
327 | ||
328 | ||
329 | int init_tracer(char* fname, char* modname, void* lib_handle) | |
330 | { | |
331 | ||
332 | dlhandle = lib_handle; | |
333 | ||
334 | // FIXME: currently, only one vtrace module is supported. 2005.09.27 | |
335 | if (g_vcpu[0]->sys_intf.vtrace != NULL) { | |
336 | ui->error("a vtracer is already loaded. Only one vtracer is supported at this time\n"); | |
337 | return 0; | |
338 | } | |
339 | ||
340 | ||
341 | vtracer_initfn = (void *(*)(const char *)) dlsym(dlhandle, "vtracer_init"); | |
342 | if (vtracer_initfn == NULL) { | |
343 | ui->error("mod load: could not find symbol vtracer_init() in %s: %s\n", fname, dlerror()); | |
344 | dlclose(dlhandle); | |
345 | return 0; | |
346 | } | |
347 | vtracer_finifn = (void (*)()) dlsym(dlhandle, "vtracer_fini"); | |
348 | if (vtracer_finifn == NULL) { | |
349 | ui->error("mod load: could not find symbol vtracer_fini() in %s: %s\n", fname, dlerror()); | |
350 | dlclose(dlhandle); | |
351 | return 0; | |
352 | } | |
353 | ||
354 | VTracer * the_vtracer = (VTracer *) vtracer_initfn(modname); | |
355 | ||
356 | for (int i=0; i<=g_vcpu_id_max; i++) | |
357 | { | |
358 | Vcpu *vcpu = get_vcpu(i); | |
359 | if (vcpu) | |
360 | { | |
361 | vcpu->sys_intf.vtrace = the_vtracer; | |
362 | vcpu->config.trace_on = 1; | |
363 | } | |
364 | } | |
365 | return 1; | |
366 | } | |
367 | ||
368 | ||
369 | int close_tracer() | |
370 | { | |
371 | if (dlhandle != NULL) { | |
372 | if (vtracer_finifn != NULL) { | |
373 | vtracer_finifn(); | |
374 | } | |
375 | ||
376 | dlclose(dlhandle); | |
377 | dlhandle = NULL; | |
378 | ||
379 | int i; | |
380 | for (i=0; i<=g_vcpu_id_max; i++) | |
381 | { | |
382 | Vcpu *vcpu = get_vcpu(i); | |
383 | if (!vcpu) | |
384 | continue; | |
385 | vcpu->sys_intf.vtrace = NULL; | |
386 | vcpu->config.trace_on = 0; | |
387 | } | |
388 | return 0; | |
389 | } | |
390 | else | |
391 | { | |
392 | ui->error("mod unload: no vtracer module is currently loaded\n"); | |
393 | return 1; | |
394 | } | |
395 | } | |
396 | ||
397 | /////////////////////////////////////////////////////////////////////////////// | |
398 | // | |
399 | // py init | |
400 | ||
401 | typedef int (*init_py_t)(char*, char*, void*); | |
402 | ||
403 | int init_py(char* fname, char* modname, void* lib_handle) | |
404 | { | |
405 | init_py_t py_initfn = (init_py_t)dlsym(lib_handle, "init_py_interface"); | |
406 | if (py_initfn == NULL) | |
407 | { | |
408 | ui->error("mod load: could not find symbol init_py_interface() in %s: %s\n", fname, dlerror()); | |
409 | dlclose(dlhandle); | |
410 | return 0; | |
411 | } | |
412 | ||
413 | return py_initfn (fname, modname, lib_handle); | |
414 | } | |
415 | ||
416 | ||
417 | /////////////////////////////////////////////////////////////////////// | |
418 | // | |
419 | ||
420 | int mod_cmd_action(void*, int argc, char **argv) | |
421 | { | |
422 | if (argc == 1) { | |
423 | ui->output(mod_cmd_usage); | |
424 | return 1; | |
425 | } | |
426 | ||
427 | char * modname = NULL; | |
428 | char * fname = NULL; | |
429 | ||
430 | if (strcmp(argv[1], "load") == 0) | |
431 | { | |
432 | if (argc != 4 && argc != 3) | |
433 | { | |
434 | ui->output(mod_cmd_usage); | |
435 | return 0; | |
436 | } | |
437 | modname = argv[2]; | |
438 | ||
439 | char suffixedname[PATH_MAX]; | |
440 | if (argc == 4) fname = argv[3]; | |
441 | else | |
442 | { /* if there isn't an argv[3] then construct one from argv[2] */ | |
443 | sprintf (suffixedname, "%s.so", argv[2]); | |
444 | fname = suffixedname; | |
445 | } | |
446 | ||
447 | ||
448 | if (ANY_RUNNING_STATE(blaze_run_state)) { | |
449 | ui->error("not in stop state, use stop command first\n"); | |
450 | return 0; | |
451 | } | |
452 | ||
453 | ||
454 | void *dlib_handle = mod_dlopen (NULL, fname, RTLD_LAZY|RTLD_GLOBAL); | |
455 | if (dlib_handle == NULL) | |
456 | { | |
457 | return 0; | |
458 | } | |
459 | ||
460 | if (strcmp(modname,"analyzer")==0) | |
461 | { | |
462 | return init_tracer(fname, modname, dlib_handle); | |
463 | } | |
464 | else if(strcmp(modname,"py")==0) | |
465 | { | |
466 | ui->verbose("loading python interpreter....\n"); | |
467 | return init_py(fname, modname, dlib_handle); | |
468 | } | |
469 | else if(strcmp(modname,"remote")==0) | |
470 | { | |
471 | extern int init_remote_debugger_interface (char*, char*, void*); | |
472 | ui->verbose(" loading interface for remote debugger....\n"); | |
473 | return init_remote_debugger_interface(fname, modname, dlib_handle); | |
474 | } | |
475 | else if (strcmp(modname,"lib")==0) | |
476 | { | |
477 | ui->verbose("lib %s was loaded. \n", fname); | |
478 | return 1; | |
479 | } | |
480 | else | |
481 | { | |
482 | ui->error(" %s : unknown module name\n%s\n", modname, mod_cmd_usage); | |
483 | dlclose(dlib_handle); | |
484 | return 0; | |
485 | } | |
486 | } | |
487 | else if (strcmp(argv[1], "unload") == 0) | |
488 | { | |
489 | if (argc < 3) | |
490 | { | |
491 | ui->output(mod_cmd_usage); | |
492 | return 0; | |
493 | } | |
494 | modname = argv[2]; | |
495 | ||
496 | if (strcmp(modname,"analyzer")==0) | |
497 | { | |
498 | return close_tracer (); | |
499 | } | |
500 | else if(strcmp(modname,"py")==0) | |
501 | { | |
502 | ui->error("cannot unload python interpreter module\n"); | |
503 | return 0; | |
504 | } | |
505 | else if(strcmp(modname,"remote")==0) | |
506 | { | |
507 | ui->error("cannot unload remote interface module\n"); | |
508 | return 0; | |
509 | } | |
510 | else | |
511 | { | |
512 | ui->error("%s: unknown module name\n%s\n", modname, mod_cmd_usage); | |
513 | return 0; | |
514 | } | |
515 | ||
516 | } /* if argv[1] eq ? */ | |
517 | else | |
518 | { | |
519 | ui->error("Invalid argument %s\n%s\n", argv[1], mod_cmd_usage); | |
520 | return 1; | |
521 | } | |
522 | ||
523 | } // int mod_cmd_action(void*, int argc, char **argv) | |
524 | ||
525 | ||
526 | ||
527 | ||
528 | ////////////////////////////////////////////////// | |
529 | ||
530 | int extra_cmd_action_1 (void*, int /*argc*/, char **argv) | |
531 | { | |
532 | LdmCmdNode *pnode = head_ldm_cmd; | |
533 | LdmCmd *pldm_cmd; | |
534 | ||
535 | for (;pnode;pnode = pnode->Next()) { | |
536 | pldm_cmd = pnode->GetData (); | |
537 | if (strcmp(argv[0], pldm_cmd->name) == NULL) { | |
538 | if (pldm_cmd->cmd_action_1) | |
539 | return pldm_cmd->cmd_action_1 (pldm_cmd->ldm->client_data, argv[1]); | |
540 | } | |
541 | } | |
542 | return 1; | |
543 | } | |
544 | ||
545 | ////////////////////////////////////////////////// | |
546 | ||
547 | int extra_cmd_action_2 (void*, int argc, char **argv) | |
548 | { | |
549 | ||
550 | LdmCmdNode *pnode = head_ldm_cmd; | |
551 | LdmCmd *pldm_cmd; | |
552 | ||
553 | for (;pnode; pnode = pnode->Next()) { | |
554 | pldm_cmd = pnode->GetData (); | |
555 | if (strcmp(argv[0], pldm_cmd->name) == NULL) { | |
556 | if (pldm_cmd->cmd_action_2) | |
557 | return pldm_cmd->cmd_action_2 (pldm_cmd->ldm->client_data, argc, argv); | |
558 | } | |
559 | } | |
560 | return 1; | |
561 | } | |
562 | ||
563 | ////////////////////////////////////////////////// | |
564 | ////////////////////////////////////////////////// | |
565 | ||
566 | extern int mmi_cmd_action (void*, int argc, char **argv) ; | |
567 | ||
568 | void init_tm () | |
569 | { | |
570 | UI_register_cmd_2 ((char*)"mod", help_string, mod_cmd_action, NULL); | |
571 | UI_register_cmd_2 ((char*)"mmi", mmi_help_string_1, mmi_cmd_action, NULL); | |
572 | UI_register_cmd_2 ((char*)"ldm", mmi_help_string_1, mmi_cmd_action, NULL); | |
573 | UI_register_cmd_2 ((char*)"ioa", mmi_help_string_1, mmi_cmd_action, NULL); | |
574 | UI_register_cmd_2 ((char*)"uldm",mmi_help_string_2, mmi_cmd_action, NULL); | |
575 | UI_register_cmd_2 ((char*)"cfg", mmi_help_string_4, mmi_cmd_action, NULL); | |
576 | UI_register_cmd_2 ((char*)"sysconf", mmi_help_string_4, mmi_cmd_action, NULL); | |
577 | UI_register_cmd_2 ((char*)"modinfo", mmi_help_string_5, mmi_cmd_action, NULL); | |
578 | ||
579 | ldm_tick_ext_init(); | |
580 | } | |
581 | ||
582 | ||
583 | ////////////////////////////////////////////////// | |
584 | ////////////////////////////////////////////////// | |
585 | //// TM API routines //// | |
586 | ////////////////////////////////////////////////// | |
587 | ////////////////////////////////////////////////// | |
588 | ||
589 | ||
590 | void TM_enable_interval (uint64_t ti) | |
591 | { | |
592 | tm_time_interval = ti; | |
593 | tm_time_target = ti + SYSTEM_get_ticks (); | |
594 | } | |
595 | void TM_disable_interval () | |
596 | { | |
597 | tm_time_target = 0xffffffffffffffffLLU; | |
598 | tm_time_interval = 0; | |
599 | } | |
600 | ||
601 | ////////////////////////////////////////////////// | |
602 | ||
603 | void TM_invalidate (tracemod_t *pmod) | |
604 | { | |
605 | pmod->valid = 0; | |
606 | } | |
607 | ||
608 | ////////////////////////////////////////////////// | |
609 | static void delete_args(Ldm *pldm) | |
610 | { | |
611 | for (int i = 0; i < pldm->argc; i++) | |
612 | free(pldm->argv[i]); | |
613 | if (pldm->argv) | |
614 | free(pldm->argv); | |
615 | } | |
616 | ||
617 | ||
618 | ////////////////////////////////////////////////// | |
619 | void TM_clean_mod () | |
620 | { | |
621 | Ldm *pldm; | |
622 | LdmNode *pnode, *prv = NULL; | |
623 | bool_t rem = FALSE; | |
624 | ||
625 | while (TRUE) { | |
626 | for (pnode=head_ldm; pnode!=NULL; pnode = pnode->Next()) { | |
627 | pldm = pnode->GetData (); | |
628 | if (!pldm->valid) { | |
629 | ui->error("TM: invalidating module <%s>\n", pldm->name); | |
630 | if (pldm->so_handle) { | |
631 | if (dlclose (pldm->so_handle)) | |
632 | ui->error("TM: dlclose failed: %s\n", dlerror()); | |
633 | } | |
634 | delete_args(pldm); | |
635 | LdmNode::DeleteNode (&head_ldm, prv); | |
636 | rem = TRUE; | |
637 | break; | |
638 | } | |
639 | prv = pnode; | |
640 | } | |
641 | if (rem) { | |
642 | rem = FALSE; | |
643 | continue; | |
644 | } | |
645 | else { | |
646 | break; | |
647 | } | |
648 | } | |
649 | } | |
650 | ||
651 | ////////////////////////////////////////////////// | |
652 | ||
653 | Ldm * TM_find_mod_spec (char * name) | |
654 | { | |
655 | Ldm *pldm; | |
656 | LdmNode *pnode; | |
657 | ||
658 | if (!name) | |
659 | return NULL; | |
660 | ||
661 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
662 | pldm = pnode->GetData (); | |
663 | if (strcmp(pldm->name, name) == NULL) { | |
664 | return pldm; | |
665 | } | |
666 | } | |
667 | return NULL; | |
668 | } | |
669 | ||
670 | ////////////////////////////////////////////////// | |
671 | ||
672 | Ldm * TM_find_mod_spec_instance (tracemod_t *parent, char * name) | |
673 | { | |
674 | Ldm *pldm; | |
675 | LdmNode *pnode; | |
676 | ||
677 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
678 | pldm = pnode->GetData (); | |
679 | if ((pldm->parent == parent) && (!name || !strcmp(pldm->name, name))) { | |
680 | return pldm; | |
681 | } | |
682 | } | |
683 | return NULL; | |
684 | } | |
685 | ||
686 | ////////////////////////////////////////////////// | |
687 | void TM_clean_mod_spec () | |
688 | { | |
689 | Ldm *pldm; | |
690 | LdmNode *pnode, *prv = NULL; | |
691 | bool_t rem = FALSE; | |
692 | ||
693 | while (TRUE) { | |
694 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
695 | ||
696 | pldm = pnode->GetData (); | |
697 | if (!pldm->valid) { | |
698 | ui->error("TM: invalidating module <%s>\n", pldm->name); | |
699 | if (pldm->so_handle) { | |
700 | if (dlclose (pldm->so_handle)) | |
701 | ui->error("TM: dlclose failed: %s\n", dlerror()); | |
702 | } | |
703 | delete_args(pldm); | |
704 | LdmNode::DeleteNode (&head_spec_ldm, prv); | |
705 | rem = TRUE; | |
706 | break; | |
707 | } | |
708 | prv = pnode; | |
709 | } | |
710 | if (rem) { | |
711 | rem = FALSE; | |
712 | continue; | |
713 | } | |
714 | else { | |
715 | break; | |
716 | } | |
717 | } | |
718 | } | |
719 | ||
720 | ////////////////////////////////////////////////// | |
721 | ||
722 | bool_t TM_verify (tracemod_t *pmod) | |
723 | { | |
724 | ||
725 | Ldm *pldm; | |
726 | LdmNode *pnode; | |
727 | ||
728 | if (!pmod) | |
729 | return FALSE; | |
730 | ||
731 | for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
732 | pldm = pnode->GetData (); | |
733 | if (pmod == pldm) { | |
734 | return TRUE; | |
735 | } | |
736 | } | |
737 | ||
738 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
739 | pldm = pnode->GetData (); | |
740 | if (pmod == pldm) { | |
741 | return TRUE; | |
742 | } | |
743 | } | |
744 | return FALSE; | |
745 | } | |
746 | ||
747 | ////////////////////////////////////////////////// | |
748 | ||
749 | tracemod_t *TM_self_register (const char* mod_name, | |
750 | const char *help, TM_OPAQUE_DATA client_data) | |
751 | { | |
752 | Ldm *pldm; | |
753 | LdmNode *pnode; | |
754 | ||
755 | for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
756 | pldm = pnode->GetData (); | |
757 | if (strcmp(mod_name, pldm->name) == NULL) { | |
758 | pldm->help = (char*) help; | |
759 | pldm->client_data = client_data; | |
760 | pldm->valid = TRUE; | |
761 | return pldm; | |
762 | } | |
763 | } | |
764 | ui->error("TM : unable to find MODULE <%s> \n", mod_name); | |
765 | return NULL; | |
766 | } | |
767 | ||
768 | ////////////////////////////////////////////////// | |
769 | ||
770 | tracemod_t *TM_self_register_spec (const char* mod_name, TM_OPAQUE_DATA client_data) | |
771 | { | |
772 | Ldm *pldm; | |
773 | LdmNode *pnode; | |
774 | ||
775 | ||
776 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
777 | pldm = pnode->GetData (); | |
778 | if (strcmp(mod_name, pldm->name) == NULL) { | |
779 | pldm->help = NULL; | |
780 | pldm->client_data = client_data; | |
781 | pldm->valid = TRUE; | |
782 | return pldm; | |
783 | } | |
784 | } | |
785 | ||
786 | ui->error("TM : unable to find MODULE <%s> \n", mod_name); | |
787 | return NULL; | |
788 | } | |
789 | ||
790 | ////////////////////////////////////////////////// | |
791 | ||
792 | void TM_ui_register_1 (tracemod_t* pmod, const char* name, | |
793 | const char */*shelp*/, const char * lhelp, fn_ui_1 fn) | |
794 | { | |
795 | LdmNode *pnode; | |
796 | Ldm *pldm; | |
797 | LdmCmd *pldm_cmd; | |
798 | ||
799 | for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
800 | ||
801 | pldm = pnode->GetData (); | |
802 | if (pmod == pldm) { | |
803 | if (pldm_cmd = ldm_cmd_add (name, fn, NULL)) { | |
804 | UI_register_cmd_1 ((char*)name, (char*)lhelp, extra_cmd_action_1, NULL); | |
805 | pldm_cmd->ldm = pldm; | |
806 | } | |
807 | return; | |
808 | } | |
809 | } | |
810 | ||
811 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
812 | pldm = pnode->GetData (); | |
813 | if (pmod == pldm) { | |
814 | if (pldm_cmd = ldm_cmd_add (name, fn, NULL)) { | |
815 | UI_register_cmd_1 ((char*)name, (char*)lhelp, extra_cmd_action_1, NULL); | |
816 | pldm_cmd->ldm = pldm; | |
817 | } | |
818 | return; | |
819 | } | |
820 | } | |
821 | ||
822 | ui->error("TM: module <%s> not found\n", pldm->name); | |
823 | } | |
824 | ||
825 | ////////////////////////////////////////////////// | |
826 | ||
827 | void TM_ui_register_2 (tracemod_t* pmod, const char* name, | |
828 | const char */*shelp*/, const char * lhelp, fn_ui_2 fn) | |
829 | { | |
830 | LdmNode *pnode; | |
831 | Ldm *pldm; | |
832 | LdmCmd *pldm_cmd; | |
833 | ||
834 | for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
835 | ||
836 | pldm = pnode->GetData (); | |
837 | if (pmod == pldm) { | |
838 | if (pldm_cmd = ldm_cmd_add (name, NULL, fn)) { | |
839 | UI_register_cmd_2 ((char*)name, (char*)lhelp, extra_cmd_action_2, NULL); | |
840 | pldm_cmd->ldm = pldm; | |
841 | } | |
842 | return; | |
843 | } | |
844 | } | |
845 | ||
846 | for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
847 | pldm = pnode->GetData (); | |
848 | if (pmod == pldm) { | |
849 | if (pldm_cmd = ldm_cmd_add (name, NULL, fn)) { | |
850 | UI_register_cmd_2 ((char*)name, (char*)lhelp, extra_cmd_action_2, NULL); | |
851 | pldm_cmd->ldm = pldm; | |
852 | } | |
853 | return; | |
854 | } | |
855 | } | |
856 | ||
857 | ui->error("TM: module <%s> not found\n", pldm->name); | |
858 | } | |
859 | ||
860 | ////////////////////////////////////////////////// | |
861 | ||
862 | void TM_time_interval_register (tracemod_t *pmod, fn_time_interval fn) | |
863 | { | |
864 | pmod->ti_action = fn; | |
865 | } | |
866 | ////////////////////////////////////////////////// | |
867 | ||
868 | void TM_ui_unregister (tracemod_t* /*pmod*/, const char *name) | |
869 | { | |
870 | ||
871 | LdmCmdNode *pnode = head_ldm_cmd, *prv = NULL; | |
872 | LdmCmd *pldm_cmd; | |
873 | ||
874 | for (;pnode; pnode = pnode->Next()) { | |
875 | pldm_cmd = pnode->GetData(); | |
876 | if (strcmp(name, pldm_cmd->name) == NULL) { | |
877 | if (prv == NULL) { | |
878 | LdmCmdNode::DeleteHead (&pnode); | |
879 | UI_invalidate_cmd ((char*)name); | |
880 | return; | |
881 | } | |
882 | else { | |
883 | LdmCmdNode::DeleteNode ((LdmCmdNode**)&head_ldm_cmd, prv); | |
884 | UI_invalidate_cmd ((char*)name); | |
885 | return; | |
886 | } | |
887 | } | |
888 | prv = pnode; | |
889 | } | |
890 | } | |
891 | ||
892 | ||
893 | ////////////////////////////////////////////////// | |
894 | ||
895 | void TM_set_type_ext (tracemod_t *pmod, Byte type) | |
896 | { | |
897 | if ( | |
898 | (type != TM_TYPE_EXT_CPU) && | |
899 | (type != TM_TYPE_EXT_DEVICE) && | |
900 | (type != TM_TYPE_EXT_SIM) | |
901 | ) { | |
902 | ui->error("TM : TM_set_type_ext (unknown type = 0x%x) \n", type); | |
903 | return; | |
904 | } | |
905 | pmod->type = type; | |
906 | } | |
907 | ||
908 | ////////////////////////////////////////////////// | |
909 | ||
910 | void TM_cpustate_register (tracemod_t* pmod, fn_cpustat fn) | |
911 | { | |
912 | pmod->cpustat_action = fn; | |
913 | } | |
914 | void TM_cpustate_registerB (tracemod_t* pmod, fn_cpustatB fn) | |
915 | { | |
916 | pmod->cpustat_actionB = fn; | |
917 | } | |
918 | ||
919 | void TM_set_mode (tracemod_t *pmod, Byte mode) | |
920 | { | |
921 | pmod->mode |= mode; | |
922 | ||
923 | if (mode & TM_EXT_IO) { | |
924 | return; | |
925 | } | |
926 | } | |
927 | ||
928 | ||
929 | bool_t TM_mt_safe () | |
930 | { | |
931 | Ldm *pldm; | |
932 | LdmNode *pnode; | |
933 | for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) { | |
934 | ||
935 | pldm = pnode->GetData (); | |
936 | if (!(pldm->mode & TM_MT_SAFE)) { | |
937 | return FALSE; | |
938 | } | |
939 | } | |
940 | return TRUE; | |
941 | } | |
942 |