Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an API for native libraries #7682

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

AditiS11
Copy link

@AditiS11 AditiS11 commented Mar 7, 2025

Use /proc file system to capture the dependent libraries. Combine multiple sections into one and iterate over the list plus invoke the callback

@babsingh
Copy link
Contributor

babsingh commented Mar 7, 2025

@keithc-ca could you please help in reviewing this PR?

/**
* Native Libraries
*
* This function is called go get all the shared libraries loaded by the Java process.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not specific to Java: please remove that reference.

Comment on lines 461 to 469
intptr_t fd=portLibrary->file_open(portLibrary,"/proc/self/maps",EsOpenRead,0);
if(0 > fd){
return -1;
}
char buffer[READ_CHUNK_SIZE +1];
char carryOver[READ_CHUNK_SIZE +1]="";
intptr_t bytesRead = 0;
uintptr_t result=0;
while (0<(bytesRead = portLibrary->file_read(portLibrary, fd, buffer, READ_CHUNK_SIZE))){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not strictly legal C code: declarations must be at the beginning of a block.

Please first update this so the additions follow the coding standard. Some examples of things that don't follow those guidelines:

  • comparisons (== and != where the constant is not on the left
  • conditions with embedded assignments
  • code should be indented consistently one tab per level (not spaces)
  • missing comments on #else and #endif
  • binary operators (e.g. +, =, <) should have a space before and after
  • a space should appear consistently after if, while, switch, etc.
  • compound expressions should have parentheses to avoid any concern for precedence rules
  • a space should appear before { for each if, while, else etc, block

@AditiS11 AditiS11 force-pushed the nativelib-x64 branch 2 times, most recently from 3b237c5 to a21d95e Compare March 11, 2025 11:23
@@ -2115,6 +2116,8 @@ typedef struct OMRPortLibrary {
uintptr_t (*sl_open_shared_library)(struct OMRPortLibrary *portLibrary, char *name, uintptr_t *descriptor, uintptr_t flags) ;
/** see @ref omrsl.c::omrsl_lookup_name "omrsl_lookup_name"*/
uintptr_t (*sl_lookup_name)(struct OMRPortLibrary *portLibrary, uintptr_t descriptor, char *name, uintptr_t *func, const char *argSignature) ;
/** see @ref omrsl.c::omrsl_get_shared_libraries "omrsl_open_shared_library"*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct the comment:

	/** see @ref omrsl.c::omrsl_get_libraries "omrsl_get_libraries"*/

@@ -29,6 +29,7 @@
#include "omrport.h"
#include "omrportpriv.h"
#include "ut_omrport.h"
#include "omrsl.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is wanted: the declaration of omrsl_get_libraries() should be in omrportpriv.h instead.

Comment on lines 53 to 54
uintptr_t
omrsl_get_libraries(struct OMRPortLibrary *portLibrary, OMRLibraryInfoCallback callback, void *userData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this to omrportpriv.h.

Comment on lines 54 to 55
/* Max Length of Library name */
#define READ_CHUNK_SIZE 4096
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment isn't really accurate, should end with a period, and might be better placed just before the function that uses it.

/**
* Native Libraries
*
* This function is called go get all the shared libraries loaded by a process.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one space between "shared" and "libraries", please.

Comment on lines 509 to 529
count = sscanf(
line,"%p-%p %4s %lx %x:%x %lu %s",
&addrLow, &addrHigh, permissions,
&offset, &devMajor, &devMinor, &inode, path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first two arguments (at least) should be on lines by themselves:

			count = sscanf(
					line,
					"%p-%p %4s %lx %x:%x %lu %s",
					&addrLow, &addrHigh, permissions,
					&offset, &devMajor, &devMinor, &inode, path);

Comment on lines 514 to 508
result = callback(path,addrLow,addrHigh, userData);
}
if (0 != result) {
portLibrary->file_close(portLibrary, fd);
return result;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces, break avoids repetition:

				result = callback(path, addrLow, addrHigh, userData);
				if (0 != result) {
					break;
				}

Comment on lines 526 to 515
#else
/* Platform not supported */
return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing comment, missing period, inconsistent indentation:

#else /* defined(LINUX) */
	/* Platform not supported. */
	return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;

Comment on lines 483 to 484
bytesRead = portLibrary->file_read(portLibrary, fd, buffer, READ_CHUNK_SIZE);
do {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving the read inside the loop avoids repetition:

	do  {
		bytesRead = portLibrary->file_read(portLibrary, fd, buffer, sizeof(buffer) - 1);

(line 522 should then be deleted)

while (NULL != line) {
nextLine = strtok(NULL, "\n");
if (NULL == nextLine && !lastCharIsNewline) {
portLibrary->str_printf(portLibrary, carryOver, sizeof(carryOver), "%s", line);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line may point within combinedBuffer and thus may not fit in carryOver: this must be checked here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change the length of the buffer to 4146 bytes. The max path length in Unix is 4096 bytes and I am considering another 50 bytes for the addresses, inode number etc. That way line can never exceed the size of the carryOver buffer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be defined within the LINUX block and be defined in terms of PATH_MAX:

#define READ_CHUNK_SIZE (PATH_MAX + 50)

However, I'm not sure that addresses my concern. No matter what size the buffers are, parts of combinedBuffer and carryOver may need more space than is available.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want line 512 any more - line 502 already wrote to carryOver. After removing that line, line 510 becomes redundant.

@AditiS11 AditiS11 force-pushed the nativelib-x64 branch 3 times, most recently from e619b0d to af91ad3 Compare March 14, 2025 14:30
Copy link
Contributor

@keithc-ca keithc-ca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the commit message:

  • lines in the body should be no more than 72 characters long
  • this does not (nor should it) "combine multiple sections"

@@ -840,3 +841,4 @@ omrport_allocate_library(struct OMRPortLibrary **portLibrary)
}
return rc;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this extra blank line (the last two characters should be "}\n").

@@ -135,3 +135,19 @@ omrsl_startup(struct OMRPortLibrary *portLibrary)
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete this blank line (we don't need more than one in a row).

/**
* Native Libraries
*
* This function is called to get all the shared libraries loaded by a process.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No trailing spaces (here or on any line you add or modify).

@@ -45,6 +45,7 @@
#include <errno.h>
#include <dlfcn.h>
#include "ut_omrport.h"
#include "omrport.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this (see line 76).

while (NULL != line) {
nextLine = strtok(NULL, "\n");
if (NULL == nextLine && !lastCharIsNewline) {
portLibrary->str_printf(portLibrary, carryOver, sizeof(carryOver), "%s", line);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be defined within the LINUX block and be defined in terms of PATH_MAX:

#define READ_CHUNK_SIZE (PATH_MAX + 50)

However, I'm not sure that addresses my concern. No matter what size the buffers are, parts of combinedBuffer and carryOver may need more space than is available.

Comment on lines +518 to +508
if (0 != result) {
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 518-520 can go before line 517 (only there might result be non-zero).

portLibrary->file_close(portLibrary, fd);
return result;
#else /* defined(LINUX) */
/* Platform not supported. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This indentation is still incorrect.

@keithc-ca
Copy link
Contributor

This should not make reference to JFR; yes, it might be one of the first consumers of this new API, but this project aims to be language neutral.

omrsl_get_libraries(struct OMRPortLibrary *portLibrary, OMRLibraryInfoCallback callback, void *userData)
{
#if defined(LINUX)
#include <limits.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't likely to work (within the function body); please move it near the top of the file (if needed).

Comment on lines 476 to 472
carryOver[0] = '\0';
intptr_t fd = portLibrary->file_open(portLibrary, "/proc/self/maps", EsOpenRead, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't legal C code (an assignment statement before a declaration).

int portableError = portLibrary->error_last_error_number(portLibrary);
Trc_PRT_find_executable_name_failedOpeningProcFS(portableError);
portLibrary->error_set_last_error_with_message(portLibrary, portableError, "Failed to open /proc fs");
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type is unsigned; a negative value is not appropriate.

char *nextLine = strtok(NULL, "\n");
if ((NULL == nextLine) && (0 == lastCharIsNewline)) {
int readChars = portLibrary->str_printf(portLibrary, carryOver, sizeof(carryOver), "%s", line);
if(readChars >= sizeof(carryOver)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space before (, please.

while (NULL != line) {
char *nextLine = strtok(NULL, "\n");
if ((NULL == nextLine) && (0 == lastCharIsNewline)) {
int readChars = portLibrary->str_printf(portLibrary, carryOver, sizeof(carryOver), "%s", line);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int is inappropriate: str_printf returns uintptr_t

}
line = nextLine;
}
} while (bytesRead < 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bytesRead cannot be negative here (see lines 486-488); please replace the "do...while" loop with a for (;;) loop.

carryOver[0] = '\0';
if (-1 == fd) {
portableError = portLibrary->error_last_error_number(portLibrary);
Trc_PRT_find_executable_name_failedOpeningProcFS(portableError);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please create a new tracepoint, that one has a different meaning/purpose.

portLibrary->error_set_last_error_with_message(
portLibrary,
portableError,
"Failed to open /proc fs");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message should mention the actual path for which open failed.

portLibrary,
portableError,
"Failed to open /proc fs");
return (uintptr_t)portableError;
Copy link
Contributor

@keithc-ca keithc-ca Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casts can't change both the size and signedness in one step; change the size, then the signedness:

		return (uintptr_t)(intptr_t)portableError;

portLibrary->error_set_last_error_with_message(
portLibrary,
portableError,
"Line from /proc/self/maps was truncated due to exceeding buffer size");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The part after "truncated" doesn't help; please omit it.

{
#if defined(LINUX)
/* Length of buffer. */
#define READ_CHUNK_SIZE (PATH_MAX + 100)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't indent macro definitions.

@AditiS11 AditiS11 changed the title jfr: add an api for native libraries Add an API for native libraries Mar 20, 2025
Comment on lines 500 to 511
char *nextLine = strtok(NULL, "\n");
if ((NULL == nextLine) && (0 == lastCharIsNewline)) {
readChars = portLibrary->str_printf(portLibrary, carryOver, sizeof(carryOver), "%s", line);
if (readChars >= sizeof(carryOver)) {
portableError = portLibrary->error_last_error_number(portLibrary);
portLibrary->error_set_last_error_with_message(
portLibrary,
portableError,
"Line from /proc/self/maps was truncated");
carryOver[0] = '\0';
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the timing of this is appropriate: the content of line should be consumed before considering text after the newline.

Copy link
Author

@AditiS11 AditiS11 Mar 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reason I am extracting nextLine in the start is because if nextLine is NULL and the last character of the current line is not \n, I want the line to be copied to the carryOver buffer because the line is incomplete. I don't want the line to be processed further (extracting the name and addresses). I don't want to end up extracting the name and address ranges for incomplete lines. Hence I am adding this check in the start itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not how strtok() works. If combinedBuffer doesn't contain a newline, then line will be NULL.

By the way, we would use strtok_r() instead (it is thread-safe).

But I don't think we need to use strtok_r() either: Instead, this should use file_read_text() which reads only up to the first newline (that will fit in the supplied buffer). Only if one is not present should it be joined to any previous fragment. When a newline is found, the line should be scanned and the information provided to the callback.

Copy link
Author

@AditiS11 AditiS11 Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the carryOver buffer completely as I have changed the implementation to use file_read_text( ). Since the function reads a single line which fits in the buffer.

@AditiS11 AditiS11 force-pushed the nativelib-x64 branch 2 times, most recently from 27ada4e to f8455bf Compare March 28, 2025 17:03
"Failed to open /proc/self/maps");
return (uintptr_t)(intptr_t)portableError;
}
while (NULL != portLibrary->file_read_text(portLibrary, fd, buffer, sizeof(buffer))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file_read_text() may return a partial line if it doesn't fit in the supplied buffer; this needs to check whether the line ends with a newline. If it does not, it might be reasonable for this function to signal failure (an unexpectedly long path name).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please let me know if the function should signal failure and stop further enumeration or continue with reading the further entries in the file?

Comment on lines 490 to 493
memset(path, 0, sizeof(path));
count = sscanf(
buffer,
"%p-%p %4s %lx %x:%x %lu %s",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest that the local path is not needed; instead of %s for the final pattern, use %n to learn the offset within buffer where the path is located.

Use /proc file system to capture the dependent libraries.
Invoke the callback on each library.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants