Add kvm_readstr, a convenience helper which lets you read C strings from
authorSimon Schubert <corecode@dragonflybsd.org>
Wed, 11 Jan 2006 01:12:59 +0000 (01:12 +0000)
committerSimon Schubert <corecode@dragonflybsd.org>
Wed, 11 Jan 2006 01:12:59 +0000 (01:12 +0000)
kernel cores/kmem.

lib/libkvm/kvm.c
lib/libkvm/kvm.h
lib/libkvm/kvm_read.3

index cec47b4..b7cbf2c 100644 (file)
@@ -36,7 +36,7 @@
  *
  * @(#)kvm.c   8.2 (Berkeley) 2/13/94
  * $FreeBSD: src/lib/libkvm/kvm.c,v 1.12.2.3 2002/09/13 14:53:43 nectar Exp $
- * $DragonFly: src/lib/libkvm/kvm.c,v 1.7 2005/10/24 19:59:51 dillon Exp $
+ * $DragonFly: src/lib/libkvm/kvm.c,v 1.8 2006/01/11 01:12:59 corecode Exp $
  */
 
 #include <sys/param.h>
@@ -388,6 +388,103 @@ kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len)
        /* NOTREACHED */
 }
 
+char *
+kvm_readstr(kvm_t *kd, u_long kva, char *buf, size_t *lenp)
+{
+       size_t len, cc, pos;
+       char ch;
+       int asize = -1;
+
+       if (buf == NULL) {
+               asize = len = 16;
+               buf = malloc(len);
+               if (buf == NULL) {
+                       _kvm_syserr(kd, kd->program, "kvm_readstr");
+                       return NULL;
+               }
+       } else {
+               len = *lenp;
+       }
+
+       if (ISALIVE(kd)) {
+               /*
+                * We're using /dev/kmem.  Just read straight from the
+                * device and let the active kernel do the address translation.
+                */
+               errno = 0;
+               if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
+                       _kvm_err(kd, 0, "invalid address (%x)", kva);
+                       return NULL;
+               }
+
+               for (pos = 0, ch = -1; ch != 0; pos++) {
+                       cc = read(kd->vmfd, &ch, 1);
+                       if ((ssize_t)cc < 0) {
+                               _kvm_syserr(kd, 0, "kvm_readstr");
+                               return NULL;
+                       } else if (cc < 1)
+                               _kvm_err(kd, kd->program, "short read");
+                       if (pos == asize) {
+                               buf = realloc(buf, asize *= 2);
+                               if (buf == NULL) {
+                                       _kvm_syserr(kd, kd->program, "kvm_readstr");
+                                       return NULL;
+                               }
+                               len = asize;
+                       }
+                       if (pos < len)
+                               buf[pos] = ch;
+               }
+
+               if (lenp != NULL)
+                       *lenp = pos;
+               if (pos > len)
+                       return NULL;
+               else
+                       return buf;
+       } else {
+               size_t left = 0;
+               for (pos = 0, ch = -1; ch != 0; pos++, left--, kva++) {
+                       if (left == 0) {
+                               u_long pa;
+
+                               left = _kvm_kvatop(kd, kva, &pa);
+                               if (left == 0)
+                                       return NULL;
+                               errno = 0;
+                               if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
+                                       _kvm_syserr(kd, 0, _PATH_MEM);
+                                       return NULL;
+                               }
+                       }
+                       cc = read(kd->vmfd, &ch, 1);
+                       if ((ssize_t)cc < 0) {
+                               _kvm_syserr(kd, 0, "kvm_readstr");
+                               return NULL;
+                       } else if (cc < 1)
+                               _kvm_err(kd, kd->program, "short read");
+                       if (pos == asize) {
+                               buf = realloc(buf, asize *= 2);
+                               if (buf == NULL) {
+                                       _kvm_syserr(kd, kd->program, "kvm_readstr");
+                                       return NULL;
+                               }
+                               len = asize;
+                       }
+                       if (pos < len)
+                               buf[pos] = ch;
+               }
+
+               if (lenp != NULL)
+                       *lenp = pos;
+               if (pos > len)
+                       return NULL;
+               else
+                       return buf;
+       }
+       /* NOTREACHED */
+}
+
 ssize_t
 kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
 {
index 09b3c35..c71e9f8 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)kvm.h       8.1 (Berkeley) 6/2/93
  * $FreeBSD: src/lib/libkvm/kvm.h,v 1.11 1999/08/27 23:44:50 peter Exp $
- * $DragonFly: src/lib/libkvm/kvm.h,v 1.5 2004/04/02 05:46:02 hmp Exp $
+ * $DragonFly: src/lib/libkvm/kvm.h,v 1.6 2006/01/11 01:12:59 corecode Exp $
  */
 
 #ifndef _KVM_H_
@@ -81,6 +81,7 @@ kvm_t  *kvm_open
 kvm_t   *kvm_openfiles
            (const char *, const char *, const char *, int, char *);
 __ssize_t        kvm_read (kvm_t *, unsigned long, void *, __size_t);
+char    *kvm_readstr(kvm_t *, u_long, char *, size_t *);
 __ssize_t        kvm_uread
            (kvm_t *, const struct proc *, unsigned long, char *, __size_t);
 __ssize_t        kvm_write (kvm_t *, unsigned long, const void *, __size_t);
index 9f61ed5..e718675 100644 (file)
@@ -35,9 +35,9 @@
 .\"
 .\"     @(#)kvm_read.3 8.1 (Berkeley) 6/4/93
 .\" $FreeBSD: src/lib/libkvm/kvm_read.3,v 1.6.2.3 2001/12/17 10:08:30 ru Exp $
-.\" $DragonFly: src/lib/libkvm/kvm_read.3,v 1.2 2003/06/17 04:26:49 dillon Exp $
+.\" $DragonFly: src/lib/libkvm/kvm_read.3,v 1.3 2006/01/11 01:12:59 corecode Exp $
 .\"
-.Dd June 4, 1993
+.Dd January 8, 2006
 .Dt KVM_READ 3
 .Os
 .Sh NAME
 .In kvm.h
 .Ft ssize_t
 .Fn kvm_read "kvm_t *kd" "unsigned long addr" "void *buf" "size_t nbytes"
+.Ft "char *"
+.Fn kvm_readstr "kvm_t *kd" "unsigned long addr" "char *buf" "size_t *len"
 .Ft ssize_t
 .Fn kvm_write "kvm_t *kd" "unsigned long addr" "const void *buf" "size_t nbytes"
 .Sh DESCRIPTION
 The
-.Fn kvm_read
+.Fn kvm_read ,
+.Fn kvm_readstr
 and
 .Fn kvm_write
 functions are used to read and write kernel virtual memory (or a crash
@@ -81,9 +84,54 @@ to
 .Fa addr .
 Unlike their SunOS counterparts, these functions cannot be used to
 read or write process address spaces.
+.Pp
+The
+.Fn kvm_readstr
+function exists for convenience to read NUL terminated strings
+from the kernel address space.
+If
+.Fa buf
+is
+.Dv NULL ,
+.Fn kvm_readstr
+will allocate a sufficiently large buffer, which needs to be
+deallocated via
+.Xr free 3
+by the caller.
+If
+.Fa len
+is not
+.Dv NULL ,
+.Fn kvm_readstr
+will interpret the value it is pointing to as the size of
+.Fa buf
+and will store the size of the complete string at
+.Fa addr .
+Note that if only
+.Fa buf
+is too small to hold the complete string,
+.Fn kvm_readstr
+will return
+.Dv NULL
+but set
+.Fa len
+to the size needed.
 .Sh RETURN VALUES
-Upon success, the number of bytes actually transferred is returned.
+For
+.Fn kvm_read
+and
+.Fn kvm_write
+the number of bytes actually transferred is returned, if the request
+was successful.
 Otherwise, -1 is returned.
+.Pp
+For
+.Fn kvm_readstr
+.Dv NULL
+is returned on failure.
+Upon success, the address of the string is returned, which will be
+.Fa buf
+if this was supplied.
 .Sh SEE ALSO
 .Xr kvm 3 ,
 .Xr kvm_close 3 ,