Discussion:
dereferencing pointer to incomplete type ‘struct workqueue_struct’
John Busch
2017-04-26 15:20:38 UTC
Permalink
Hello,

I’m new to SystemTap, and trying to print information about kernel
work queues. I’ve used the example code in section 4.3 [1] of the
tutorial as my starting point, and I’m working on an up-to-date Fedora
25 system.

The example code in the tutorial works just fine. However, when I
essentially swap out variable and struct names to modify the example
to walk through workqueue_structs (instead of task_structs), I get a
“dereferencing pointer to incomplete type ‘struct workqueue_struct’”
compilation error on the line containing list_for_each_safe. Code
sample below.

workqueue_struct is defined in workqueue.h [2] and workqueue.c [4],
and I’m trying to access the global variable system_wq [3, 5]. How
would I gain access to these objects in systemtap? I must be doing
something wrong, but can't figure out what it is.

Thanks!

[1] https://sourceware.org/systemtap/tutorial/Tapsets.html
[2] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L16
[3] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L365
[4] http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
[5] http://lxr.free-electrons.com/source/kernel/workqueue.c#L338

%{
#include <linux/workqueue.h>
#include <linux/list.h>
%}

function read_wq_list:long ()
%{
int ret = 0;
struct workqueue_struct *wq;
struct list_head *p, *n;

list_for_each_safe(p, n, system_wq->list) {
wq = list_entry(p, struct workqueue_struct, list);
_stp_printf("workqueue struct %s\n", wq->name);
}

STAP_RETURN(ret);
%}

probe begin
{
printf("reading list of workqueues\n")
read_wq_list()
exit()
}
Arkady
2017-04-27 07:07:13 UTC
Permalink
The simplest way to resolve the problem is top copy the struct to the
inline C code

http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
Post by John Busch
Hello,
I’m new to SystemTap, and trying to print information about kernel
work queues. I’ve used the example code in section 4.3 [1] of the
tutorial as my starting point, and I’m working on an up-to-date Fedora
25 system.
The example code in the tutorial works just fine. However, when I
essentially swap out variable and struct names to modify the example
to walk through workqueue_structs (instead of task_structs), I get a
“dereferencing pointer to incomplete type ‘struct workqueue_struct’”
compilation error on the line containing list_for_each_safe. Code
sample below.
workqueue_struct is defined in workqueue.h [2] and workqueue.c [4],
and I’m trying to access the global variable system_wq [3, 5]. How
would I gain access to these objects in systemtap? I must be doing
something wrong, but can't figure out what it is.
Thanks!
[1] https://sourceware.org/systemtap/tutorial/Tapsets.html
[2] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L16
[3] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L365
[4] http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
[5] http://lxr.free-electrons.com/source/kernel/workqueue.c#L338
%{
#include <linux/workqueue.h>
#include <linux/list.h>
%}
function read_wq_list:long ()
%{
int ret = 0;
struct workqueue_struct *wq;
struct list_head *p, *n;
list_for_each_safe(p, n, system_wq->list) {
wq = list_entry(p, struct workqueue_struct, list);
_stp_printf("workqueue struct %s\n", wq->name);
}
STAP_RETURN(ret);
%}
probe begin
{
printf("reading list of workqueues\n")
read_wq_list()
exit()
}
John Busch
2017-04-27 13:02:02 UTC
Permalink
This worked for me. Thank you Arkady!
Post by Arkady
The simplest way to resolve the problem is top copy the struct to the
inline C code
http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
Post by John Busch
Hello,
I’m new to SystemTap, and trying to print information about kernel
work queues. I’ve used the example code in section 4.3 [1] of the
tutorial as my starting point, and I’m working on an up-to-date Fedora
25 system.
The example code in the tutorial works just fine. However, when I
essentially swap out variable and struct names to modify the example
to walk through workqueue_structs (instead of task_structs), I get a
“dereferencing pointer to incomplete type ‘struct workqueue_struct’”
compilation error on the line containing list_for_each_safe. Code
sample below.
workqueue_struct is defined in workqueue.h [2] and workqueue.c [4],
and I’m trying to access the global variable system_wq [3, 5]. How
would I gain access to these objects in systemtap? I must be doing
something wrong, but can't figure out what it is.
Thanks!
[1] https://sourceware.org/systemtap/tutorial/Tapsets.html
[2] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L16
[3] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L365
[4] http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
[5] http://lxr.free-electrons.com/source/kernel/workqueue.c#L338
%{
#include <linux/workqueue.h>
#include <linux/list.h>
%}
function read_wq_list:long ()
%{
int ret = 0;
struct workqueue_struct *wq;
struct list_head *p, *n;
list_for_each_safe(p, n, system_wq->list) {
wq = list_entry(p, struct workqueue_struct, list);
_stp_printf("workqueue struct %s\n", wq->name);
}
STAP_RETURN(ret);
%}
probe begin
{
printf("reading list of workqueues\n")
read_wq_list()
exit()
}
David Smith
2017-04-27 14:43:07 UTC
Permalink
If you look carefully, workqueue_struct isn't defined in
include/linux/workqueue.h. It is declared ("struct
workqueue_struct;"), but never fully defined ("struct workqueue_struct
{ char *name, ... }") in that file. So, that's why the compiler is
giving you that error. It has nothing to do with systemtap, if you
tried to compile a kernel module without systemtap, you'd get the same
error. The workqueue_struct definition is private to the workqueue.c
file.

Strangely enough, systemtap use of debuginfo would give it a
definition of that structure. So, you could write something like the
following in script language:

====
function display_wq_name:long(wq:long)
{
printf("workqueue struct %s\n", @cast(wq, "workqueue_struct")->name)
}
====

However, the problem is iterating through that list in script
language. To do that correctly, you'd need embedded-C as you've got
here.

To solve your problem, unfortunately copying the workqueue_struct
definition into your module is the only way to go to make the compiler
happy. Of course if you plan to use this long term, you'll have to
keep an eye on that private structure and be on the lookout for
changes.

Also note that if this is just a one-off exercise, your code is fine.
If you planned to use this long term or on a system you really cared
about, you'd need to change it to use systemtap's kderef_* functions
to ensure that memory is safe to read.
Post by John Busch
This worked for me. Thank you Arkady!
Post by Arkady
The simplest way to resolve the problem is top copy the struct to the
inline C code
http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
Post by John Busch
Hello,
I’m new to SystemTap, and trying to print information about kernel
work queues. I’ve used the example code in section 4.3 [1] of the
tutorial as my starting point, and I’m working on an up-to-date Fedora
25 system.
The example code in the tutorial works just fine. However, when I
essentially swap out variable and struct names to modify the example
to walk through workqueue_structs (instead of task_structs), I get a
“dereferencing pointer to incomplete type ‘struct workqueue_struct’”
compilation error on the line containing list_for_each_safe. Code
sample below.
workqueue_struct is defined in workqueue.h [2] and workqueue.c [4],
and I’m trying to access the global variable system_wq [3, 5]. How
would I gain access to these objects in systemtap? I must be doing
something wrong, but can't figure out what it is.
Thanks!
[1] https://sourceware.org/systemtap/tutorial/Tapsets.html
[2] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L16
[3] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L365
[4] http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
[5] http://lxr.free-electrons.com/source/kernel/workqueue.c#L338
%{
#include <linux/workqueue.h>
#include <linux/list.h>
%}
function read_wq_list:long ()
%{
int ret = 0;
struct workqueue_struct *wq;
struct list_head *p, *n;
list_for_each_safe(p, n, system_wq->list) {
wq = list_entry(p, struct workqueue_struct, list);
_stp_printf("workqueue struct %s\n", wq->name);
}
STAP_RETURN(ret);
%}
probe begin
{
printf("reading list of workqueues\n")
read_wq_list()
exit()
}
--
David Smith
Principal Software Engineer
Red Hat
John Busch
2017-04-27 19:08:33 UTC
Permalink
Thanks David, this is helpful. Struct definitions in .c files is new
to me. I'll also check out using kderef_* as well. Thanks!
Post by David Smith
If you look carefully, workqueue_struct isn't defined in
include/linux/workqueue.h. It is declared ("struct
workqueue_struct;"), but never fully defined ("struct workqueue_struct
{ char *name, ... }") in that file. So, that's why the compiler is
giving you that error. It has nothing to do with systemtap, if you
tried to compile a kernel module without systemtap, you'd get the same
error. The workqueue_struct definition is private to the workqueue.c
file.
Strangely enough, systemtap use of debuginfo would give it a
definition of that structure. So, you could write something like the
====
function display_wq_name:long(wq:long)
{
}
====
However, the problem is iterating through that list in script
language. To do that correctly, you'd need embedded-C as you've got
here.
To solve your problem, unfortunately copying the workqueue_struct
definition into your module is the only way to go to make the compiler
happy. Of course if you plan to use this long term, you'll have to
keep an eye on that private structure and be on the lookout for
changes.
Also note that if this is just a one-off exercise, your code is fine.
If you planned to use this long term or on a system you really cared
about, you'd need to change it to use systemtap's kderef_* functions
to ensure that memory is safe to read.
Post by John Busch
This worked for me. Thank you Arkady!
Post by Arkady
The simplest way to resolve the problem is top copy the struct to the
inline C code
http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
Post by John Busch
Hello,
I’m new to SystemTap, and trying to print information about kernel
work queues. I’ve used the example code in section 4.3 [1] of the
tutorial as my starting point, and I’m working on an up-to-date Fedora
25 system.
The example code in the tutorial works just fine. However, when I
essentially swap out variable and struct names to modify the example
to walk through workqueue_structs (instead of task_structs), I get a
“dereferencing pointer to incomplete type ‘struct workqueue_struct’”
compilation error on the line containing list_for_each_safe. Code
sample below.
workqueue_struct is defined in workqueue.h [2] and workqueue.c [4],
and I’m trying to access the global variable system_wq [3, 5]. How
would I gain access to these objects in systemtap? I must be doing
something wrong, but can't figure out what it is.
Thanks!
[1] https://sourceware.org/systemtap/tutorial/Tapsets.html
[2] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L16
[3] http://lxr.free-electrons.com/source/include/linux/workqueue.h#L365
[4] http://lxr.free-electrons.com/source/kernel/workqueue.c#L239
[5] http://lxr.free-electrons.com/source/kernel/workqueue.c#L338
%{
#include <linux/workqueue.h>
#include <linux/list.h>
%}
function read_wq_list:long ()
%{
int ret = 0;
struct workqueue_struct *wq;
struct list_head *p, *n;
list_for_each_safe(p, n, system_wq->list) {
wq = list_entry(p, struct workqueue_struct, list);
_stp_printf("workqueue struct %s\n", wq->name);
}
STAP_RETURN(ret);
%}
probe begin
{
printf("reading list of workqueues\n")
read_wq_list()
exit()
}
--
David Smith
Principal Software Engineer
Red Hat
Frank Ch. Eigler
2017-04-28 14:35:59 UTC
Permalink
[...] However, the problem is iterating through that list in script
language. To do that correctly, you'd need embedded-C as you've got
here. [...]
Iterating through the list in script language is possible though.
The workqueue structure is available via
p = @var("system_wq")
Its list_head field is accessible via
n = @cast(p, "workqueue_struct")->list->next
One can get back to the workqueue_struct from a list pointer via
p = & @container_of(n, "workqueue_struct", list)

So putting it together:

# stap -DMAXACTION=50000 -e '
probe oneshot {
p=@var("system_wq")
while (max++ < 5000) {
printf("p=%p name=%s\n", p, @cast(p,"workqueue_struct")->name$);
n = @cast(p, "workqueue_struct")->list->next;
ne = & @cast(p, "workqueue_struct")->list;
if (n == ne) break;
p = & @container_of(n, "workqueue_struct", list);
}
}
'

- FChE

Loading...