// conversions tapset // Copyright (C) 2005-2009 Red Hat Inc. // Copyright (C) 2007 Intel Corporation. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. /** * sfunction kernel_string - Retrieves string from kernel memory. * @addr: The kernel address to retrieve the string from. * * Description: Returns the null terminated C string from a given kernel * memory address. Reports an error on string copy fault. */ function kernel_string:string (addr:long) %{ /* pure */ char *destination = THIS->__retvalue; deref_string (destination, THIS->addr, MAXSTRINGLEN); if (0) { deref_fault: /* branched to from deref_string() */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel string copy fault at 0x%p", (void *) (uintptr_t) THIS->addr); CONTEXT->last_error = CONTEXT->error_buffer; } %} /** * sfunction kernel_string_n - Retrieves string of given length from kernel memory. * @addr: The kernel address to retrieve the string from. * @n: The maximum length of the string (if not null terminated). * * Description: Returns the C string of a maximum given length from a * given kernel memory address. Reports an error on string copy fault. */ function kernel_string_n:string (addr:long, n:long) %{ /* pure */ char *destination = THIS->__retvalue; int64_t len = clamp_t(int64_t, THIS->n + 1, 1, MAXSTRINGLEN); deref_string (destination, THIS->addr, len); if (0) { deref_fault: /* branched to from deref_string() */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel string copy fault at 0x%p", (void *) (uintptr_t) THIS->addr); CONTEXT->last_error = CONTEXT->error_buffer; } %} /** * sfunction kernel_long - Retrieves a long value stored in kernel memory. * @addr: The kernel address to retrieve the long from. * * Description: Returns the long value from a given kernel memory address. * Reports an error when reading from the given address fails. */ function kernel_long:long (addr:long) %{ /* pure */ THIS->__retvalue = kread((long *) (intptr_t) THIS->addr); if (0) { deref_fault: /* branched to from kread() */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel long copy fault at 0x%p", (void *) (uintptr_t) THIS->addr); CONTEXT->last_error = CONTEXT->error_buffer; } %} /** * sfunction kernel_int - Retrieves an int value stored in kernel memory. * @addr: The kernel address to retrieve the int from. * * Description: Returns the int value from a given kernel memory address. * Reports an error when reading from the given address fails. */ function kernel_int:long (addr:long) %{ /* pure */ THIS->__retvalue = kread((int *) (intptr_t) THIS->addr); if (0) { deref_fault: /* branched to from kread() */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel int copy fault at 0x%p", (void *) (uintptr_t) THIS->addr); CONTEXT->last_error = CONTEXT->error_buffer; } %} /** * sfunction kernel_short - Retrieves a short value stored in kernel memory. * @addr: The kernel address to retrieve the short from. * * Description: Returns the short value from a given kernel memory address. * Reports an error when reading from the given address fails. */ function kernel_short:long (addr:long) %{ /* pure */ THIS->__retvalue = kread((short *) (intptr_t) THIS->addr); if (0) { deref_fault: /* branched to from kread() */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel short copy fault at 0x%p", (void *) (uintptr_t) THIS->addr); CONTEXT->last_error = CONTEXT->error_buffer; } %} /** * sfunction kernel_char - Retrieves a char value stored in kernel memory. * @addr: The kernel address to retrieve the char from. * * Description: Returns the char value from a given kernel memory address. * Reports an error when reading from the given address fails. */ function kernel_char:long (addr:long) %{ /* pure */ THIS->__retvalue = kread((char *) (intptr_t) THIS->addr); if (0) { deref_fault: /* branched to from kread() */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel char copy fault at 0x%p", (void *) (uintptr_t) THIS->addr); CONTEXT->last_error = CONTEXT->error_buffer; } %} /** * sfunction user_string - Retrieves string from user space. * @addr: The user space address to retrieve the string from. * * Description: Returns the null terminated C string from a given user space * memory address. Reports "" on the rare cases when userspace * data is not accessible. */ function user_string:string (addr:long) { return user_string2 (addr, "") } /** * sfunction user_string2 - Retrieves string from user space with alternative error string.. * @addr: The user space address to retrieve the string from. * @err_msg: The error message to return when data isn't available. * * Description: Returns the null terminated C string from a given user space * memory address. Reports the given error message on the rare cases when * userspace data is not accessible. */ function user_string2:string (addr:long, err_msg:string) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (_stp_strncpy_from_user (THIS->__retvalue, (const char __user*) (uintptr_t) THIS->addr, MAXSTRINGLEN) < 0) strlcpy (THIS->__retvalue, THIS->err_msg, MAXSTRINGLEN); %} /** * sfunction user_string_warn - Retrieves string from user space. * @addr: The user space address to retrieve the string from. * * Description: Returns the null terminated C string from a given user space * memory address. Reports "" on the rare cases when userspace * data is not accessible and warns (but does not abort) about the failure. */ function user_string_warn:string (addr:long) %{ /* pure */ /* unprivileged */ long rc; assert_is_myproc(); rc = _stp_strncpy_from_user (THIS->__retvalue, (const char __user*) (uintptr_t) THIS->addr, MAXSTRINGLEN); if (rc < 0) { // NB: using error_buffer to get local space for the warning, but we're // not aborting, so leave last_error alone. snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "user string copy fault %ld at %p", rc, (void *) (uintptr_t) THIS->addr); _stp_warn(CONTEXT->error_buffer); strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); } %} /** * sfunction user_string_quoted - Retrieves and quotes string from user space. * @addr: The user space address to retrieve the string from. * * Description: Returns the null terminated C string from a given user space * memory address where any ASCII characters that are not printable are * replaced by the corresponding escape sequence in the returned string. * Reports "NULL" for address zero. Returns "" on the rare * cases when userspace data is not accessible at the given address. */ function user_string_quoted:string (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (THIS->addr == 0) strlcpy (THIS->__retvalue, "NULL", MAXSTRINGLEN); else /* XXX: stp_text_str uses sleepy __get_user() => unsafe ?! */ _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, MAXSTRINGLEN, 1, 1); %} /** * sfunction user_string_n - Retrieves string of given length from user space. * @addr: The user space address to retrieve the string from. * @n: The maximum length of the string (if not null terminated). * * Description: Returns the C string of a maximum given length from a * given user space address. Returns "" on the rare cases * when userspace data is not accessible at the given address. */ function user_string_n:string (addr:long, n:long) { return user_string_n2(addr, n, "") } /** * sfunction user_string_n2 - Retrieves string of given length from user space. * @addr: The user space address to retrieve the string from. * @n: The maximum length of the string (if not null terminated). * @err_msg: The error message to return when data isn't available. * * Description: Returns the C string of a maximum given length from a * given user space address. Returns the given error message string on * the rare cases when userspace data is not accessible at the given address. */ function user_string_n2:string (addr:long, n:long, err_msg:string) %{ /* pure */ /* unprivileged */ int64_t len = clamp_t(int64_t, THIS->n + 1, 1, MAXSTRINGLEN); assert_is_myproc(); if (_stp_strncpy_from_user(THIS->__retvalue, (char __user *) (uintptr_t) THIS->addr, len) < 0) strlcpy(THIS->__retvalue, THIS->err_msg, MAXSTRINGLEN); else THIS->__retvalue[len - 1] = '\0'; %} /** * sfunction user_string_n_warn - Retrieves string from user space. * @addr: The user space address to retrieve the string from. * @n: The maximum length of the string (if not null terminated). * * Description: Returns up to n characters of a C string from a given * user space memory address. Reports "" on the rare cases * when userspace data is not accessible and warns (but does not abort) * about the failure. */ function user_string_n_warn:string (addr:long, n:long) %{ /* pure */ /* unprivileged */ int64_t len = clamp_t(int64_t, THIS->n + 1, 1, MAXSTRINGLEN); long rc; assert_is_myproc(); rc = _stp_strncpy_from_user(THIS->__retvalue, (char __user *) (uintptr_t) THIS->addr, len); if (rc < 0) { // NB: using error_buffer to get local space for the warning, but we're // not aborting, so leave last_error alone. snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "user string copy fault %ld at %p", rc, (void *) (uintptr_t) THIS->addr); _stp_warn(CONTEXT->error_buffer); strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); } else THIS->__retvalue[len - 1] = '\0'; %} /** * sfunction user_string_quoted - Retrieves and quotes string from user space. * @addr: The user space address to retrieve the string from. * @n: The maximum length of the string (if not null terminated). * * Description: Returns up to n characters of a C string from the given * user space memory address where any ASCII characters that are not * printable are replaced by the corresponding escape sequence in the * returned string. Reports "NULL" for address zero. Returns "" * on the rare cases when userspace data is not accessible at the given * address. */ function user_string_n_quoted:string (addr:long, n:long) %{ /* pure */ /* unprivileged */ int64_t len = clamp_t(int64_t, THIS->n + 1, 1, MAXSTRINGLEN); assert_is_myproc(); if (THIS->addr == 0) strlcpy(THIS->__retvalue, "NULL", MAXSTRINGLEN); else /* XXX: stp_text_str uses sleepy __get_user() => unsafe ?! */ _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, len, 1, 1); %} /** * sfunction user_short - Retrieves a short value stored in user space. * @addr: The user space address to retrieve the short from. * * Description: Returns the short value from a given user space address. * Returns zero when user space data is not accessible. */ function user_short:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) goto fault; if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { fault: THIS->__retvalue = 0; } %} /** * sfunction user_short_warn - Retrieves a short value stored in user space. * @addr: The user space address to retrieve the short from. * * Description: Returns the short value from a given user space address. * Returns zero when user space and warns (but does not abort) about the * failure. */ function user_short_warn:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) goto fault; if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { fault: snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "user short copy fault %p", (void *) (uintptr_t) THIS->addr); _stp_warn(CONTEXT->error_buffer); THIS->__retvalue = 0; } %} /** * sfunction user_int - Retrieves an int value stored in user space. * @addr: The user space address to retrieve the int from. * * Description: Returns the int value from a given user space address. * Returns zero when user space data is not accessible. */ function user_int:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) goto fault; if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { fault: THIS->__retvalue = 0; } %} /** * sfunction user_int_warn - Retrieves an int value stored in user space. * @addr: The user space address to retrieve the int from. * * Description: Returns the int value from a given user space address. * Returns zero when user space and warns (but does not abort) about the * failure. */ function user_int_warn:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) goto fault; if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { fault: snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "user int copy fault %p", (void *) (uintptr_t) THIS->addr); _stp_warn(CONTEXT->error_buffer); THIS->__retvalue = 0; } %} /** * sfunction user_long - Retrieves a long value stored in user space. * @addr: The user space address to retrieve the long from. * * Description: Returns the long value from a given user space address. * Returns zero when user space data is not accessible. */ function user_long:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) goto fault; if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { fault: THIS->__retvalue = 0; } %} /** * sfunction user_long_warn - Retrieves a long value stored in user space. * @addr: The user space address to retrieve the long from. * * Description: Returns the long value from a given user space address. * Returns zero when user space and warns (but does not abort) about the * failure. */ function user_long_warn:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) goto fault; if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { fault: snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "user long copy fault %p", (void *) (uintptr_t) THIS->addr); _stp_warn(CONTEXT->error_buffer); THIS->__retvalue = 0; } %} /** * sfunction user_char - Retrieves a char value stored in user space. * @addr: The user space address to retrieve the char from. * * Description: Returns the char value from a given user space address. * Returns zero when user space data is not accessible. */ function user_char:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) goto fault; if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { fault: THIS->__retvalue = 0; } %} /** * sfunction user_char_warn - Retrieves a char value stored in user space. * @addr: The user space address to retrieve the char from. * * Description: Returns the char value from a given user space address. * Returns zero when user space and warns (but does not abort) about the * failure. */ function user_char_warn:long (addr:long) %{ /* pure */ /* unprivileged */ assert_is_myproc(); if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) goto fault; if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { fault: snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "user char copy fault %p", (void *) (uintptr_t) THIS->addr); _stp_warn(CONTEXT->error_buffer); THIS->__retvalue = 0; } %}