// SPDX-License-Identifier: GPL-2.0-only
/*
* lib / hexdump . c
*/
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/export.h>
#include <linux/unaligned.h>
const char hex_asc[] = "0123456789abcdef" ;
EXPORT_SYMBOL(hex_asc);
const char hex_asc_upper[] = "0123456789ABCDEF" ;
EXPORT_SYMBOL(hex_asc_upper);
/**
* hex_to_bin - convert a hex digit to its real value
* @ ch : ascii character represents hex digit
*
* hex_to_bin ( ) converts one hex digit to its actual value or - 1 in case of bad
* input .
*
* This function is used to load cryptographic keys , so it is coded in such a
* way that there are no conditions or memory accesses that depend on data .
*
* Explanation of the logic :
* ( ch - ' 9 ' - 1 ) is negative if ch < = ' 9 '
* ( ' 0 ' - 1 - ch ) is negative if ch > = ' 0 '
* we " and " these two values , so the result is negative if ch is in the range
* ' 0 ' . . . ' 9 '
* we are only interested in the sign , so we do a shift " > > 8 " ; note that right
* shift of a negative value is implementation - defined , so we cast the
* value to ( unsigned ) before the shift - - - we have 0 xffffff if ch is in
* the range ' 0 ' . . . ' 9 ' , 0 otherwise
* we " and " this value with ( ch - ' 0 ' + 1 ) - - - we have a value 1 . . . 10 if ch is
* in the range ' 0 ' . . . ' 9 ' , 0 otherwise
* we add this value to - 1 - - - we have a value 0 . . . 9 if ch is in the range ' 0 '
* . . . ' 9 ' , - 1 otherwise
* the next line is similar to the previous one , but we need to decode both
* uppercase and lowercase letters , so we use ( ch & 0 xdf ) , which converts
* lowercase to uppercase
*/
int hex_to_bin(unsigned char ch)
{
unsigned char cu = ch & 0 xdf;
return -1 +
((ch - '0' + 1 ) & (unsigned )((ch - '9' - 1 ) & ('0' - 1 - ch)) >> 8 ) +
((cu - 'A' + 11 ) & (unsigned )((cu - 'F' - 1 ) & ('A' - 1 - cu)) >> 8 );
}
EXPORT_SYMBOL(hex_to_bin);
/**
* hex2bin - convert an ascii hexadecimal string to its binary representation
* @ dst : binary result
* @ src : ascii hexadecimal string
* @ count : result length
*
* Return 0 on success , - EINVAL in case of bad input .
*/
int hex2bin(u8 *dst, const char *src, size_t count)
{
while (count--) {
int hi, lo;
hi = hex_to_bin(*src++);
if (unlikely(hi < 0 ))
return -EINVAL;
lo = hex_to_bin(*src++);
if (unlikely(lo < 0 ))
return -EINVAL;
*dst++ = (hi << 4 ) | lo;
}
return 0 ;
}
EXPORT_SYMBOL(hex2bin);
/**
* bin2hex - convert binary data to an ascii hexadecimal string
* @ dst : ascii hexadecimal result
* @ src : binary data
* @ count : binary data length
*/
char *bin2hex(char *dst, const void *src, size_t count)
{
const unsigned char *_src = src;
while (count--)
dst = hex_byte_pack(dst, *_src++);
return dst;
}
EXPORT_SYMBOL(bin2hex);
/**
* hex_dump_to_buffer - convert a blob of data to " hex ASCII " in memory
* @ buf : data blob to dump
* @ len : number of bytes in the @ buf
* @ rowsize : number of bytes to print per line ; must be 16 or 32
* @ groupsize : number of bytes to print at a time ( 1 , 2 , 4 , 8 ; default = 1 )
* @ linebuf : where to put the converted data
* @ linebuflen : total size of @ linebuf , including space for terminating NUL
* @ ascii : include ASCII after the hex output
*
* hex_dump_to_buffer ( ) works on one " line " of output at a time , i . e . ,
* 16 or 32 bytes of input data converted to hex + ASCII output .
*
* Given a buffer of u8 data , hex_dump_to_buffer ( ) converts the input data
* to a hex + ASCII dump at the supplied memory location .
* The converted output is always NUL - terminated .
*
* E . g . :
* hex_dump_to_buffer ( frame - > data , frame - > len , 16 , 1 ,
* linebuf , sizeof ( linebuf ) , true ) ;
*
* example output buffer :
* 40 41 42 43 44 45 46 47 48 49 4 a 4 b 4 c 4 d 4 e 4 f @ ABCDEFGHIJKLMNO
*
* Return :
* The amount of bytes placed in the buffer without terminating NUL . If the
* output was truncated , then the return value is the number of bytes
* ( excluding the terminating NUL ) which would have been written to the final
* string if enough space had been available .
*/
int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
char *linebuf, size_t linebuflen, bool ascii)
{
const u8 *ptr = buf;
int ngroups;
u8 ch;
int j, lx = 0 ;
int ascii_column;
int ret;
if (rowsize != 16 && rowsize != 32 )
rowsize = 16 ;
if (len > rowsize) /* limit to one line at a time */
len = rowsize;
if (!is_power_of_2(groupsize) || groupsize > 8 )
groupsize = 1 ;
if ((len % groupsize) != 0 ) /* no mixed size output */
groupsize = 1 ;
ngroups = len / groupsize;
ascii_column = rowsize * 2 + rowsize / groupsize + 1 ;
if (!linebuflen)
goto overflow1;
if (!len)
goto nil;
if (groupsize == 8 ) {
const u64 *ptr8 = buf;
for (j = 0 ; j < ngroups; j++) {
ret = snprintf(linebuf + lx, linebuflen - lx,
"%s%16.16llx" , j ? " " : "" ,
get_unaligned(ptr8 + j));
if (ret >= linebuflen - lx)
goto overflow1;
lx += ret;
}
} else if (groupsize == 4 ) {
const u32 *ptr4 = buf;
for (j = 0 ; j < ngroups; j++) {
ret = snprintf(linebuf + lx, linebuflen - lx,
"%s%8.8x" , j ? " " : "" ,
get_unaligned(ptr4 + j));
if (ret >= linebuflen - lx)
goto overflow1;
lx += ret;
}
} else if (groupsize == 2 ) {
const u16 *ptr2 = buf;
for (j = 0 ; j < ngroups; j++) {
ret = snprintf(linebuf + lx, linebuflen - lx,
"%s%4.4x" , j ? " " : "" ,
get_unaligned(ptr2 + j));
if (ret >= linebuflen - lx)
goto overflow1;
lx += ret;
}
} else {
for (j = 0 ; j < len; j++) {
if (linebuflen < lx + 2 )
goto overflow2;
ch = ptr[j];
linebuf[lx++] = hex_asc_hi(ch);
if (linebuflen < lx + 2 )
goto overflow2;
linebuf[lx++] = hex_asc_lo(ch);
if (linebuflen < lx + 2 )
goto overflow2;
linebuf[lx++] = ' ' ;
}
if (j)
lx--;
}
if (!ascii)
goto nil;
while (lx < ascii_column) {
if (linebuflen < lx + 2 )
goto overflow2;
linebuf[lx++] = ' ' ;
}
for (j = 0 ; j < len; j++) {
if (linebuflen < lx + 2 )
goto overflow2;
ch = ptr[j];
linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.' ;
}
nil:
linebuf[lx] = '\0' ;
return lx;
overflow2:
linebuf[lx++] = '\0' ;
overflow1:
return ascii ? ascii_column + len : (groupsize * 2 + 1 ) * ngroups - 1 ;
}
EXPORT_SYMBOL(hex_dump_to_buffer);
#ifdef CONFIG_PRINTK
/**
* print_hex_dump - print a text hex dump to syslog for a binary blob of data
* @ level : kernel log level ( e . g . KERN_DEBUG )
* @ prefix_str : string to prefix each line with ;
* caller supplies trailing spaces for alignment if desired
* @ prefix_type : controls whether prefix of an offset , address , or none
* is printed ( % DUMP_PREFIX_OFFSET , % DUMP_PREFIX_ADDRESS , % DUMP_PREFIX_NONE )
* @ rowsize : number of bytes to print per line ; must be 16 or 32
* @ groupsize : number of bytes to print at a time ( 1 , 2 , 4 , 8 ; default = 1 )
* @ buf : data blob to dump
* @ len : number of bytes in the @ buf
* @ ascii : include ASCII after the hex output
*
* Given a buffer of u8 data , print_hex_dump ( ) prints a hex + ASCII dump
* to the kernel log at the specified kernel log level , with an optional
* leading prefix .
*
* print_hex_dump ( ) works on one " line " of output at a time , i . e . ,
* 16 or 32 bytes of input data converted to hex + ASCII output .
* print_hex_dump ( ) iterates over the entire input @ buf , breaking it into
* " line size " chunks to format and print .
*
* E . g . :
* print_hex_dump ( KERN_DEBUG , " raw data : " , DUMP_PREFIX_ADDRESS ,
* 16 , 1 , frame - > data , frame - > len , true ) ;
*
* Example output using % DUMP_PREFIX_OFFSET and 1 - byte mode :
* 0009 ab42 : 40 41 42 43 44 45 46 47 48 49 4 a 4 b 4 c 4 d 4 e 4 f @ ABCDEFGHIJKLMNO
* Example output using % DUMP_PREFIX_ADDRESS and 4 - byte mode :
* ffffffff88089af0 : 73727170 77767574 7 b7a7978 7 f7e7d7c pqrstuvwxyz { | } ~ .
*/
void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
int rowsize, int groupsize,
const void *buf, size_t len, bool ascii)
{
const u8 *ptr = buf;
int i, linelen, remaining = len;
unsigned char linebuf[32 * 3 + 2 + 32 + 1 ];
if (rowsize != 16 && rowsize != 32 )
rowsize = 16 ;
for (i = 0 ; i < len; i += rowsize) {
linelen = min(remaining, rowsize);
remaining -= rowsize;
hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
linebuf, sizeof (linebuf), ascii);
switch (prefix_type) {
case DUMP_PREFIX_ADDRESS:
printk("%s%s%p: %s\n" ,
level, prefix_str, ptr + i, linebuf);
break ;
case DUMP_PREFIX_OFFSET:
printk("%s%s%.8x: %s\n" , level, prefix_str, i, linebuf);
break ;
default :
printk("%s%s%s\n" , level, prefix_str, linebuf);
break ;
}
}
}
EXPORT_SYMBOL(print_hex_dump);
#endif /* defined(CONFIG_PRINTK) */
Messung V0.5 in Prozent C=97 H=65 G=82
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland