aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/traceevent/plugin_function.c
blob: a00ec190821aa352234ddf11f5d6ab3bb911dc5f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License (not later!)
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not,  see <http://www.gnu.org/licenses>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "event-parse.h"
#include "event-utils.h"

static struct func_stack {
	int size;
	char **stack;
} *fstack;

static int cpus = -1;

#define STK_BLK 10

struct pevent_plugin_option plugin_options[] =
{
	{
		.name = "parent",
		.plugin_alias = "ftrace",
		.description =
		"Print parent of functions for function events",
	},
	{
		.name = "indent",
		.plugin_alias = "ftrace",
		.description =
		"Try to show function call indents, based on parents",
		.set = 1,
	},
	{
		.name = NULL,
	}
};

static struct pevent_plugin_option *ftrace_parent = &plugin_options[0];
static struct pevent_plugin_option *ftrace_indent = &plugin_options[1];

static void add_child(struct func_stack *stack, const char *child, int pos)
{
	int i;

	if (!child)
		return;

	if (pos < stack->size)
		free(stack->stack[pos]);
	else {
		char **ptr;

		ptr = realloc(stack->stack, sizeof(char *) *
			      (stack->size + STK_BLK));
		if (!ptr) {
			warning("could not allocate plugin memory\n");
			return;
		}

		stack->stack = ptr;

		for (i = stack->size; i < stack->size + STK_BLK; i++)
			stack->stack[i] = NULL;
		stack->size += STK_BLK;
	}

	stack->stack[pos] = strdup(child);
}

static int add_and_get_index(const char *parent, const char *child, int cpu)
{
	int i;

	if (cpu < 0)
		return 0;

	if (cpu > cpus) {
		struct func_stack *ptr;

		ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
		if (!ptr) {
			warning("could not allocate plugin memory\n");
			return 0;
		}

		fstack = ptr;

		/* Account for holes in the cpu count */
		for (i = cpus + 1; i <= cpu; i++)
			memset(&fstack[i], 0, sizeof(fstack[i]));
		cpus = cpu;
	}

	for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) {
		if (strcmp(parent, fstack[cpu].stack[i]) == 0) {
			add_child(&fstack[cpu], child, i+1);
			return i;
		}
	}

	/* Not found */
	add_child(&fstack[cpu], parent, 0);
	add_child(&fstack[cpu], child, 1);
	return 0;
}

static int function_handler(struct trace_seq *s, struct pevent_record *record,
			    struct event_format *event, void *context)
{
	struct pevent *pevent = event->pevent;
	unsigned long long function;
	unsigned long long pfunction;
	const char *func;
	const char *parent;
	int index;

	if (pevent_get_field_val(s, event, "ip", record, &function, 1))
		return trace_seq_putc(s, '!');

	func = pevent_find_function(pevent, function);

	if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
		return trace_seq_putc(s, '!');

	parent = pevent_find_function(pevent, pfunction);

	if (parent && ftrace_indent->set)
		index = add_and_get_index(parent, func, record->cpu);

	trace_seq_printf(s, "%*s", index*3, "");

	if (func)
		trace_seq_printf(s, "%s", func);
	else
		trace_seq_printf(s, "0x%llx", function);

	if (ftrace_parent->set) {
		trace_seq_printf(s, " <-- ");
		if (parent)
			trace_seq_printf(s, "%s", parent);
		else
			trace_seq_printf(s, "0x%llx", pfunction);
	}

	return 0;
}

int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
	pevent_register_event_handler(pevent, -1, "ftrace", "function",
				      function_handler, NULL);

	traceevent_plugin_add_options("ftrace", plugin_options);

	return 0;
}

void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
	int i, x;

	pevent_unregister_event_handler(pevent, -1, "ftrace", "function",
					function_handler, NULL);

	for (i = 0; i <= cpus; i++) {
		for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
			free(fstack[i].stack[x]);
		free(fstack[i].stack);
	}

	traceevent_plugin_remove_options(plugin_options);

	free(fstack);
	fstack = NULL;
	cpus = -1;
}
framework. The docking support in this driver does not take care of enabling or disabling any other devices you may have attached to the dock. For example, a CD drive plugged into the UltraBase needs to be disabled or enabled separately. See the provided example acpid configuration files for how this can be accomplished. There is no support yet for PCI devices that may be attached to a docking station, e.g. in the ThinkPad Dock II. The driver currently does not recognize, enable or disable such devices. This means that the only docking stations currently supported are the X-series UltraBase docks and "dumb" port replicators like the Mini Dock (the latter don't need any ACPI support, actually). UltraBay Eject -- /proc/acpi/ibm/bay ------------------------------------ Inserting or ejecting an UltraBay device requires some actions to be taken by the operating system to safely make or break the electrical connections with the device. This feature generates the following ACPI events: ibm/bay MSTR 00000003 00000000 -- eject request ibm/bay MSTR 00000001 00000000 -- eject lever inserted NOTE: These events will only be generated if the UltraBay was present when the laptop was originally booted (on the X series, the UltraBay is in the dock, so it may not be present if the laptop was undocked). This is due to the current lack of support for hot plugging of devices in the Linux ACPI framework. If the laptop was booted without the UltraBay, the following message is shown in the logs: "ibm_acpi: bay device not present". No bay-related events are generated but the eject command described below still works. It can be executed manually or triggered by a hot key combination. Sliding the eject lever generates the first event shown above. The handler for this event should take whatever actions are necessary to shut down the device in the UltraBay (e.g. call idectl), then issue the following command: echo eject > /proc/acpi/ibm/bay After the LED on the UltraBay goes off, it is safe to pull out the device. When the eject lever is inserted, the second event above is generated. The handler for this event should take whatever actions are necessary to enable the UltraBay device (e.g. call idectl). The contents of the /proc/acpi/ibm/bay file shows the current status of the UltraBay, as provided by the ACPI framework. Experimental Features --------------------- The following features are marked experimental because using them involves guessing the correct values of some parameters. Guessing incorrectly may have undesirable effects like crashing your ThinkPad. USE THESE WITH CAUTION! To activate them, you'll need to supply the experimental=1 parameter when loading the module. Experimental: CMOS control - /proc/acpi/ibm/cmos ------------------------------------------------ This feature is used internally by the ACPI firmware to control the ThinkLight on most newer ThinkPad models. It appears that it can also control LCD brightness, sounds volume and more, but only on some models. The commands are non-negative integer numbers: echo 0 >/proc/acpi/ibm/cmos echo 1 >/proc/acpi/ibm/cmos echo 2 >/proc/acpi/ibm/cmos ... The range of numbers which are used internally by various models is 0 to 21, but it's possible that numbers outside this range have interesting behavior. Here is the behavior on the X40 (tpb is the ThinkPad Buttons utility): 0 - no effect but tpb reports "Volume down" 1 - no effect but tpb reports "Volume up" 2 - no effect but tpb reports "Mute on" 3 - simulate pressing the "Access IBM" button 4 - LCD brightness up 5 - LCD brightness down 11 - toggle screen expansion 12 - ThinkLight on 13 - ThinkLight off 14 - no effect but tpb reports ThinkLight status change If you try this feature, please send me a report similar to the above. On models which allow control of LCD brightness or sound volume, I'd like to provide this functionality in an user-friendly way, but first I need a way to identify the models which this is possible. Experimental: LED control - /proc/acpi/ibm/LED ---------------------------------------------- Some of the LED indicators can be controlled through this feature. The available commands are: echo <led number> on >/proc/acpi/ibm/led echo <led number> off >/proc/acpi/ibm/led echo <led number> blink >/proc/acpi/ibm/led The <led number> parameter is a non-negative integer. The range of LED numbers used internally by various models is 0 to 7 but it's possible that numbers outside this range are also valid. Here is the mapping on the X40: 0 - power 1 - battery (orange) 2 - battery (green) 3 - UltraBase 4 - UltraBay 7 - standby All of the above can be turned on and off and can be made to blink. If you try this feature, please send me a report similar to the above. I'd like to provide this functionality in an user-friendly way, but first I need to identify the which numbers correspond to which LEDs on various models. Experimental: ACPI sounds - /proc/acpi/ibm/beep ----------------------------------------------- The BEEP method is used internally by the ACPI firmware to provide audible alerts in various situtation. This feature allows the same sounds to be triggered manually. The commands are non-negative integer numbers: echo 0 >/proc/acpi/ibm/beep echo 1 >/proc/acpi/ibm/beep echo 2 >/proc/acpi/ibm/beep ... The range of numbers which are used internally by various models is 0 to 17, but it's possible that numbers outside this range are also valid. Here is the behavior on the X40: 2 - two beeps, pause, third beep 3 - single beep 4 - "unable" 5 - single beep 6 - "AC/DC" 7 - high-pitched beep 9 - three short beeps 10 - very long beep 12 - low-pitched beep (I've only been able to identify a couple of them). If you try this feature, please send me a report similar to the above. I'd like to provide this functionality in an user-friendly way, but first I need to identify the which numbers correspond to which sounds on various models. Multiple Command, Module Parameters ----------------------------------- Multiple commands can be written to the proc files in one shot by separating them with commas, for example: echo enable,0xffff > /proc/acpi/ibm/hotkey echo lcd_disable,crt_enable > /proc/acpi/ibm/video Commands can also be specified when loading the ibm_acpi module, for example: modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable Example Configuration --------------------- The ACPI support in the kernel is intended to be used in conjunction with a user-space daemon, acpid. The configuration files for this daemon control what actions are taken in response to various ACPI events. An example set of configuration files are included in the config/ directory of the tarball package available on the web site. Note that these are provided for illustration purposes only and may need to be adapted to your particular setup. The following utility scripts are used by the example action scripts (included with ibm-acpi for completeness): /usr/local/sbin/idectl -- from the hdparm source distribution, see http://www.ibiblio.org/pub/Linux/system/hardware /usr/local/sbin/laptop_mode -- from the Linux kernel source distribution, see Documentation/laptop-mode.txt /sbin/service -- comes with Redhat/Fedora distributions Toan T Nguyen <ntt@control.uchicago.edu> has written a SuSE powersave script for the X20, included in config/usr/sbin/ibm_hotkeys_X20 Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event handler script for the X31. You can get the latest version from http://dev.gentoo.org/~brix/files/x31.sh David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh script which works on Debian systems, included in configs/etc/acpi/actions/blank-debian.sh TODO ---- I'd like to implement the following features but haven't yet found the time and/or I don't yet know how to implement them: - UltraBay floppy drive support