Blame source/uds/loggerLinuxKernel.c

Packit Service 310c69
/*
Packit Service 310c69
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service 310c69
 *
Packit Service 310c69
 * This program is free software; you can redistribute it and/or
Packit Service 310c69
 * modify it under the terms of the GNU General Public License
Packit Service 310c69
 * as published by the Free Software Foundation; either version 2
Packit Service 310c69
 * of the License, or (at your option) any later version.
Packit Service 310c69
 * 
Packit Service 310c69
 * This program is distributed in the hope that it will be useful,
Packit Service 310c69
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 310c69
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 310c69
 * GNU General Public License for more details.
Packit Service 310c69
 * 
Packit Service 310c69
 * You should have received a copy of the GNU General Public License
Packit Service 310c69
 * along with this program; if not, write to the Free Software
Packit Service 310c69
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 310c69
 * 02110-1301, USA. 
Packit Service 310c69
 *
Packit Service 310c69
 * $Id: //eng/uds-releases/jasper/kernelLinux/uds/loggerLinuxKernel.c#2 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include <linux/delay.h>
Packit Service 310c69
#include <linux/hardirq.h>
Packit Service 310c69
#include <linux/module.h>
Packit Service 310c69
#include <linux/sched.h>
Packit Service 310c69
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static const char *priorityToLogLevel(int priority)
Packit Service 310c69
{
Packit Service 310c69
  switch (priority) {
Packit Service 310c69
    case LOG_EMERG:
Packit Service 310c69
    case LOG_ALERT:
Packit Service 310c69
    case LOG_CRIT:
Packit Service 310c69
      return KERN_CRIT;
Packit Service 310c69
    case LOG_ERR:
Packit Service 310c69
      return KERN_ERR;
Packit Service 310c69
    case LOG_WARNING:
Packit Service 310c69
      return KERN_WARNING;
Packit Service 310c69
    case LOG_NOTICE:
Packit Service 310c69
      return KERN_NOTICE;
Packit Service 310c69
    case LOG_INFO:
Packit Service 310c69
      return KERN_INFO;
Packit Service 310c69
    case LOG_DEBUG:
Packit Service 310c69
      return KERN_DEBUG;
Packit Service 310c69
    default:
Packit Service 310c69
      return "";
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static const char *getCurrentInterruptType(void)
Packit Service 310c69
{
Packit Service 310c69
  if (in_nmi()) {
Packit Service 310c69
    return "NMI";
Packit Service 310c69
  }
Packit Service 310c69
  if (in_irq()) {
Packit Service 310c69
    return "HI";
Packit Service 310c69
  }
Packit Service 310c69
  if (in_softirq()) {
Packit Service 310c69
    return "SI";
Packit Service 310c69
  }
Packit Service 310c69
  return "INTR";
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void logMessagePack(int         priority,
Packit Service 310c69
                    const char *prefix,
Packit Service 310c69
                    const char *fmt1,
Packit Service 310c69
                    va_list     args1,
Packit Service 310c69
                    const char *fmt2,
Packit Service 310c69
                    va_list     args2)
Packit Service 310c69
{
Packit Service 310c69
  if (priority > getLogLevel()) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * The kernel's printk has some magic for indirection to a secondary
Packit Service 310c69
   * va_list. It wants us to supply a pointer to the va_list.
Packit Service 310c69
   *
Packit Service 310c69
   * However, va_list varies across platforms and can be an array
Packit Service 310c69
   * type, which makes passing it around as an argument kind of
Packit Service 310c69
   * tricky, due to the automatic conversion to a pointer. This makes
Packit Service 310c69
   * taking the address of the argument a dicey thing; if we use "&a"
Packit Service 310c69
   * it works fine for non-array types, but for array types we get the
Packit Service 310c69
   * address of a pointer. Functions like va_copy and sprintf don't
Packit Service 310c69
   * care as they get "va_list" values passed and are written to do
Packit Service 310c69
   * the right thing, but printk explicitly wants the address of the
Packit Service 310c69
   * va_list.
Packit Service 310c69
   *
Packit Service 310c69
   * So, we copy the va_list values to ensure that "&" consistently
Packit Service 310c69
   * works the way we want.
Packit Service 310c69
   */
Packit Service 310c69
  va_list args1Copy;
Packit Service 310c69
  va_copy(args1Copy, args1);
Packit Service 310c69
  va_list args2Copy;
Packit Service 310c69
  va_copy(args2Copy, args2);
Packit Service 310c69
  struct va_format vaf1 = {
Packit Service 310c69
    .fmt = (fmt1 != NULL) ? fmt1 : "",
Packit Service 310c69
    .va  = &args1Copy,
Packit Service 310c69
  };
Packit Service 310c69
  struct va_format vaf2 = {
Packit Service 310c69
    .fmt = (fmt2 != NULL) ? fmt2 : "",
Packit Service 310c69
    .va  = &args2Copy,
Packit Service 310c69
  };
Packit Service 310c69
Packit Service 310c69
  if (prefix == NULL) {
Packit Service 310c69
    prefix = "";
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Context info formats:
Packit Service 310c69
   *
Packit Service 310c69
   * interrupt:   uds[NMI]: blah
Packit Service 310c69
   * process:     uds: myprog: blah
Packit Service 310c69
   *
Packit Service 310c69
   * Fields: module name, interrupt level or process name.
Packit Service 310c69
   *
Packit Service 310c69
   * XXX need the equivalent of VDO's deviceInstance here
Packit Service 310c69
   */
Packit Service 310c69
  if (in_interrupt()) {
Packit Service 310c69
    printk("%s%s[%s]: %s%pV%pV\n", priorityToLogLevel(priority),
Packit Service 310c69
	   THIS_MODULE->name, getCurrentInterruptType(), prefix, &vaf1, &vaf2);
Packit Service 310c69
  } else {
Packit Service 310c69
    printk("%s%s: %s: %s%pV%pV\n", priorityToLogLevel(priority),
Packit Service 310c69
	   THIS_MODULE->name, current->comm, prefix, &vaf1, &vaf2);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  va_end(args1Copy);
Packit Service 310c69
  va_end(args2Copy);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void logBacktrace(int priority)
Packit Service 310c69
{
Packit Service 310c69
  if (priority > getLogLevel()) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
  logMessage(priority, "[backtrace]");
Packit Service 310c69
  dump_stack();
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void pauseForLogger(void)
Packit Service 310c69
{
Packit Service 310c69
  // Hopefully, a few milliseconds of sleep will be large enough
Packit Service 310c69
  // for the kernel log buffer to be flushed.
Packit Service 310c69
  msleep(4);
Packit Service 310c69
}