I'm studying Operating Systems and, of course, Minix 3.
Can someone tell me which file and line of code in Minix 3 are the entry points of:
Kernel;
Process Manager;
Memory Manager;
Virtual Memory Manager;
Any Device Driver.
Any of above will help me a lot.
Thanks.
I'm using the main github source:
https://github.com/Stichting-MINIX-Research-Foundation/minix
Try first searching for the device drivers since they are more "self-contained". Device drivers are found inhttps://github.com/Stichting-MINIX-Research-Foundation/minix/tree/master/minix/drivers
Instead of just pointing the entry points, I will show how I usually do. I will use the minix/drivers/video/fb/fb.h as an example. The fb is a driver responsible for controlling video displayed on a monitor. I could open any file, but I chose the fb.h since it is a header file and will contain the signatures of public functions.
I am on Linux so I can use the grep -r command. The -r flag search recursively for the given pattern. So by inspecting fb.h I found the following functions:
int arch_fb_init(int minor, struct edid_info *info);
int arch_get_device(int minor, struct device *dev);
int arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp);
int arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvs_copy);
int arch_get_fixscreeninfo(int minor, struct fb_fix_screeninfo *fbfsp);
int arch_pan_display(int minor, struct fb_var_screeninfo *fbvs_copy);
Well, arch_fb_init seems to be an entry point. To verify if arch_fb_init is indeed an entry point, I use
grep -r "arch_fb_init"
Which in turn returns the following
$ grep -r "arch_fb_init"
drivers/video/fb/arch/earm/fb_arch.c:arch_fb_init(int minor, struct edid_info *info)
drivers/video/fb/fb.h:int arch_fb_init(int minor, struct edid_info *info);
drivers/video/fb/fb.c: if (arch_fb_init(minor, infop) == OK) {
The second match is the fb.h itself. The other two are in fb_arch.c and fb.c. Then I go to those files and inspect each of them. Opening fb_arch.c and searching for arch_fb_init I find on line 315 an implementation of this function. By now, the implementation of the function could be more interesting because we want to figure out the caller/callee hierarchy.
Opening fb.c I find an occurrence of arch_fb_init on line 74, which is a call to arch_fb_init. This call to arch_fb_init is performed by another function named fb_open (line 60 on fb.c).
Now I repeat the process but now searching for fb_open. Performing another grep now returns the following.
$ grep -r "fb_open"
drivers/video/fb/fb.c:static int fb_open(devminor_t minor, int access, endpoint_t user_endpt);
drivers/video/fb/fb.c: .cdr_open = fb_open,
drivers/video/fb/fb.c:fb_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt))
All the occurrences are also in fb.c. By inspecting fb.c, one can see that the first grep match is a declaration of the fb_open function, and the third one is the implementation itself. The second one is using fb_open to construct a table (line 46 on file fb.c) that you can see below
/* Entry points to the fb driver. */
static struct chardriver fb_tab =
{
.cdr_open = fb_open,
.cdr_close = fb_close,
.cdr_read = fb_read,
.cdr_write = fb_write,
.cdr_ioctl = fb_ioctl
};
The commentary "Entry points to the fb driver." indicates that we are getting closer. If you have an IDE capable of parsing the Minix project, it will be easier to find all the callers/callee. If you don't have an IDE, you can use the grep command with the -r flag. If you know object orientation, this fb_tab is kind of a virtual table. Probably is setting callbacks that the kernel can use when calling this driver. I'm not sure because I never worked with minix before, but I have some general knowledge in OS, and the names used imply that I may be right.
Now searching for fb_tab by using grep, I get the following:
$ grep -r "fb_tab"
drivers/video/fb/fb.c:static struct chardriver fb_tab =
drivers/video/fb/fb.c: chardriver_task(&fb_tab);
All the occurrences once again in fb.c. The first match is the definition of fb_tab itself. The second one is the following
int
main(int argc, char *argv[])
{
env_setargs(argc, argv);
fb_edid_args_parse();
sef_local_startup();
chardriver_task(&fb_tab);
return OK;
}
By inspecting this main function, env_setargs and fb_edid_args_parse are probably just parsing arguments and setting flags. Now, the sef_local_startup and chardriver_task functions may be worth performing a grep.
Performing a grep on chardriver_task returns the following:
$ grep -r "chardriver_task"
drivers/examples/hello/hello.c: chardriver_task(&hello_tab);
drivers/sensors/tsl2550/tsl2550.c: chardriver_task(&tsl2550_tab);
drivers/sensors/bmp085/bmp085.c: chardriver_task(&bmp085_tab);
drivers/sensors/sht21/sht21.c: chardriver_task(&sht21_tab);
drivers/printer/printer/printer.c: chardriver_task(&printer_tab);
drivers/system/log/log.c: chardriver_task(&log_dtab);
drivers/system/random/main.c: chardriver_task(&r_dtab);
drivers/bus/i2c/i2c.c: chardriver_task(&i2c_tab);
drivers/bus/pci/main.c: chardriver_task(&driver);
drivers/video/fb/fb.c: chardriver_task(&fb_tab);
include/minix/chardriver.h:void chardriver_task(const struct chardriver *cdp);
servers/input/input.c: chardriver_task(&input_tab);
lib/libchardriver/chardriver.c: * chardriver_task *
lib/libchardriver/chardriver.c:void chardriver_task(const struct chardriver *cdp)
lib/libaudiodriver/audio_fw.c: chardriver_task(&audio_tab);
Many of the matches are calling the chardriver_task similar to the one found in fb.c but the following probably is the declaration
include/minix/chardriver.h:void chardriver_task(const struct chardriver *cdp);
And this one probably is the implementation
lib/libchardriver/chardriver.c:void chardriver_task(const struct chardriver *cdp)
As you can see, there isn't a clear entry point. It depends on what you're searching for. In the case of the fb driver, if you're searching for its initialization, it is probably the main function. However, if you're searching for how the kernel will be calling the driver probably is by the callbacks set on fb_tab.
If you can edit your question, someone will probably give you a better answer.
Related
We have a kernel module using filename_lookup call which is not exported anymore in RHEL8 Kernel 4.18. But found another system call exported in /proc/kallsyms, which is filename_lookup.part.64
What is filename_lookup.part.64 ? Can I call it in our code using the address exported in /proc/kallsyms?
I am not able to find any documentation on filename_lookup.part.64.
Is it safe to use this kind of undocumented APIs?
struct filename filename = { .name = name };
struct nameidata nd;
filename_lookup(AT_FDCWD, &filename, LOOKUP_PARENT, &nd);
I am looking to find the calls that can be used to replace the above in the absence of filename_lookup()
Regarding your question
What is filename_lookup.part.64 ? Can I call it in our code using the
address exported in /proc/kallsyms?
as can be read at here, it is the original filename_lookup function without some parts that the compiler optimized and set them inline, so its not safe.
As said earlier #user3248278, would be easier to use the wrappers such as kern_path or user_path_at_empty.
Filename_lookup is now wrapped with various APIs, which are exported, for example -
*int kern_path(const char *name, unsigned int flags, struct path path) - for getting inodes in kernels.
You can easily search in elixir for filename_lookup and you can find the wrappers.
I'm aware of many similar questions on this site. I really like the solution mention in the following link:
https://stackoverflow.com/a/25021520/884553
with some modification, you can include text file at compile time, for example:
constexpr const char* s =
#include "file.txt"
BUT to make this work you have to add string literal prefix and suffix to your original file, for example
R"(
This is the original content,
and I don't want this file to be modified. but i
don't know how to do it.
)";
My question is: is there a way to make this work but not modifying file.txt?
(I know I can use command line tools to make a copy, prepend and append to the copy, remove the copy after compile. I'm looking for a more elegant solution than this. hopefully no need of other tools)
Here's what I've tried (but not working):
#include <iostream>
int main() {
constexpr const char* s =
#include "bra.txt" // R"(
#include "file.txt" //original file without R"( and )";
#include "ket.txt" // )";
std::cout << s << "\n";
return 0;
}
/opt/gcc8/bin/g++ -std=c++1z a.cpp
In file included from a.cpp:5:
bra.txt:1:1: error: unterminated raw string
R"(
^
a.cpp: In function ‘int main()’:
a.cpp:4:27: error: expected primary-expression at end of input
constexpr const char* s =
^
a.cpp:4:27: error: expected ‘}’ at end of input
a.cpp:3:12: note: to match this ‘{’
int main() {
^
No, this cannot be done.
There is a c++2a proposal to allow inclusion of such resources at compile time called std::embed.
The motivation part of ths p1040r1 proposal:
Motivation
Every C and C++ programmer -- at some point -- attempts to #include large chunks of non-C++ data into their code. Of course, #include expects the format of the data to be source code, and thusly the program fails with spectacular lexer errors. Thusly, many different tools and practices were adapted to handle this, as far back as 1995 with the xxd tool. Many industries need such functionality, including (but hardly limited to):
Financial Development
representing coefficients and numeric constants for performance-critical algorithms;
Game Development
assets that do not change at runtime, such as icons, fixed textures and other data
Shader and scripting code;
Embedded Development
storing large chunks of binary, such as firmware, in a well-compressed format
placing data in memory on chips and systems that do not have an operating system or file system;
Application Development
compressed binary blobs representing data
non-C++ script code that is not changed at runtime; and
Server Development
configuration parameters which are known at build-time and are baked in to set limits and give compile-time information to tweak performance under certain loads
SSL/TLS Certificates hard-coded into your executable (requiring a rebuild and potential authorization before deploying new certificates).
In the pursuit of this goal, these tools have proven to have inadequacies and contribute poorly to the C++ development cycle as it continues to scale up for larger and better low-end devices and high-performance machines, bogging developers down with menial build tasks and trying to cover-up disappointing differences between platforms.
MongoDB has been kind enough to share some of their code below. Other companies have had their example code anonymized or simply not included directly out of shame for the things they need to do to support their workflows. The author thanks MongoDB for their courage and their support for std::embed.
The request for some form of #include_string or similar dates back quite a long time, with one of the oldest stack overflow questions asked-and-answered about it dating back nearly 10 years. Predating even that is a plethora of mailing list posts and forum posts asking how to get script code and other things that are not likely to change into the binary.
This paper proposes <embed> to make this process much more efficient, portable, and streamlined. Here’s an example of the ideal:
#include <embed>
int main (int, char*[]) {
constexpr std::span<const std::byte> fxaa_binary = std::embed( "fxaa.spirv" );
// assert this is a SPIRV file, compile-time
static_assert( fxaa_binary[0] == 0x03 && fxaa_binary[1] == 0x02
&& fxaa_binary[2] == 0x23 && fxaa_binary[3] == 0x07
, "given wrong SPIRV data, check rebuild or check the binaries!" )
auto context = make_vulkan_context();
// data kept around and made available for binary
// to use at runtime
auto fxaa_shader = make_shader( context, fxaa_binary );
for (;;) {
// ...
// and we’re off!
// ...
}
return 0;
}
I have to migrate some code to LTTng. We were using syslog-like tool and using printf-like format...
I have found several log lines printing pointers with %p but I do not know how to "translate" those lines into LTTng.
Any help will be really appreciated.
If you're using LTTng 2.7+, your best bet is using tracelog(), a special API that was designed to ease the migration from logging to tracing.
You should be able to use %p with tracelog() since it uses the vsprintf() family of functions to format the recorded message.
If you already tread on the path to defining static tracepoints, I suggest using a CTF integer backed by a uintptr_t if your compiler supports C99, otherwise unsigned long long or perhaps size_t (which should be able to hold an address most of the time, although it's not guaranteed):
#include <stdint.h>
TRACEPOINT_EVENT(
my_provider,
my_memory_address,
/* arguments (input) */
TP_ARGS(
const void *, address
),
/* event fields (output) */
TP_FIELDS(
ctf_integer_hex(uintptr_t, address, address)
)
)
Then you can use it like this:
tracepoint(my_provider, my_memory_address, my_pointer);
I copied code that's supposed to change desktop wallpaper. I have this constant in my program:
const char * image_name = "button_out.gif";
Later, I write the image on disk using Magick++:
image.write(image_name);
The image appears in program's working directory. If I run the program directly from explorer the working directory equals the program location.
Because the code prints the 0x80070002 - File not found error I added a exist function in the beginning:
#include <sys/stat.h>
bool exists(const char* name) {
struct stat buffer;
return (stat (name, &buffer) == 0);
}
void SetWallpaper(LPCWSTR file){
if(!exists((const char* )file)) {
wcout << "The file "<<file<<" does not exist!" << endl;
return;
... actually try to set a wallpaper ...
}
The error is not printed however and the code proceeds.
Now the question is:
Does my exist function work properly?
Where does windows look for that image?
Full code to set a Magick++ generated image as background in case I have missed something relevant in this question.
Problem 1: String Conversions
Your primary problem is that you are attempting to use LPCWSTR (a const wchar_t *) and const char * interchangeably. I see a number of issues in your source, in particular:
You start with const char * image_name.
You then cast it to a LPCWSTR to pass to SetWallpaper. This basically guarantees that SetWallpaper will fail, as desktop->SetWallpaper is not able to handle non wide-character strings.
You then cast it back to a const char * to pass to stat() via exists(). This should work in your situation (since the original string really is a char *) but isn't correct because your string parameter to SetWallpaper is supposedly a proper LPCWSTR.
You need to pick a string format (wide-character vs. what Windows terms "ANSI") and stick to that format, using consistent APIs throughout.
The easiest option is probably just to leave most of your code untouched, but modify SetWallpaper to take a const char * and convert to a wide-character string when needed (for this you can use mbstowcs). So, for example:
void SetWallpaper(const char * file){ // <- Use a const char* parameter.
...
// Convert to a wide-character string to pass to COM:
wchar_t wcfile[MAX_PATH + 1];
mbstowcs(wcfile, file, sizeof(wcfile) / sizeof(wchar_t));
// Pass the converted wide-character string:
desktop->SetWallpaper(wcfile, 0);
...
}
The other option would be to use wide-character strings throughout, i.e.:
LPCWSTR image_name = L"button_out.gif";
Modify exists() to take a LPCWSTR and use _wstat() instead.
Use wide-character versions of all other API functions.
However, I am unsure how that would interact with the ImageMagick API, which may not have wide-character support. So it's up to you. Choose whatever approach is the easiest to implement but make sure you are consistent. The general rule is do not cast between LPCWSTR and const char *; if you are ever in a situation where you need to change one to the other, you cannot cast, you must convert (via mbstowcs or wcstombs).
Problem 2: SetWallpaper default directory is not current working directory
At this point, your string usage will be consistent. Now that you have that problem ironed out, if SetWallpaper fails while exists() does not, then SetWallpaper is not looking where you think it is. As you discovered in your comment, SetWallpaper looks in the desktop by default. In this case, while I have not tested it, you may be able to work around this by passing an absolute path to SetWallpaper. For this, you can use GetFullPathName to determine the absolute file name given your relative path. Remember to be consistent with your string types, though.
Also, if stat() continues to fail, then that problem is either that your working directory is not what you think it is, or your filename is not what you think it is. To that end you will want to perform the following tests:
Print the current working directory at the point you check for the files existence, verify it is correct.
Print the filename when you check for its existence, verify it is correct.
You should be good to go once you work all the above issues out.
What object is the meta-data of the dot/double-dot file records as returned by FindFirstFile on a directory referring to?
In practice they seem to behave as a curious mixture of soft and hard links. On my system the file attributes (e.g. read-only/hidden/archive flags) do reflect the state of the target they point towards, however the creation/write/access access fields always seem to equal the creation time of the directory being searched.
I ask because a build tool I was working on decided to cache search results by first translating the file names to absolute ones and filing away the meta-data, leading broken builds when the creation-times of later directories mismatched.
May I rely on the ftCreationTime of "." being equal to the creation time of the folder itself? This would be useful in avoiding unnecessary queries.
For the record here is a quick-and-dirty repro:
#include <stdio.h>
#include <windows.h>
static void print(const WIN32_FIND_DATAA *data) {
printf("name=%s attrib=%08lX creation=%08lX%08lX\n", data->cFileName, data->dwFileAttributes,
data->ftCreationTime.dwHighDateTime, data->ftCreationTime.dwLowDateTime);
}
int main(void) {
WIN32_FIND_DATAA data = { 0 };
HANDLE handle = FindFirstFileA("C:\\Windows\\System\\*", &data);
print(&data);
FindNextFileA(handle, &data);
print(&data);
FindFirstFileA("C:\\Windows", &data);
print(&data);
FindFirstFileA("C:\\Windows\\System", &data);
print(&data);
return 0;
}
From MSDN:
Use a period as a directory component in a path to represent the current directory...
Use two consecutive periods (..) as a directory component in a path to represent the parent of the current directory
It means . is current directory and you may rely that they attributes are the same. But anyway I don't understand why can't you just ignore the dot and dotdot files.