1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "config.h"
22 #include <stdarg.h>
23 
24 #include "util.h"
25 #include "Emsg.h"
26 #include "StringBuilder.h"
27 
28 // The Emsg, experiment message, has as objects I18N'd messages
29 //	in a structure suitable for attaching to and fetching
30 //	from a queue of such messages.  It is intended to
31 //	be used for collector errors, collector warnings, parser
32 //	errors, and er_archive errors that are encountered when
33 //	reading an experiment
34 
35 // ----------------------- Message --------------------------
36 
Emsg(Cmsg_warn w,const char * i18n_text)37 Emsg::Emsg (Cmsg_warn w, const char *i18n_text)
38 {
39   warn = w;
40   flavor = 0;
41   par = NULL;
42   text = strdup (i18n_text);
43   next = NULL;
44 }
45 
Emsg(Cmsg_warn w,StringBuilder & sb)46 Emsg::Emsg (Cmsg_warn w, StringBuilder& sb)
47 {
48   warn = w;
49   flavor = 0;
50   par = NULL;
51   text = sb.toString ();
52   next = NULL;
53 }
54 
Emsg(Cmsg_warn w,int f,const char * param)55 Emsg::Emsg (Cmsg_warn w, int f, const char *param)
56 {
57   char *type;
58   warn = w;
59   flavor = f;
60   if (param != NULL)
61     par = dbe_strdup (param);
62   else
63     par = dbe_strdup ("");
64   next = NULL;
65 
66   // determine type
67   switch (warn)
68     {
69     case CMSG_WARN:
70       type = GTXT ("*** Collector Warning");
71       break;
72     case CMSG_ERROR:
73       type = GTXT ("*** Collector Error");
74       break;
75     case CMSG_FATAL:
76       type = GTXT ("*** Collector Fatal Error");
77       break;
78     case CMSG_COMMENT:
79       type = GTXT ("Comment");
80       break;
81     case CMSG_PARSER:
82       type = GTXT ("*** Log Error");
83       break;
84     case CMSG_ARCHIVE:
85       type = GTXT ("*** Archive Error");
86       break;
87     default:
88       type = GTXT ("*** Internal Error");
89       break;
90     };
91 
92   // now convert the message to its I18N'd string
93   switch (flavor)
94     {
95     case COL_ERROR_NONE:
96       text = dbe_sprintf (GTXT ("%s: No error"), type);
97       break;
98     case COL_ERROR_ARGS2BIG:
99       text = dbe_sprintf (GTXT ("%s: Data argument too long"), type);
100       break;
101     case COL_ERROR_BADDIR:
102       text = dbe_sprintf (GTXT ("%s: Bad experiment directory name"), type);
103       break;
104     case COL_ERROR_ARGS:
105       text = dbe_sprintf (GTXT ("%s: Data argument format error `%s'"), type, par);
106       break;
107     case COL_ERROR_PROFARGS:
108       text = dbe_sprintf (GTXT ("%s: [UNUSED] Bad clock-profiling argument"), type);
109       break;
110     case COL_ERROR_SYNCARGS:
111       text = dbe_sprintf (GTXT ("%s: [UNUSED] Bad synchronization tracing argument"), type);
112       break;
113     case COL_ERROR_HWCARGS:
114       text = dbe_sprintf (GTXT ("%s: Bad hardware counter profiling argument"), type);
115       break;
116     case COL_ERROR_DIRPERM:
117       text = dbe_sprintf (GTXT ("%s: Experiment directory is not writeable; check umask and permissions"), type);
118       break;
119     case COL_ERROR_NOMSACCT:
120       text = dbe_sprintf (GTXT ("%s: Turning on microstate accounting failed"), type);
121       break;
122     case COL_ERROR_PROFINIT:
123       text = dbe_sprintf (GTXT ("%s: Initializing clock-profiling failed"), type);
124       break;
125     case COL_ERROR_SYNCINIT:
126       text = dbe_sprintf (GTXT ("%s: Initializing synchronization tracing failed"), type);
127       break;
128     case COL_ERROR_HWCINIT:
129       text = dbe_sprintf (GTXT ("%s: Initializing hardware counter profiling failed -- %s"), type, par);
130       break;
131     case COL_ERROR_HWCFAIL:
132       text = dbe_sprintf (GTXT ("%s: HW counter data collection failed; likely cause is that another process preempted the counters"), type);
133       break;
134     case COL_ERROR_EXPOPEN:
135       text = dbe_sprintf (GTXT ("%s: Experiment initialization failed, %s"), type, par);
136       break;
137     case COL_ERROR_SIZELIM:
138       text = dbe_sprintf (GTXT ("%s: Experiment size limit exceeded, writing %s"), type, par);
139       break;
140     case COL_ERROR_SYSINFO:
141       text = dbe_sprintf (GTXT ("%s: system name can not be determined"), type);
142       break;
143     case COL_ERROR_OVWOPEN:
144       text = dbe_sprintf (GTXT ("%s: Can't open overview %s"), type, par);
145       break;
146     case COL_ERROR_OVWWRITE:
147       text = dbe_sprintf (GTXT ("%s: Can't write overview %s"), type, par);
148       break;
149     case COL_ERROR_OVWREAD:
150       text = dbe_sprintf (GTXT ("%s: Can't read overview data for %s"), type, par);
151       break;
152     case COL_ERROR_NOZMEM:
153       text = dbe_sprintf (GTXT ("%s: Open of /dev/zero failed: %s"), type, par);
154       break;
155     case COL_ERROR_NOZMEMMAP:
156       text = dbe_sprintf (GTXT ("%s: Mmap of /dev/zero failed: %s"), type, par);
157       break;
158     case COL_ERROR_NOHNDL:
159       text = dbe_sprintf (GTXT ("%s: Out of data handles for %s"), type, par);
160       break;
161     case COL_ERROR_FILEOPN:
162       text = dbe_sprintf (GTXT ("%s: Open failed %s"), type, par);
163       break;
164     case COL_ERROR_FILETRNC:
165       text = dbe_sprintf (GTXT ("%s: Truncate failed for file %s"), type, par);
166       break;
167     case COL_ERROR_FILEMAP:
168       text = dbe_sprintf (GTXT ("%s: Mmap failed %s"), type, par);
169       break;
170     case COL_ERROR_HEAPINIT:
171       text = dbe_sprintf (GTXT ("%s: Initializing heap tracing failed"), type);
172       break;
173     case COL_ERROR_DISPINIT:
174       text = dbe_sprintf (GTXT ("%s: Initializing SIGPROF dispatcher failed"), type);
175       break;
176     case COL_ERROR_ITMRINIT:
177       text = dbe_sprintf (GTXT ("%s: Initializing interval timer failed; %s"), type, par);
178       break;
179     case COL_ERROR_SMPLINIT:
180       text = dbe_sprintf (GTXT ("%s: Initializing periodic sampling failed"), type);
181       break;
182     case COL_ERROR_MPIINIT:
183       text = dbe_sprintf (GTXT ("%s: Initializing MPI tracing failed"), type);
184       break;
185     case COL_ERROR_JAVAINIT:
186       text = dbe_sprintf (GTXT ("%s: Initializing Java profiling failed"), type);
187       break;
188     case COL_ERROR_LINEINIT:
189       text = dbe_sprintf (GTXT ("%s: Initializing descendant process lineage failed"), type);
190       break;
191     case COL_ERROR_NOSPACE:
192       text = dbe_sprintf (GTXT ("%s: Out of disk space writing `%s'"), type, par);
193       break;
194     case COL_ERROR_ITMRRST:
195       text = dbe_sprintf (GTXT ("%s: Resetting interval timer failed: %s"), type, par);
196       break;
197     case COL_ERROR_MKDIR:
198       text = dbe_sprintf (GTXT ("%s: Unable to create directory `%s'"), type, par);
199       break;
200     case COL_ERROR_JVM2NEW:
201       text = dbe_sprintf (GTXT ("%s: JVM version with JVMTI requires more recent release of the performance tools; please upgrade"), type);
202       break;
203     case COL_ERROR_JVMNOTSUPP:
204       text = dbe_sprintf (GTXT ("%s: JVM version does not support JVMTI; no java profiling is available"), type);
205       break;
206     case COL_ERROR_JVMNOJSTACK:
207       text = dbe_sprintf (GTXT ("%s: JVM version does not support java callstacks; java mode data will not be recorded"), type);
208       break;
209     case COL_ERROR_DYNOPEN:
210       text = dbe_sprintf (GTXT ("%s: Can't open dyntext file `%s'"), type, par);
211       break;
212     case COL_ERROR_DYNWRITE:
213       text = dbe_sprintf (GTXT ("%s: Can't write dyntext file `%s'"), type, par);
214       break;
215     case COL_ERROR_MAPOPEN:
216       text = dbe_sprintf (GTXT ("%s: Can't open map file `%s'"), type, par);
217       break;
218     case COL_ERROR_MAPREAD:
219       text = dbe_sprintf (GTXT ("%s: Can't read map file `%s'"), type, par);
220       break;
221     case COL_ERROR_MAPWRITE:
222       text = dbe_sprintf (GTXT ("%s: Can't write map file"), type);
223       break;
224     case COL_ERROR_RESOLVE:
225       text = dbe_sprintf (GTXT ("%s: Can't resolve map file `%s'"), type, par);
226       break;
227     case COL_ERROR_OMPINIT:
228       text = dbe_sprintf (GTXT ("%s: Initializing OpenMP tracing failed"), type);
229       break;
230     case COL_ERROR_DURATION_INIT:
231       text = dbe_sprintf (GTXT ("%s: Initializing experiment-duration setting to `%s' failed"), type, par);
232       break;
233     case COL_ERROR_RDTINIT:
234       text = dbe_sprintf (GTXT ("%s: Initializing RDT failed"), type);
235       break;
236     case COL_ERROR_GENERAL:
237       if (strlen (par))
238 	text = dbe_sprintf (GTXT ("%s: %s"), type, par);
239       else
240 	text = dbe_sprintf (GTXT ("%s: General error"), type);
241       break;
242     case COL_ERROR_EXEC_FAIL:
243       text = dbe_sprintf (GTXT ("%s: Exec of process failed"), type);
244       break;
245     case COL_ERROR_THR_MAX:
246       text = dbe_sprintf (GTXT ("%s: Thread count exceeds maximum (%s); set SP_COLLECTOR_NUMTHREADS for higher value"), type, par);
247       break;
248     case COL_ERROR_IOINIT:
249       text = dbe_sprintf (GTXT ("%s: Initializing IO tracing failed"), type);
250       break;
251     case COL_ERROR_NODATA:
252       text = dbe_sprintf (GTXT ("%s: No data was recorded in the experiment"), type);
253       break;
254     case COL_ERROR_DTRACE_FATAL:
255       text = dbe_sprintf (GTXT ("%s: Fatal error reported from DTrace -- %s"), type, par);
256       break;
257     case COL_ERROR_MAPSEEK:
258       text = dbe_sprintf (GTXT ("%s: Seek error on map file `%s'"), type, par);
259       break;
260     case COL_ERROR_UNEXP_FOUNDER:
261       text = dbe_sprintf (GTXT ("%s: Unexpected value for founder `%s'"), type, par);
262       break;
263     case COL_ERROR_LOG_OPEN:
264       text = dbe_sprintf (GTXT ("%s: Failure to open log file"), type);
265       break;
266     case COL_ERROR_TSD_INIT:
267       text = dbe_sprintf (GTXT ("%s: TSD could not be initialized"), type);
268       break;
269     case COL_ERROR_UTIL_INIT:
270       text = dbe_sprintf (GTXT ("%s: libcol_util.c initialization failed"), type);
271       break;
272     case COL_ERROR_MAPCACHE:
273       text = dbe_sprintf (GTXT ("%s: Unable to cache mappings;  internal error (`%s')"), type, par);
274       break;
275     case COL_WARN_NONE:
276       text = dbe_sprintf (GTXT ("%s: No warning"), type);
277       break;
278     case COL_WARN_FSTYPE:
279       text = dbe_sprintf (GTXT ("%s: Experiment was written to a filesystem of type `%s'; data may be distorted"), type, par);
280       break;
281     case COL_WARN_PROFRND:
282       text = dbe_sprintf (GTXT ("%s: Profiling interval was changed from requested %s (microsecs.) used"), type, par);
283       break;
284     case COL_WARN_SIZELIM:
285       text = dbe_sprintf (GTXT ("%s: Experiment size limit exceeded"), type);
286       break;
287     case COL_WARN_SIGPROF:
288       text = dbe_sprintf (GTXT ("%s: SIGPROF handler was changed (%s) during the run; profile data may be unreliable"), type, par);
289       break;
290     case COL_WARN_SMPLADJ:
291       text = dbe_sprintf (GTXT ("%s: Periodic sampling rate adjusted %s microseconds"), type, par);
292       break;
293     case COL_WARN_ITMROVR:
294       text = dbe_sprintf (GTXT ("%s: Application's attempt to set interval timer period to %s was ignored; its behavior may be changed"), type, par);
295       break;
296     case COL_WARN_ITMRREP:
297       text = dbe_sprintf (GTXT ("%s: Collection interval timer period was changed (%s); profile data may be unreliable"), type, par);
298       break;
299     case COL_WARN_SIGEMT:
300       text = dbe_sprintf (GTXT ("%s: SIGEMT handler was changed during the run; profile data may be unreliable"), type);
301       break;
302     case COL_WARN_CPCBLK:
303       text = dbe_sprintf (GTXT ("%s: libcpc access blocked for hardware counter profiling"), type);
304       break;
305     case COL_WARN_VFORK:
306       text = dbe_sprintf (GTXT ("%s: vfork(2) replaced by %s; execution may be affected"), type, par);
307       break;
308     case COL_WARN_EXECENV:
309       text = dbe_sprintf (GTXT ("%s: exec environment augmented with %s missing collection variables"), type, par);
310       break;
311     case COL_WARN_SAMPSIGUSED:
312       text = dbe_sprintf (GTXT ("%s: target installed handler for sample signal %s; samples may be lost"), type, par);
313       break;
314     case COL_WARN_PAUSESIGUSED:
315       text = dbe_sprintf (GTXT ("%s: target installed handler for pause/resume signal %s; data may be lost or unexpected"),
316 			  type, par);
317       break;
318     case COL_WARN_CPCNOTRESERVED:
319       text = dbe_sprintf (GTXT ("%s: unable to reserve HW counters; data may be distorted by other users of the counters"), type);
320       break;
321     case COL_WARN_LIBTHREAD_T1: /* par contains the aslwpid... do we want to report it? */
322       text = dbe_sprintf (GTXT ("%s: application ran with a libthread version that may distort data; see collect(1) man page"), type);
323       break;
324     case COL_WARN_SIGMASK:
325       text = dbe_sprintf (GTXT ("%s: Blocking %s ignored while in use for collection"), type, par);
326       break;
327     case COL_WARN_NOFOLLOW:
328       text = dbe_sprintf (GTXT ("%s: Following disabled for uncollectable target (%s)"), type, par);
329       break;
330     case COL_WARN_RISKYFOLLOW:
331       text = dbe_sprintf (GTXT ("%s: Following unqualified target may be unreliable (%s)"), type, par);
332       break;
333     case COL_WARN_IDCHNG:
334       text = dbe_sprintf (GTXT ("%s: Imminent process ID change (%s) may result in an inconsistent experiment"), type, par);
335       break;
336     case COL_WARN_OLDJAVA:
337       text = dbe_sprintf (GTXT ("%s: Java profiling requires JVM version 1.4.2_02 or later"), type);
338       break;
339     case COL_WARN_ITMRPOVR:
340       text = dbe_sprintf (GTXT ("%s: Collector reset application's profile timer %s; application behavior may be changed"), type, par);
341       break;
342     case COL_WARN_NO_JAVA_HEAP:
343       text = dbe_sprintf (GTXT ("%s: Java heap profiling is not supported by JVMTI; disabled "), type);
344       break;
345     case COL_WARN_RDT_PAUSE_NOMEM:
346       text = dbe_sprintf (GTXT ("%s: Data race detection paused at %s because of running out of internal memory"), type, par);
347       break;
348     case COL_WARN_RDT_RESUME:
349       text = dbe_sprintf (GTXT ("%s: Data race detection resumed"), type);
350       break;
351     case COL_WARN_RDT_THROVER:
352       text = dbe_sprintf (GTXT ("%s: Too many concurrent/created threads;  accesses with thread IDs above limit are not checked"), type);
353       break;
354     case COL_WARN_THR_PAUSE_RESUME:
355       text = dbe_sprintf (GTXT ("%s: The collector_thread_pause/collector_thread_resume APIs are deprecated, and will be removed in a future release"), type);
356       break;
357     case COL_WARN_NOPROF_DATA:
358       text = dbe_sprintf (GTXT ("%s: No profile data recorded in experiment"), type);
359       break;
360     case COL_WARN_LONG_FSTAT:
361       text = dbe_sprintf (GTXT ("%s: Long fstat call -- %s"), type, par);
362       break;
363     case COL_WARN_LONG_READ:
364       text = dbe_sprintf (GTXT ("%s: Long read call -- %s"), type, par);
365       break;
366     case COL_WARN_LINUX_X86_APICID:
367       text = dbe_sprintf (GTXT ("%s: Linux libc sched_getcpu() not found; using x86 %s IDs rather than CPU IDs"), type, par);
368       break;
369 
370     case COL_COMMENT_NONE:
371       text = dbe_sprintf (GTXT ("%s"), par);
372       break;
373     case COL_COMMENT_CWD:
374       text = dbe_sprintf (GTXT ("Initial execution directory `%s'"), par);
375       break;
376     case COL_COMMENT_ARGV:
377       text = dbe_sprintf (GTXT ("Argument list `%s'"), par);
378       break;
379     case COL_COMMENT_MAYASSNAP:
380       text = dbe_sprintf (GTXT ("Mayas snap file `%s'"), par);
381       break;
382 
383     case COL_COMMENT_LINEFORK:
384       text = dbe_sprintf (GTXT ("Target fork: %s"), par);
385       break;
386     case COL_COMMENT_LINEEXEC:
387       text = dbe_sprintf (GTXT ("Target exec: %s"), par);
388       break;
389     case COL_COMMENT_LINECOMBO:
390       text = dbe_sprintf (GTXT ("Target fork/exec: %s"), par);
391       break;
392     case COL_COMMENT_FOXSNAP:
393       text = dbe_sprintf (GTXT ("Fox snap file `%s'"), par);
394       break;
395     case COL_COMMENT_ROCKSNAP:
396       text = dbe_sprintf (GTXT ("Rock simulator snap file `%s'"), par);
397       break;
398     case COL_COMMENT_BITINSTRDATA:
399       text = dbe_sprintf (GTXT ("Bit instrument data file `%s'"), par);
400       break;
401     case COL_COMMENT_BITSNAP:
402       text = dbe_sprintf (GTXT ("Bit snap file `%s'"), par);
403       break;
404     case COL_COMMENT_SIMDSPSNAP:
405       text = dbe_sprintf (GTXT ("Simulator dataspace profiling snap file `%s'"), par);
406       break;
407     case COL_COMMENT_HWCADJ:
408       text = dbe_sprintf (GTXT ("%s: HWC overflow interval adjusted: %s"), type, par);
409       break;
410     case COL_WARN_APP_NOT_READY:
411       text = dbe_sprintf (GTXT ("*** Collect: %s"), par);
412       break;
413     case COL_WARN_RDT_DL_TERMINATE:
414       text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process terminated"), type);
415       break;
416     case COL_WARN_RDT_DL_TERMINATE_CORE:
417       text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process terminated and core dumped"), type);
418       break;
419     case COL_WARN_RDT_DL_CONTINUE:
420       text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process allowed to continue"), type);
421       break;
422     default:
423       text = dbe_sprintf (GTXT ("%s: Number %d (\"%s\")"), type, flavor, par);
424       break;
425     };
426 }
427 
~Emsg()428 Emsg::~Emsg ()
429 {
430   free (par);
431   free (text);
432 }
433 
434 // ----------------------- Message Queue --------------------
Emsgqueue(char * _qname)435 Emsgqueue::Emsgqueue (char *_qname)
436 {
437   first = NULL;
438   last = NULL;
439   qname = strdup (_qname);
440 }
441 
~Emsgqueue()442 Emsgqueue::~Emsgqueue ()
443 {
444   free (qname);
445   clear ();
446 }
447 
448 Emsg *
find_msg(Cmsg_warn w,char * msg)449 Emsgqueue::find_msg (Cmsg_warn w, char *msg)
450 {
451   for (Emsg *m = first; m; m = m->next)
452     if (m->get_warn () == w && strcmp (m->get_msg (), msg) == 0)
453       return m;
454   return NULL;
455 }
456 
457 Emsg *
append(Cmsg_warn w,char * msg)458 Emsgqueue::append (Cmsg_warn w, char *msg)
459 {
460   Emsg *m = find_msg (w, msg);
461   if (m)
462     return m;
463   m = new Emsg (w, msg);
464   append (m);
465   return m;
466 }
467 
468 // Append a single message to a queue
469 void
append(Emsg * m)470 Emsgqueue::append (Emsg* m)
471 {
472   m->next = NULL;
473   if (last == NULL)
474     {
475       first = m;
476       last = m;
477     }
478   else
479     {
480       last->next = m;
481       last = m;
482     }
483 }
484 
485 // Append a queue of messages to a queue
486 void
appendqueue(Emsgqueue * mq)487 Emsgqueue::appendqueue (Emsgqueue* mq)
488 {
489   Emsg *m = mq->first;
490   if (m == NULL)
491     return;
492   if (last == NULL)
493     first = m;
494   else
495     last->next = m;
496   // now find the new last
497   while (m->next != NULL)
498     m = m->next;
499   last = m;
500 }
501 
502 Emsg *
fetch(void)503 Emsgqueue::fetch (void)
504 {
505   return first;
506 }
507 
508 // Empty the queue, deleting all messages
509 void
clear(void)510 Emsgqueue::clear (void)
511 {
512   Emsg *pp;
513   Emsg *p = first;
514   while (p != NULL)
515     {
516       pp = p;
517       p = p->next;
518       delete pp;
519     }
520   first = NULL;
521   last = NULL;
522 }
523 
524 // Mark the queue empty, without deleting the messages --
525 //	used when the messages have been requeued somewhere else
526 void
mark_clear(void)527 Emsgqueue::mark_clear (void)
528 {
529   first = NULL;
530   last = NULL;
531 }
532 
DbeMessages()533 DbeMessages::DbeMessages ()
534 {
535   msgs = NULL;
536 }
537 
~DbeMessages()538 DbeMessages::~DbeMessages ()
539 {
540   if (msgs)
541     {
542       msgs->destroy ();
543       delete msgs;
544     }
545 }
546 
547 Emsg *
get_error()548 DbeMessages::get_error ()
549 {
550   for (int i = msgs ? msgs->size () - 1 : -1; i >= 0; i--)
551     {
552       Emsg *msg = msgs->get (i);
553       if (msg->get_warn () == CMSG_ERROR)
554 	return msg;
555     }
556   return NULL;
557 }
558 
559 void
remove_msg(Emsg * msg)560 DbeMessages::remove_msg (Emsg *msg)
561 {
562   for (int i = 0, sz = msgs ? msgs->size () : 0; i < sz; i++)
563     if (msg == msgs->get (i))
564       {
565 	msgs->remove (i);
566 	delete msg;
567 	return;
568       }
569 }
570 
571 Emsg *
append_msg(Cmsg_warn w,const char * fmt,...)572 DbeMessages::append_msg (Cmsg_warn w, const char *fmt, ...)
573 {
574   char buffer[256];
575   size_t buf_size;
576   Emsg *msg;
577   va_list vp;
578 
579   va_start (vp, fmt);
580   buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
581   va_end (vp);
582   if (buf_size < sizeof (buffer))
583     msg = new Emsg (w, buffer);
584   else
585     {
586       va_start (vp, fmt);
587       char *buf = (char *) malloc (buf_size);
588       vsnprintf (buf, buf_size, fmt, vp);
589       va_end (vp);
590       msg = new Emsg (w, buf);
591       free (buf);
592     }
593 
594   if (msgs == NULL)
595     msgs = new Vector<Emsg*>();
596   msgs->append (msg);
597   Dprintf (DEBUG_ERR_MSG, NTXT ("Warning: %s\n"), msg->get_msg ());
598   return msg;
599 }
600 
601 void
append_msgs(Vector<Emsg * > * lst)602 DbeMessages::append_msgs (Vector<Emsg*> *lst)
603 {
604   if (lst && (lst->size () != 0))
605     {
606       if (msgs == NULL)
607 	msgs = new Vector<Emsg*>();
608       for (int i = 0, sz = lst->size (); i < sz; i++)
609 	{
610 	  Emsg *m = lst->fetch (i);
611 	  msgs->append (new Emsg (m->get_warn (), m->get_msg ()));
612 	}
613     }
614 }
615