Add support for attempting returns from panic
[akaros.git] / kern / src / printfmt.c
index 4bbceb2..b64625e 100644 (file)
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <kthread.h>
+#include <syscall.h>
 #include <ns.h>
 
 /* Print a number (base <= 16) in reverse order,
@@ -130,17 +131,6 @@ void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_li
                        putch(va_arg(ap, int), putdat);
                        break;
 
-               // error message
-               case 'e':
-                       err = va_arg(ap, int);
-                       if (err < 0)
-                               err = -err;
-                       if (err >= NUMERRORS)
-                               printfmt(putch, putdat, "error %d(%s)", err, get_cur_errbuf());
-                       else
-                               printfmt(putch, putdat, "%s (%s)", error_string[err], get_cur_errbuf());
-                       break;
-
                case 'E': // ENET MAC
                        if ((mac = va_arg(ap, uint8_t *)) == NULL){
                                char *s = "00:00:00:00:00:00";
@@ -268,7 +258,6 @@ void printfmt(void (*putch)(int, void**), void **putdat, const char *fmt, ...)
        va_start(ap, fmt);
        vprintfmt(putch, putdat, fmt, ap);
        va_end(ap);
-       check_poison("printfmt");
 }
 
 typedef struct sprintbuf {
@@ -284,13 +273,22 @@ static void sprintputch(int ch, sprintbuf_t **b)
        (*b)->cnt++;
 }
 
-int vsnprintf(char *buf, int n, const char *fmt, va_list ap)
+int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap)
 {
        sprintbuf_t b;// = {buf, buf+n-1, 0};
        sprintbuf_t *bp = &b;
 
        /* this isn't quite the snprintf 'spec', but errors aren't helpful */
-       if (buf == NULL || n < 1)
+       assert(buf);
+       /* We might get large, 'negative' values for code that repeatedly calls
+        * snprintf(), e.g.:
+        *              len += snprintf(buf + len, bufsz - len, "foo");
+        *              len += snprintf(buf + len, bufsz - len, "bar");
+        * If len > bufsz, that will appear as a large value.  This is not quite the
+        * glibc semantics (we aren't returning the size we would have printed), but
+        * it short circuits the rest of the function and avoids potential errors in
+        * the putch() functions. */
+       if (!n || (n > INT32_MAX))
                return 0;
 
        b.buf = NULL; // zra : help out the Deputy optimizer a bit
@@ -306,7 +304,7 @@ int vsnprintf(char *buf, int n, const char *fmt, va_list ap)
        return b.cnt;
 }
 
-int snprintf(char *buf, int n, const char *fmt, ...)
+int snprintf(char *buf, size_t n, const char *fmt, ...)
 {
        va_list ap;
        int rc;
@@ -315,27 +313,32 @@ int snprintf(char *buf, int n, const char *fmt, ...)
        rc = vsnprintf(buf, n, fmt, ap);
        va_end(ap);
 
-       check_poison("snprintf");
        return rc;
 }
 
-/* convenience function: do a print, return the pointer to the end. */
+/* Convenience function: do a print, return the pointer to the null at the end.
+ *
+ * Unlike snprintf(), when we overflow, this doesn't return the 'end' where we
+ * would have written to.  Instead, we'll return 'end - 1', which is the last
+ * byte, and enforce the null-termination.  */
 char *seprintf(char *buf, char *end, const char *fmt, ...)
 {
        va_list ap;
        int rc;
-       int n = end - buf;
-
-       if (n <= 0)
-               return buf;
+       size_t n = end - buf;
 
        va_start(ap, fmt);
        rc = vsnprintf(buf, n, fmt, ap);
        va_end(ap);
-       check_poison("seprintf");
 
-       if (rc >= 0)
-               return buf + rc;
-       else
+       /* Some error - leave them where they were. */
+       if (rc < 0)
                return buf;
+       /* Overflow - put them at the end */
+       if (rc >= n) {
+               *(end - 1) = '\0';
+               return end - 1;
+       }
+       assert(buf[rc] == '\0');
+       return buf + rc;
 }