On Sun, Apr 09, 2023 at 09:15:12AM +0200, Otto Moerbeek wrote:
> On Sun, Apr 09, 2023 at 08:20:43AM +0200, Otto Moerbeek wrote:
> 
> > On Sun, Apr 09, 2023 at 07:53:31AM +0200, Sebastien Marie wrote:
> > 
> > > On Fri, Apr 07, 2023 at 09:52:52AM +0200, Otto Moerbeek wrote:
> > > > > Hi,
> > > > > 
> > > > > This is work in progress. I have to think if the flags to kdump I'm
> > > > > introducing should be two or a single one.
> > > > > 
> > > > > Currently, malloc.c can be compiled with MALLOC_STATS defined. If run
> > > > > with option D it dumps its state to a malloc.out file at exit. This
> > > > > state can be used to find leaks amongst other things.
> > > > > 
> > > > > This is not ideal for pledged processes, as they often have no way to
> > > > > write files.
> > > > > 
> > > > > This changes malloc to use utrace(2) for that.
> > > > > 
> > > > > As kdump has no nice way to show those lines without all extras it
> > > > > normally shows, so add two options to it to just show the lines.
> > > > > 
> > > > > To use, compile and install libc with MALLOC_STATS defined.
> > > > > 
> > > > > Run :
> > > > > 
> > > > > $ MALLOC_OPTIONS=D ktrace -tu your_program
> > > > > ...
> > > > > $ kdump -hu
> > > > > 
> > > > > Feedback appreciated.
> > > 
> > > I can't really comment on malloc(3) stuff, but I agree that utrace(2) is 
> > > a good 
> > > way to get information outside a pledged process.
> > > 
> > > I tend to think it is safe to use it, as the pledged process need 
> > > cooperation 
> > > from outside to exfiltrate informations (a process with permission to 
> > > call 
> > > ktrace(2) on this pid).
> > > 
> > > Please note it is a somehow generic problem: at least profiled processes 
> > > would 
> > > also get advantage of using it.
> > > 
> > > 
> > > Regarding kdump options, I think that -u option should implies -h (no 
> > > header).
> > > 
> > > Does it would make sens to considere a process using utrace(2) with 
> > > several 
> > > interleaved records for different sources ? A process with 
> > > MALLOC_OPTIONS=D and 
> > > profiling enabled for example ? An (another) option on kdump to filter on 
> > > utrace 
> > > label would be useful in such case, or have -u mandate a label to filter 
> > > on.
> > > 
> > > $ MALLOC_OPTIONS=D ktrace -tu your_program
> > > $ kdump -u mallocdumpline
> > > 
> > > and for profiling:
> > > 
> > > $ kdump -u profil > gmon.out
> > > $ gprof your_program gmon.out
> > > 
> > > Thanks.
> > 
> > Thanks! Your suggestions make a lot of sense. I'll rework the kdump
> > part to make it more flexable for different purposes.
> 
> Anothew aspect of safety is the information availble in the heap
> itself. I'm pretty sure the addresses of call sites into malloc are
> interesting to attackers. To prevent a program having access to those
> (even if they are stored inside the malloc meta data that is not
> directly accesible to a program), I'm making sure the recording only
> takes place if malloc option D is used.
> 
> This is included in a diff with the kdump changes and a few other
> things below. I'm also compiling with MALLOC_STATS if !SMALL.
> 
> usage is now:
> 
> $ MALLOC_OPTIONS=D ktrace -tu a.out 
> $ kdump -u malloc
> 

I would prefer if every utrace() call is a full line (in other words ulog
should be line buffered). It makes the regular kdump output more useable.
Right now you depend on kdump -u to put the lines back together.

Whenever I used utrace() I normally passed binary objects to the call so I
could enrich the ktrace with userland trace info.  So if kdump -u is used
for more then just mallocstats it should have a true binary mode. For
example gmon.out is a binary format so the above example by semarie@ would
not work.  As usual this can be solved in tree once that problem is hit.

> Index: lib/libc/stdlib/malloc.3
> ===================================================================
> RCS file: /home/cvs/src/lib/libc/stdlib/malloc.3,v
> retrieving revision 1.130
> diff -u -p -r1.130 malloc.3
> --- lib/libc/stdlib/malloc.3  1 Apr 2023 18:47:51 -0000       1.130
> +++ lib/libc/stdlib/malloc.3  9 Apr 2023 07:08:20 -0000
> @@ -284,10 +284,13 @@ If it has been corrupted, the process is
>  .It Cm D
>  .Dq Dump .
>  .Fn malloc
> -will dump statistics to the file
> -.Pa ./malloc.out ,
> -if it already exists,
> +will dump statistics using
> +.Xr utrace 2
>  at exit.
> +To record the dump:
> +.Dl $ MALLOC_OPTIONS=D ktrace -tu program ...
> +To view the dump:
> +.Dl $ kdump -u malloc ...
>  This option requires the library to have been compiled with -DMALLOC_STATS in
>  order to have any effect.
>  .It Cm F
> Index: lib/libc/stdlib/malloc.c
> ===================================================================
> RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v
> retrieving revision 1.280
> diff -u -p -r1.280 malloc.c
> --- lib/libc/stdlib/malloc.c  5 Apr 2023 06:25:38 -0000       1.280
> +++ lib/libc/stdlib/malloc.c  9 Apr 2023 07:08:20 -0000
> @@ -1,6 +1,6 @@
>  /*   $OpenBSD: malloc.c,v 1.280 2023/04/05 06:25:38 otto Exp $       */
>  /*
> - * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <o...@drijf.net>
> + * Copyright (c) 2008, 2010, 2011, 2016, 2023 Otto Moerbeek <o...@drijf.net>
>   * Copyright (c) 2012 Matthew Dempsky <matt...@openbsd.org>
>   * Copyright (c) 2008 Damien Miller <d...@openbsd.org>
>   * Copyright (c) 2000 Poul-Henning Kamp <p...@freebsd.org>
> @@ -23,7 +23,9 @@
>   * can buy me a beer in return. Poul-Henning Kamp
>   */
>  
> -/* #define MALLOC_STATS */
> +#ifndef SMALL
> +#define MALLOC_STATS
> +#endif
>  
>  #include <sys/types.h>
>  #include <sys/queue.h>
> @@ -39,8 +41,10 @@
>  #include <unistd.h>
>  
>  #ifdef MALLOC_STATS
> +#include <sys/types.h>
>  #include <sys/tree.h>
> -#include <fcntl.h>
> +#include <sys/ktrace.h>
> +#include <dlfcn.h>
>  #endif
>  
>  #include "thread_private.h"
> @@ -225,10 +229,14 @@ struct malloc_readonly {
>       size_t  malloc_guard;           /* use guard pages after allocations? */
>  #ifdef MALLOC_STATS
>       int     malloc_stats;           /* dump statistics at end */
> +#define DO_STATS     mopts.malloc_stats
> +#else
> +#define      DO_STATS        0
>  #endif
>       u_int32_t malloc_canary;        /* Matched against ones in pool */
>  };
>  
> +
>  /* This object is mapped PROT_READ after initialisation to prevent tampering 
> */
>  static union {
>       struct malloc_readonly mopts;
> @@ -243,15 +251,11 @@ static __dead void wrterror(struct dir_i
>      __attribute__((__format__ (printf, 2, 3)));
>  
>  #ifdef MALLOC_STATS
> -void malloc_dump(int, int, struct dir_info *);
> +void malloc_dump(void);
>  PROTO_NORMAL(malloc_dump);
> -void malloc_gdump(int);
> -PROTO_NORMAL(malloc_gdump);
>  static void malloc_exit(void);
> -#define CALLER       __builtin_return_address(0)
> -#else
> -#define CALLER       NULL
>  #endif
> +#define CALLER       (DO_STATS ? __builtin_return_address(0) : NULL)
>  
>  /* low bits of r->p determine size: 0 means >= page size and r->size holding
>   * real size, otherwise low bits is the bucket + 1
> @@ -318,9 +322,9 @@ wrterror(struct dir_info *d, char *msg, 
>       dprintf(STDERR_FILENO, "\n");
>  
>  #ifdef MALLOC_STATS
> -     if (mopts.malloc_stats)
> -             malloc_gdump(STDERR_FILENO);
> -#endif /* MALLOC_STATS */
> +     if (DO_STATS)
> +             malloc_dump();
> +#endif
>  
>       errno = saved_errno;
>  
> @@ -486,11 +490,11 @@ omalloc_init(void)
>       }
>  
>  #ifdef MALLOC_STATS
> -     if (mopts.malloc_stats && (atexit(malloc_exit) == -1)) {
> +     if (DO_STATS && (atexit(malloc_exit) == -1)) {
>               dprintf(STDERR_FILENO, "malloc() warning: atexit(2) failed."
>                   " Will not be able to dump stats on exit\n");
>       }
> -#endif /* MALLOC_STATS */
> +#endif
>  
>       while ((mopts.malloc_canary = arc4random()) == 0)
>               ;
> @@ -596,9 +600,7 @@ insert(struct dir_info *d, void *p, size
>       }
>       d->r[index].p = p;
>       d->r[index].size = sz;
> -#ifdef MALLOC_STATS
> -     d->r[index].f = f;
> -#endif
> +     STATS_SETF(&d->r[index], f);
>       d->regions_free--;
>       return 0;
>  }
> @@ -1104,12 +1106,10 @@ malloc_bytes(struct dir_info *d, size_t 
>               }
>       }
>  found:
> -#ifdef MALLOC_STATS
> -     if (i == 0 && k == 0) {
> +     if (i == 0 && k == 0 && DO_STATS) {
>               struct region_info *r = find(d, bp->page);
> -             r->f = f;
> +             STATS_SETF(r, f);
>       }
> -#endif
>  
>       *lp ^= 1 << k;
>  
> @@ -1193,6 +1193,9 @@ free_bytes(struct dir_info *d, struct re
>       info = (struct chunk_info *)r->size;
>       chunknum = find_chunknum(d, info, ptr, 0);
>  
> +     if (chunknum == 0 && DO_STATS)
> +             STATS_SETF(r, NULL);
> +
>       info->bits[chunknum / MALLOC_BITS] |= 1U << (chunknum % MALLOC_BITS);
>       info->free++;
>  
> @@ -1214,7 +1217,7 @@ free_bytes(struct dir_info *d, struct re
>       unmap(d, info->page, MALLOC_PAGESIZE, 0);
>  
>       delete(d, r);
> -             mp = &d->chunk_info_list[info->bucket];
> +     mp = &d->chunk_info_list[info->bucket];
>       LIST_INSERT_HEAD(mp, info, entries);
>  }
>  
> @@ -1694,9 +1697,11 @@ orealloc(struct dir_info **argpool, void
>       r = findpool(p, *argpool, &pool, &saved_function);
>  
>       REALSIZE(oldsz, r);
> -     if (mopts.chunk_canaries && oldsz <= MALLOC_MAXCHUNK) {
> -             info = (struct chunk_info *)r->size;
> -             chunknum = find_chunknum(pool, info, p, 0);
> +     if (oldsz <= MALLOC_MAXCHUNK) {
> +             if (DO_STATS || mopts.chunk_canaries) {
> +                     info = (struct chunk_info *)r->size;
> +                     chunknum = find_chunknum(pool, info, p, 0);
> +             }
>       }
>  
>       goldsz = oldsz;
> @@ -1808,7 +1813,8 @@ orealloc(struct dir_info **argpool, void
>                       info->bits[info->offset + chunknum] = newsz;
>                       fill_canary(p, newsz, B2SIZE(info->bucket));
>               }
> -             STATS_SETF(r, f);
> +             if (chunknum == 0 && DO_STATS)
> +                     STATS_SETF(r, f);
>               ret = p;
>       } else if (newsz != oldsz || forced) {
>               /* create new allocation */
> @@ -1825,7 +1831,8 @@ orealloc(struct dir_info **argpool, void
>               /* oldsz == newsz */
>               if (newsz != 0)
>                       wrterror(pool, "realloc internal inconsistency");
> -             STATS_SETF(r, f);
> +             if (chunknum == 0 && DO_STATS)
> +                     STATS_SETF(r, f);
>               ret = p;
>       }
>  done:
> @@ -2225,6 +2232,21 @@ aligned_alloc(size_t alignment, size_t s
>  
>  #ifdef MALLOC_STATS
>  
> +static void
> +ulog(const char *format, ...)
> +{
> +     va_list ap;
> +     char buf[100];
> +     int len;
> +
> +     va_start(ap, format);
> +     len = vsnprintf(buf, sizeof(buf), format, ap);
> +     if (len > (int)sizeof(buf))
> +             len = sizeof(buf);
> +     utrace("malloc", buf, len);
> +     va_end(ap);
> +}
> +
>  struct malloc_leak {
>       void *f;
>       size_t total_size;
> @@ -2280,21 +2302,32 @@ putleakinfo(void *f, size_t sz, int cnt)
>  static struct malloc_leak *malloc_leaks;
>  
>  static void
> -dump_leaks(int fd)
> +dump_leaks(void)
>  {
>       struct leaknode *p;
>       unsigned int i = 0;
>  
> -     dprintf(fd, "Leak report\n");
> -     dprintf(fd, "                 f     sum      #    avg\n");
> +     ulog("Leak report:\n");
> +     ulog("                 f     sum      #    avg\n");
>       /* XXX only one page of summary */
>       if (malloc_leaks == NULL)
>               malloc_leaks = MMAP(MALLOC_PAGESIZE, 0);
>       if (malloc_leaks != MAP_FAILED)
>               memset(malloc_leaks, 0, MALLOC_PAGESIZE);
>       RBT_FOREACH(p, leaktree, &leakhead) {
> -             dprintf(fd, "%18p %7zu %6u %6zu\n", p->d.f,
> -                 p->d.total_size, p->d.count, p->d.total_size / p->d.count);
> +             Dl_info info;
> +             const char *caller = p->d.f;
> +             const char *object = "?";
> +
> +             if (caller != NULL) {
> +                     if (dladdr(p->d.f, &info) != 0) {
> +                             caller -= (uintptr_t)info.dli_fbase;
> +                             object = info.dli_fname;
> +                     }
> +             }
> +             ulog("%18p %7zu %6u %6zu addr2line -e %s %p\n", p->d.f,
> +                 p->d.total_size, p->d.count, p->d.total_size / p->d.count,
> +                 object, caller);
>               if (malloc_leaks == MAP_FAILED ||
>                   i >= MALLOC_PAGESIZE / sizeof(struct malloc_leak))
>                       continue;
> @@ -2306,10 +2339,10 @@ dump_leaks(int fd)
>  }
>  
>  static void
> -dump_chunk(int fd, struct chunk_info *p, void *f, int fromfreelist)
> +dump_chunk(struct chunk_info *p, void *f, int fromfreelist)
>  {
>       while (p != NULL) {
> -             dprintf(fd, "chunk %18p %18p %4zu %d/%d\n",
> +             ulog("chunk %18p %18p %4zu %d/%d\n",
>                   p->page, ((p->bits[0] & 1) ? NULL : f),
>                   B2SIZE(p->bucket), p->free, p->total);
>               if (!fromfreelist) {
> @@ -2325,17 +2358,19 @@ dump_chunk(int fd, struct chunk_info *p,
>               }
>               p = LIST_NEXT(p, entries);
>               if (p != NULL)
> -                     dprintf(fd, "        ");
> +                     ulog("       ->");
>       }
>  }
>  
>  static void
> -dump_free_chunk_info(int fd, struct dir_info *d)
> +dump_free_chunk_info(struct dir_info *d)
>  {
>       int i, j, count;
>       struct chunk_info *p;
>  
> -     dprintf(fd, "Free chunk structs:\n");
> +     ulog("Free chunk structs:\n");
> +     ulog("Bkt) #CI                     page"
> +         "                  f size free/n\n");
>       for (i = 0; i <= BUCKETS; i++) {
>               count = 0;
>               LIST_FOREACH(p, &d->chunk_info_list[i], entries)
> @@ -2345,99 +2380,98 @@ dump_free_chunk_info(int fd, struct dir_
>                       if (p == NULL && count == 0)
>                               continue;
>                       if (j == 0)
> -                             dprintf(fd, "%3d) %3d ", i, count);
> +                             ulog("%3d) %3d ", i, count);
>                       else
> -                             dprintf(fd, "         ");
> +                             ulog("         ");
>                       if (p != NULL)
> -                             dump_chunk(fd, p, NULL, 1);
> +                             dump_chunk(p, NULL, 1);
>                       else
> -                             dprintf(fd, "\n");
> +                             ulog(".\n");
>               }
>       }
>  
>  }
>  
>  static void
> -dump_free_page_info(int fd, struct dir_info *d)
> +dump_free_page_info(struct dir_info *d)
>  {
>       struct smallcache *cache;
>       size_t i, total = 0;
>  
> -     dprintf(fd, "Cached in small cache:\n");
> +     ulog("Cached in small cache:\n");
>       for (i = 0; i < MAX_SMALLCACHEABLE_SIZE; i++) {
>               cache = &d->smallcache[i];
>               if (cache->length != 0)
> -                     dprintf(fd, "%zu(%u): %u = %zu\n", i + 1, cache->max,
> +                     ulog("%zu(%u): %u = %zu\n", i + 1, cache->max,
>                           cache->length, cache->length * (i + 1));
>               total += cache->length * (i + 1);
>       }
>  
> -     dprintf(fd, "Cached in big cache: %zu/%zu\n", d->bigcache_used,
> +     ulog("Cached in big cache: %zu/%zu\n", d->bigcache_used,
>           d->bigcache_size);
>       for (i = 0; i < d->bigcache_size; i++) {
>               if (d->bigcache[i].psize != 0)
> -                     dprintf(fd, "%zu: %zu\n", i, d->bigcache[i].psize);
> +                     ulog("%zu: %zu\n", i, d->bigcache[i].psize);
>               total += d->bigcache[i].psize;
>       }
> -     dprintf(fd, "Free pages cached: %zu\n", total);
> +     ulog("Free pages cached: %zu\n", total);
>  }
>  
>  static void
> -malloc_dump1(int fd, int poolno, struct dir_info *d)
> +malloc_dump1(int poolno, struct dir_info *d)
>  {
>       size_t i, realsize;
>  
> -     dprintf(fd, "Malloc dir of %s pool %d at %p\n", __progname, poolno, d);
> +     ulog("Malloc dir of %s pool %d at %p\n", __progname, poolno, d);
>       if (d == NULL)
>               return;
> -     dprintf(fd, "MT=%d J=%d Fl=%x\n", d->malloc_mt, d->malloc_junk, 
> d->mmap_flag);
> -     dprintf(fd, "Region slots free %zu/%zu\n",
> +     ulog("MT=%d J=%d Fl=%x\n", d->malloc_mt, d->malloc_junk, d->mmap_flag);
> +     ulog("Region slots free %zu/%zu\n",
>               d->regions_free, d->regions_total);
> -     dprintf(fd, "Finds %zu/%zu\n", d->finds, d->find_collisions);
> -     dprintf(fd, "Inserts %zu/%zu\n", d->inserts, d->insert_collisions);
> -     dprintf(fd, "Deletes %zu/%zu\n", d->deletes, d->delete_moves);
> -     dprintf(fd, "Cheap reallocs %zu/%zu\n",
> +     ulog("Finds %zu/%zu\n", d->finds, d->find_collisions);
> +     ulog("Inserts %zu/%zu\n", d->inserts, d->insert_collisions);
> +     ulog("Deletes %zu/%zu\n", d->deletes, d->delete_moves);
> +     ulog("Cheap reallocs %zu/%zu\n",
>           d->cheap_reallocs, d->cheap_realloc_tries);
> -     dprintf(fd, "Other pool searches %zu/%zu\n",
> +     ulog("Other pool searches %zu/%zu\n",
>           d->other_pool, d->pool_searches);
> -     dprintf(fd, "In use %zu\n", d->malloc_used);
> -     dprintf(fd, "Guarded %zu\n", d->malloc_guarded);
> -     dump_free_chunk_info(fd, d);
> -     dump_free_page_info(fd, d);
> -     dprintf(fd,
> -         "slot)  hash d  type               page                  f "
> +     ulog("In use %zu\n", d->malloc_used);
> +     ulog("Guarded %zu\n", d->malloc_guarded);
> +     dump_free_chunk_info(d);
> +     dump_free_page_info(d);
> +     ulog("Hash table:\n");
> +     ulog("slot)  hash d  type               page                  f "
>           "size [free/n]\n");
>       for (i = 0; i < d->regions_total; i++) {
>               if (d->r[i].p != NULL) {
>                       size_t h = hash(d->r[i].p) &
>                           (d->regions_total - 1);
> -                     dprintf(fd, "%4zx) #%4zx %zd ",
> +                     ulog("%4zx) #%4zx %zd ",
>                           i, h, h - i);
>                       REALSIZE(realsize, &d->r[i]);
>                       if (realsize > MALLOC_MAXCHUNK) {
>                               putleakinfo(d->r[i].f, realsize, 1);
> -                             dprintf(fd,
> -                                 "pages %18p %18p %zu\n", d->r[i].p,
> +                             ulog("pages %18p %18p %zu\n", d->r[i].p,
>                                   d->r[i].f, realsize);
>                       } else
> -                             dump_chunk(fd,
> +                             dump_chunk(
>                                   (struct chunk_info *)d->r[i].size,
>                                   d->r[i].f, 0);
>               }
>       }
> -     dump_leaks(fd);
> -     dprintf(fd, "\n");
> +     dump_leaks();
> +     ulog("\n");
>  }
>  
> -void
> -malloc_dump(int fd, int poolno, struct dir_info *pool)
> +static void
> +malloc_dump0(int poolno, struct dir_info *pool)
>  {
>       int i;
>       void *p;
>       struct region_info *r;
>       int saved_errno = errno;
>  
> -     if (pool == NULL)
> +     if (pool == NULL || pool->r == NULL)
>               return;
>       for (i = 0; i < MALLOC_DELAYED_CHUNK_MASK + 1; i++) {
>               p = pool->delayed_chunks[i];
> @@ -2451,50 +2485,40 @@ malloc_dump(int fd, int poolno, struct d
>       }
>       /* XXX leak when run multiple times */
>       RBT_INIT(leaktree, &leakhead);
> -     malloc_dump1(fd, poolno, pool);
> +     malloc_dump1(poolno, pool);
>       errno = saved_errno;
>  }
> -DEF_WEAK(malloc_dump);
>  
>  void
> -malloc_gdump(int fd)
> +malloc_dump(void)
>  {
>       int i;
>       int saved_errno = errno;
>  
>       for (i = 0; i < mopts.malloc_mutexes; i++)
> -             malloc_dump(fd, i, mopts.malloc_pool[i]);
> +             malloc_dump0(i, mopts.malloc_pool[i]);
>  
>       errno = saved_errno;
>  }
> -DEF_WEAK(malloc_gdump);
> +DEF_WEAK(malloc_dump);
>  
>  static void
>  malloc_exit(void)
>  {
> -     int save_errno = errno, fd;
> -     unsigned i;
> +     int save_errno = errno;
>  
> -     fd = open("malloc.out", O_RDWR|O_APPEND);
> -     if (fd != -1) {
> -             dprintf(fd, "******** Start dump %s *******\n", __progname);
> -             dprintf(fd,
> -                 "M=%u I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u "
> -                 "G=%zu\n",
> -                 mopts.malloc_mutexes,
> -                 mopts.internal_funcs, mopts.malloc_freecheck,
> -                 mopts.malloc_freeunmap, mopts.def_malloc_junk,
> -                 mopts.malloc_realloc, mopts.malloc_xmalloc,
> -                 mopts.chunk_canaries, mopts.def_maxcache,
> -                 mopts.malloc_guard);
> +     ulog("******** Start dump %s *******\n", __progname);
> +     ulog("M=%u I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u "
> +         "G=%zu\n",
> +         mopts.malloc_mutexes,
> +         mopts.internal_funcs, mopts.malloc_freecheck,
> +         mopts.malloc_freeunmap, mopts.def_malloc_junk,
> +         mopts.malloc_realloc, mopts.malloc_xmalloc,
> +         mopts.chunk_canaries, mopts.def_maxcache,
> +         mopts.malloc_guard);
>  
> -             for (i = 0; i < mopts.malloc_mutexes; i++)
> -                     malloc_dump(fd, i, mopts.malloc_pool[i]);
> -             dprintf(fd, "******** End dump %s *******\n", __progname);
> -             close(fd);
> -     } else
> -             dprintf(STDERR_FILENO,
> -                 "malloc() warning: Couldn't dump stats\n");
> +     malloc_dump();
> +     ulog("******** End dump %s *******\n", __progname);
>       errno = save_errno;
>  }
>  
> Index: usr.bin/kdump/kdump.1
> ===================================================================
> RCS file: /home/cvs/src/usr.bin/kdump/kdump.1,v
> retrieving revision 1.35
> diff -u -p -r1.35 kdump.1
> --- usr.bin/kdump/kdump.1     30 Jul 2022 07:19:30 -0000      1.35
> +++ usr.bin/kdump/kdump.1     9 Apr 2023 07:08:20 -0000
> @@ -42,6 +42,7 @@
>  .Op Fl m Ar maxdata
>  .Op Fl p Ar pid
>  .Op Fl t Ar trstr
> +.Op Fl u Ar word
>  .Sh DESCRIPTION
>  .Nm
>  displays the kernel trace files produced with
> @@ -106,6 +107,18 @@ See the
>  option of
>  .Xr ktrace 1
>  for the meaning of the letters.
> +.It Fl u Ar word
> +Display
> +.Xr utrace 2
> +records having
> +.XR utrace 2
> +header
> +.Ar word
> +as strings with
> +.Xr vis 3
> +escaping, without
> +.Xr ktrace 2
> +header information.
>  .It Fl X
>  Display I/O data with hexadecimal data and printable ASCII characters
>  side by side.
> Index: usr.bin/kdump/kdump.c
> ===================================================================
> RCS file: /home/cvs/src/usr.bin/kdump/kdump.c,v
> retrieving revision 1.156
> diff -u -p -r1.156 kdump.c
> --- usr.bin/kdump/kdump.c     17 Feb 2023 18:01:26 -0000      1.156
> +++ usr.bin/kdump/kdump.c     9 Apr 2023 07:08:20 -0000
> @@ -88,6 +88,7 @@ int needtid, tail, basecol;
>  char *tracefile = DEF_TRACEFILE;
>  struct ktr_header ktr_header;
>  pid_t pid_opt = -1;
> +char* utracefilter;
>  
>  #define eqs(s1, s2)  (strcmp((s1), (s2)) == 0)
>  
> @@ -168,7 +169,7 @@ main(int argc, char *argv[])
>                       screenwidth = 80;
>       }
>  
> -     while ((ch = getopt(argc, argv, "f:dHlm:np:RTt:xX")) != -1)
> +     while ((ch = getopt(argc, argv, "f:dHlm:np:RTt:u:xX")) != -1)
>               switch (ch) {
>               case 'f':
>                       tracefile = optarg;
> @@ -212,6 +213,9 @@ main(int argc, char *argv[])
>                       if (trpoints < 0)
>                               errx(1, "unknown trace point in %s", optarg);
>                       break;
> +             case 'u':
> +                     utracefilter = optarg;
> +                     break;
>               case 'x':
>                       iohex = 1;
>                       break;
> @@ -246,7 +250,7 @@ main(int argc, char *argv[])
>               silent = 0;
>               if (pid_opt != -1 && pid_opt != ktr_header.ktr_pid)
>                       silent = 1;
> -             if (silent == 0 && trpoints & (1<<ktr_header.ktr_type))
> +             if (utracefilter == NULL && silent == 0 && trpoints & 
> (1<<ktr_header.ktr_type))
>                       dumpheader(&ktr_header);
>               ktrlen = ktr_header.ktr_len;
>               if (ktrlen > size) {
> @@ -1254,10 +1258,18 @@ showbufc(int col, unsigned char *dp, siz
>  static void
>  showbuf(unsigned char *dp, size_t datalen)
>  {
> -     int i, j;
> +     size_t i, j;
>       int col = 0, bpl;
>       unsigned char c;
> +     char visbuf[5];
>  
> +     if (utracefilter != NULL) {
> +             for (i = 0; i < datalen; i++) {
> +                     vis(visbuf, dp[i], VIS_SAFE | VIS_OCTAL, 0);
> +                     printf("%s", visbuf);
> +             }
> +             return;
> +     }
>       if (iohex == 1) {
>               putchar('\t');
>               col = 8;
> @@ -1280,7 +1292,7 @@ showbuf(unsigned char *dp, size_t datale
>               if (bpl <= 0)
>                       bpl = 1;
>               for (i = 0; i < datalen; i += bpl) {
> -                     printf("   %04x:  ", i);
> +                     printf("   %04zx:  ", i);
>                       for (j = 0; j < bpl; j++) {
>                               if (i+j >= datalen)
>                                       printf("   ");
> @@ -1413,9 +1425,13 @@ ktruser(struct ktr_user *usr, size_t len
>       if (len < sizeof(struct ktr_user))
>               errx(1, "invalid ktr user length %zu", len);
>       len -= sizeof(struct ktr_user);
> -     printf("%.*s:", KTR_USER_MAXIDLEN, usr->ktr_id);
> -     printf(" %zu bytes\n", len);
> -     showbuf((unsigned char *)(usr + 1), len);
> +     if (utracefilter == NULL) {
> +             printf("%.*s:", KTR_USER_MAXIDLEN, usr->ktr_id);
> +             printf(" %zu bytes\n", len);
> +             showbuf((unsigned char *)(usr + 1), len);
> +     }
> +     else if (strncmp(usr->ktr_id, utracefilter, KTR_USER_MAXIDLEN) == 0)
> +             showbuf((unsigned char *)(usr + 1), len);
>  }
>  
>  static void
> @@ -1473,8 +1489,8 @@ usage(void)
>  
>       extern char *__progname;
>       fprintf(stderr, "usage: %s "
> -         "[-dHlnRTXx] [-f file] [-m maxdata] [-p pid] [-t trstr]\n",
> -         __progname);
> +         "[-dHlnRTXx] [-f file] [-m maxdata] [-p pid] [-t trstr] "
> +         "[-u word]\n", __progname);
>       exit(1);
>  }
>  
> 
> 
> 

-- 
:wq Claudio

Reply via email to