HelenOS sources

root/kernel/generic/src/debug/util.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. read_byte
  2. read_uint16
  3. read_uint24
  4. read_uint32
  5. read_uint64
  6. read_uint
  7. read_uleb128
  8. read_sleb128
  9. skip_leb128
  10. read_initial_length
  11. read_string
  12. skip_string
  13. safe_increment
  14. skip_format
  15. skip_formatted_entry
  16. skip_formatted_list

/*
 * Copyright (c) 2023 Jiří Zárevúcky
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef DEBUG_UTIL_H_
#define DEBUG_UTIL_H_

#include <assert.h>
#include <stdint.h>
#include <debug/constants.h>
#include <debug/sections.h>
#include <debug.h>

#define DEBUGF dummy_printf

extern bool skip_data(unsigned, const uint8_t **const, const uint8_t *, unsigned);
extern void print_format(const char *, const uint8_t *, const uint8_t *);
extern void print_formatted_list(debug_sections_t *, const char *,
    const uint8_t *, const uint8_t *, const uint8_t *, const uint8_t *, unsigned);

extern void print_block(const uint8_t **, const uint8_t *, unsigned);
extern void print_formed_data(debug_sections_t *scs, unsigned, const uint8_t **const, const uint8_t *, unsigned);

static inline uint8_t read_byte(const uint8_t **data, const uint8_t *data_end)
{
        if (*data >= data_end) {
                return 0;
        } else {
                return *((*data)++);
        }
}

/* Casting to these structures allows us to read unaligned integers safely. */
struct u16 {
        uint16_t val;
} __attribute__((packed));

struct u32 {
        uint32_t val;
} __attribute__((packed));

struct u64 {
        uint64_t val;
} __attribute__((packed));

static inline uint16_t read_uint16(const uint8_t **data, const uint8_t *data_end)
{
        if (*data + 2 > data_end) {
                /* Safe exit path for malformed input. */
                *data = data_end;
                return 0;
        }

        uint16_t v = ((struct u16 *) *data)->val;
        *data += 2;
        return v;
}

static inline uint32_t read_uint24(const uint8_t **data, const uint8_t *data_end)
{
        if (*data + 3 > data_end) {
                /* Safe exit path for malformed input. */
                *data = data_end;
                return 0;
        }

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        uint32_t v = (*data)[0] | (*data)[1] << 8 | (*data)[2] << 16;
#else
        uint32_t v = (*data)[2] | (*data)[1] << 8 | (*data)[0] << 16;
#endif

        *data += 3;
        return v;
}

static inline uint32_t read_uint32(const uint8_t **data, const uint8_t *data_end)
{
        if (*data + 4 > data_end) {
                /* Safe exit path for malformed input. */
                *data = data_end;
                return 0;
        }

        uint32_t v = ((struct u32 *) *data)->val;
        *data += 4;
        return v;
}

static inline uint64_t read_uint64(const uint8_t **data, const uint8_t *data_end)
{
        if (*data + 8 > data_end) {
                /* Safe exit path for malformed input. */
                *data = data_end;
                return 0;
        }

        uint64_t v = ((struct u64 *) *data)->val;
        *data += 8;
        return v;
}

static inline uint64_t read_uint(const uint8_t **data, const uint8_t *data_end, unsigned bytes)
{
        switch (bytes) {
        case 1:
                return read_byte(data, data_end);
        case 2:
                return read_uint16(data, data_end);
        case 4:
                return read_uint32(data, data_end);
        case 8:
                return read_uint64(data, data_end);
        default:
                panic("unimplemented");
        }
}

static inline uint64_t read_uleb128(const uint8_t **data, const uint8_t *data_end)
{
        uint64_t result = 0;
        unsigned shift = 0;

        while (*data < data_end) {
                uint8_t byte = *((*data)++);
                result |= (byte & 0x7f) << shift;
                shift += 7;

                if ((byte & 0x80) == 0)
                        break;
        }

        return result;
}

static inline int64_t read_sleb128(const uint8_t **data, const uint8_t *data_end)
{
        uint64_t result = 0;
        unsigned shift = 0;

        while (*data < data_end) {
                uint8_t byte = *((*data)++);
                result |= (byte & 0x7f) << shift;
                shift += 7;

                if ((byte & 0x80) == 0) {
                        if (shift < 64 && (byte & 0x40) != 0) {
                                /* sign extend */
                                result |= -(1 << shift);
                        }
                        break;
                }
        }

        return (int64_t) result;
}

static inline void skip_leb128(const uint8_t **data, const uint8_t *data_end)
{
        while (*data < data_end) {
                uint8_t byte = *((*data)++);
                if ((byte & 0x80) == 0)
                        break;
        }
}

static inline uint64_t read_initial_length(const uint8_t **data, const uint8_t *data_end, unsigned *width)
{
        uint32_t initial = read_uint32(data, data_end);
        if (initial == 0xffffffffu) {
                *width = 8;
                return read_uint64(data, data_end);
        } else {
                *width = 4;
                return initial;
        }
}

static inline const char *read_string(const uint8_t **data, const uint8_t *data_end)
{
        const char *start = (const char *) *data;

        // NUL-terminated string.
        while (*data < data_end && **data != 0)
                (*data)++;

        if (*data < data_end) {
                // Skip the terminating zero.
                (*data)++;
                return start;
        } else {
                // No terminating zero, we can't use this.
                return NULL;
        }
}

static inline void skip_string(const uint8_t **data, const uint8_t *data_end)
{
        (void) read_string(data, data_end);
}

static inline void safe_increment(const uint8_t **data,
    const uint8_t *data_end, ptrdiff_t increment)
{
        assert(data_end >= *data);

        if (increment >= data_end - *data) {
                *data = data_end;
        } else {
                (*data) += increment;
        }
}

static inline void skip_format(const uint8_t **data, const uint8_t *const data_end,
    unsigned count)
{
        for (unsigned i = 0; i < count; i++) {
                (void) read_uleb128(data, data_end);
                (void) read_uleb128(data, data_end);
        }
}

static inline void skip_formatted_entry(const uint8_t **data, const uint8_t *const data_end,
    const uint8_t *format, const uint8_t *format_end, unsigned width)
{
        while (format < format_end) {
                /* Ignore content type code */
                (void) read_uleb128(&format, format_end);

                uint64_t form = read_uleb128(&format, format_end);
                skip_data(form, data, data_end, width);
        }
}

static inline void skip_formatted_list(const uint8_t **data, const uint8_t *const data_end,
    unsigned count,     const uint8_t *format, const uint8_t *format_end,
    unsigned width)
{
        for (unsigned i = 0; i < count; i++) {
                skip_formatted_entry(data, data_end, format, format_end, width);
        }
}

#endif /* DEBUG_UTIL_H_ */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub