/*
  Copyright (C) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
  Portions Copyright 2011-2020 David Anderson. All Rights Reserved.

  This program is free software; you can redistribute it
  and/or modify it under the terms of version 2.1 of the
  GNU Lesser General Public License as published by the Free
  Software Foundation.

  This program is distributed in the hope that it would be
  useful, but WITHOUT ANY WARRANTY; without even the implied
  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  Further, this software is distributed without any warranty
  that it is free of the rightful claim of any third person
  regarding infringement or the like.  Any license provided
  herein, whether implied or otherwise, applies only to this
  software file.  Patent licenses, if any, provided herein
  do not apply to combinations of this program with other
  software, or any other product whatsoever.

  You should have received a copy of the GNU Lesser General
  Public License along with this program; if not, write the
  Free Software Foundation, Inc., 51 Franklin Street - Fifth
  Floor, Boston MA 02110-1301, USA.

*/

#include <config.h>

#include <stddef.h> /* size_t */

#if defined(_WIN32) && defined(HAVE_STDAFX_H)
#include "stdafx.h"
#endif /* HAVE_STDAFX_H */

#include "dwarf.h"
#include "libdwarf.h"
#include "libdwarf_private.h"
#include "dwarf_base_types.h"
#include "dwarf_opaque.h"
#include "dwarf_error.h"
#include "dwarf_util.h"

#define MORE_BYTES      0x80
#define DATA_MASK       0x7f
#define DIGIT_WIDTH     7
#define SIGN_BIT        0x40

/*  Note that with 'make check')
    many of the test items
    only make sense if Dwarf_Unsigned (and Dwarf_Signed)
    are 64 bits.  The encode/decode logic should
    be fine whether those types are 64 or 32 bits.
    See runtests.sh */

/* The encode/decode functions here are public */

/*  10 bytes of leb, 7 bits each part of the number, gives
    room for a 64bit number.
    While any number of leading zeroes would be legal, so
    no max is really truly required here, why would a
    compiler generate leading zeros (for unsigned leb)?
    That would seem strange except in rare circumstances
    a compiler may want, for overall alignment, to
    add extra bytes..

    So we allow more than 10 as it is legal for a compiler to
    generate an leb with correct but useless trailing
    zero bytes (note the interaction with sign in the signed case).
    The value of BYTESLEBMAX is arbitrary but allows catching
    corrupt data in a short time.
    Before April 2021 BYTESLEBMAX was 10 as it was assumed
    there were no 'useless' 0x80 high-order bytes in an LEB.
    (0x80 meaning the 7 bits 'value' is zero)
    However in DWARF6 (and at least one compiler before
    DWARF6) a few high order bytes are allowed as padding.

*/
#define BYTESLEBMAX 24
#define BITSPERBYTE 8

/*  When an leb value needs to reveal its length,
    but the value is not needed  */
int
_dwarf_skip_leb128(char * leb128,
    Dwarf_Unsigned * leb128_length,
    char * endptr)
{
    unsigned   byte        = 0;
    /*  The byte_length value will be a small non-negative integer. */
    unsigned   byte_length = 1;

    if (leb128 >=endptr) {
        return DW_DLV_ERROR;
    }

    byte = *(unsigned char *)leb128;
    if ((byte & 0x80) == 0) {
        *leb128_length = 1;
        return DW_DLV_OK;
    } else {
        unsigned       byte2  = 0;
        if ((leb128+1) >=endptr) {
            return DW_DLV_ERROR;
        }
        byte2 = *(unsigned char *)(leb128 + 1);
        if ((byte2 & 0x80) == 0) {
            *leb128_length = 2;
            return DW_DLV_OK;
        }
        /*  Gets messy to hand-inline more byte checking.
            One or two byte leb is very frequent. */
    }

    ++byte_length;
    ++leb128;
    /*  Validity of leb128+1 checked above */
    for (;;byte_length++,leb128++) {
        if (leb128 >= endptr) {
            /*  Off end of available space. */
            return DW_DLV_ERROR;
        }
        byte = *(unsigned char *)leb128;
        if (byte & 0x80) {
            if (byte_length >=  BYTESLEBMAX)  {
                /*  Too long. Not sane length. */
                return DW_DLV_ERROR;
            }
            continue;
        }
        break;
    }
    *leb128_length = byte_length;
    return DW_DLV_OK;
}
/*  Decode ULEB with checking.
    Casting leb128 to (unsigned char *) as
    the signedness of char * is unpredictable in C */
int
dwarf_decode_leb128(char * leb128,
    Dwarf_Unsigned * leb128_length,
    Dwarf_Unsigned *outval,
    char * endptr)
{
    unsigned long  byte        = 0;
    Dwarf_Unsigned word_number = 0;
    Dwarf_Unsigned number      = 0;
    unsigned long  shift       = 0; /* at least 32 bits, even Win32 */
    /*  The byte_length value will be a small non-negative integer. */
    unsigned int   byte_length       = 0;

    if (leb128 >=endptr) {
        return DW_DLV_ERROR;
    }
    /*  The following unrolls-the-loop for the first two bytes and
        unpacks into 32 bits to make this as fast as possible.
        word_number is assumed big enough that the shift has a defined
        result. */
    byte = *(unsigned char *)leb128;
    if ((byte & 0x80) == 0) {
        if (leb128_length) {
            *leb128_length = 1;
        }
        if (outval) {
            *outval = byte;
        }
        return DW_DLV_OK;
    } else {
        unsigned long byte2        = 0;
        if ((leb128+1) >=endptr) {
            return DW_DLV_ERROR;
        }
        byte2 =  *(unsigned char *)(leb128 + 1);
        if ((byte2 & 0x80) == 0) {
            if (leb128_length) {
                *leb128_length = 2;
            }
            word_number =  byte & 0x7f;
            word_number |= (byte2 & 0x7f) << 7;
            if (outval) {
                *outval = word_number;
            }
            return DW_DLV_OK;
        }
        /* Gets messy to hand-inline more byte checking. */
    }

    /*  The rest handles long numbers. Because the 'number'
        may be larger than the default int/unsigned,
        we must cast the 'byte' before
        the shift for the shift to have a defined result. */
    number = 0;
    shift = 0;
    byte_length = 1;
    for (;;) {
        unsigned int b = byte & 0x7f;
        if (shift >= (sizeof(number)*BITSPERBYTE)) {
            /*  Shift is large. Maybe corrupt value,
                maybe some padding high-end byte zeroes
                that we can ignore. */
            if (!b) {
                if (byte_length >= BYTESLEBMAX) {
                    /*  Erroneous input.  */
                    if (leb128_length) {
                        *leb128_length = BYTESLEBMAX;
                    }
                    return DW_DLV_ERROR;
                }
                ++leb128;
                /*  shift cannot overflow as
                    BYTESLEBMAX is not a large value */
                shift += 7;
                if (leb128 >=endptr ) {
                    if (leb128 == endptr && !byte) {
                        /* Meaning zero bits a padding byte */
                        if (leb128_length) {
                            *leb128_length = byte_length;
                        }
                        if (outval) {
                            *outval = number;
                        }
                        return DW_DLV_OK;
                    }
                    return DW_DLV_ERROR;
                }
                ++byte_length;
                byte = *(unsigned char *)leb128;
                continue;
            }
            /*  Too big, corrupt data given the non-zero
                byte content */
            return DW_DLV_ERROR;
        }
        number |= ((Dwarf_Unsigned)b << shift);
        if ((byte & 0x80) == 0) {
            if (leb128_length) {
                *leb128_length = byte_length;
            }
            if (outval) {
                *outval = number;
            }
            return DW_DLV_OK;
        }
        shift += 7;
        byte_length++;
        if (byte_length > BYTESLEBMAX) {
            /*  Erroneous input.  */
            if (leb128_length) {
                *leb128_length = BYTESLEBMAX;
            }
            break;
        }
        ++leb128;
        if (leb128 >= endptr) {
            return DW_DLV_ERROR;
        }
        byte = *(unsigned char *)leb128;
    }
    return DW_DLV_ERROR;
}

/*  Decode SLEB with checking
    Casting leb128 to (unsigned char *) as
    the signedness of char * is unpredictable
    in C */
int
dwarf_decode_signed_leb128(char * leb128,
    Dwarf_Unsigned * leb128_length,
    Dwarf_Signed *outval,char * endptr)
{
    Dwarf_Unsigned byte   = 0;
    unsigned int   b      = 0;
    Dwarf_Signed   number = 0;
    unsigned long  shift  = 0;
    int            sign   = FALSE;
    /*  The byte_length value will be a small non-negative integer. */
    unsigned int   byte_length = 1;

    /*  byte_length being the number of bytes
        of data absorbed so far in
        turning the leb into a Dwarf_Signed. */
    if (!outval) {
        return DW_DLV_ERROR;
    }
    if (leb128 >= endptr) {
        return DW_DLV_ERROR;
    }
    byte   = *(unsigned char *)leb128;
    for (;;) {
        b = byte & 0x7f;
        if (shift >= (sizeof(number)*BITSPERBYTE)) {
            /*  Shift is large. Maybe corrupt value,
                maybe some padding high-end byte zeroes
                that we can ignore (but notice sign bit
                from the last usable byte). */
            sign =  b & 0x40;
            if (!byte || byte == 0x40) {
                /*  The value is complete. */
                break;
            }
            if (b == 0) {
                ++byte_length;
                if (byte_length > BYTESLEBMAX) {
                    /*  Erroneous input.  */
                    if (leb128_length) {
                        *leb128_length = BYTESLEBMAX;
                    }
                    return DW_DLV_ERROR;
                }
                ++leb128;
                /*  shift cannot overflow as
                    BYTESLEBMAX is not a large value */
                shift += 7;
                if (leb128 >= endptr) {
                    return DW_DLV_ERROR;
                }
                byte = *(unsigned char *)leb128;
                continue;
            }
            /*  Too big, corrupt data given the non-zero
                byte content */
            return DW_DLV_ERROR;
        }
        /*  This bit of the last byte indicates sign */
        sign =  b & 0x40;
        number |= ((Dwarf_Unsigned)b) << shift;
        shift += 7;
        if ((byte & 0x80) == 0) {
            break;
        }
        ++leb128;
        if (leb128 >= endptr) {
            return DW_DLV_ERROR;
        }
        byte = *(unsigned char *)leb128;
        byte_length++;
        if (byte_length > BYTESLEBMAX) {
            /*  Erroneous input. */
            if (leb128_length) {
                *leb128_length = BYTESLEBMAX;
            }
            return DW_DLV_ERROR;
        }
    }
    if (sign) {
        /* The following avoids undefined behavior. */
        unsigned int shiftlim = sizeof(Dwarf_Signed) * BITSPERBYTE -1;
        if (shift < shiftlim) {
            Dwarf_Signed y = (Dwarf_Signed)
                (((Dwarf_Unsigned)1) << shift);
            Dwarf_Signed x = -y;
            number |= x;
        } else if (shift == shiftlim) {
            Dwarf_Signed x= (((Dwarf_Unsigned)1) << shift);
            number |= x;
        } else {
            /* trailing zeroes case */
            Dwarf_Signed x= (((Dwarf_Unsigned)1) << shiftlim);
            number |= x;
        }
    }
    if (leb128_length) {
        *leb128_length = byte_length;
    }
    *outval = number;
    return DW_DLV_OK;
}

/*  Encode val as a uleb128. This encodes it as an unsigned
    number.
    Return DW_DLV_ERROR or DW_DLV_OK.
    space to write leb number is provided by caller, with caller
    passing length.
    number of bytes used returned thru nbytes arg.
    This never emits padding, it emits the minimum
    number of bytes that can hold the value. */
int dwarf_encode_leb128(Dwarf_Unsigned val, int *nbytes,
    char *space, int splen)
{
    char *a;
    char *end = space + splen;

    a = space;
    do {
        unsigned char uc;

        if (a >= end) {
            return DW_DLV_ERROR;
        }
        uc = val & DATA_MASK;
        val >>= DIGIT_WIDTH;
        if (val != 0) {
            uc |= MORE_BYTES;
        }
        *a = uc;
        a++;
    } while (val);
    *nbytes = (int)(a - space);
    return DW_DLV_OK;
}

/*  This never emits padding at the end, so it
    says nothing about what such would look like
    for a negative value. */
int dwarf_encode_signed_leb128(Dwarf_Signed value, int *nbytes,
    char *space, int splen)
{
    char *str;
    Dwarf_Signed sign = -(value < 0);
    int more = 1;
    char *end = space + splen;

    str = space;

    do {
        unsigned char byte = value & DATA_MASK;

        value >>= DIGIT_WIDTH;

        if (str >= end) {
            return DW_DLV_ERROR;
        }
        /*  Remaining chunks would just contain the sign
            bit, and this chunk
            has already captured at least one sign bit.  */
        if (value == sign &&
            ((byte & SIGN_BIT) == (sign & SIGN_BIT))) {
            more = 0;
        } else {
            byte |= MORE_BYTES;
        }
        *str = byte;
        str++;
    } while (more);
    *nbytes = (int)(str - space);
    return DW_DLV_OK;
}
