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
37Emsg::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
46Emsg::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
55Emsg::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
428Emsg::~Emsg ()
429{
430  free (par);
431  free (text);
432}
433
434// ----------------------- Message Queue --------------------
435Emsgqueue::Emsgqueue (char *_qname)
436{
437  first = NULL;
438  last = NULL;
439  qname = strdup (_qname);
440}
441
442Emsgqueue::~Emsgqueue ()
443{
444  free (qname);
445  clear ();
446}
447
448Emsg *
449Emsgqueue::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
457Emsg *
458Emsgqueue::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
469void
470Emsgqueue::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
486void
487Emsgqueue::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
502Emsg *
503Emsgqueue::fetch (void)
504{
505  return first;
506}
507
508// Empty the queue, deleting all messages
509void
510Emsgqueue::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
526void
527Emsgqueue::mark_clear (void)
528{
529  first = NULL;
530  last = NULL;
531}
532
533DbeMessages::DbeMessages ()
534{
535  msgs = NULL;
536}
537
538DbeMessages::~DbeMessages ()
539{
540  if (msgs)
541    {
542      msgs->destroy ();
543      delete msgs;
544    }
545}
546
547Emsg *
548DbeMessages::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
559void
560DbeMessages::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
571Emsg *
572DbeMessages::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
601void
602DbeMessages::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