Skip to content

Fix Debugger timeout on 32 bit devices. #9869

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

Merged
merged 5 commits into from
Mar 4, 2025

Conversation

dellis1972
Copy link
Contributor

@dellis1972 dellis1972 commented Mar 3, 2025

Fixes: #9573

Context: 8e1c0e6

A customer reports that they are unable to attach a debugger to
32-bit Android apps:

> am start -a "android.intent.action.MAIN" -c "android.intent.category.LAUNCHER" -n "com.companyname.exemploandroid/crc64358cda76bdc6f75f.MainActivity"
> Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.companyname.exemploandroid/crc64358cda76bdc6f75f.MainActivity }
…
[monodroid-debug] Trying to initialize the debugger with options: --debugger-agent=transport=dt_socket,loglevel=0,address=127.0.0.1:8805,server=y,embedding=1,timeout=8
…
[mono] Listening on 127.0.0.1:8805 (timeout=8 ms)...
[mono] debugger-agent: Timed out waiting to connect.

Of particular note from the above log messages is the timeout=8
value, which is considerably lower than it needs to be, which is a
value in milliseconds. This low value is responsible for the
subsequent debugger-agent: Timed out log message.

The timeout= value was introduced in commit 8e1c0e6, which used
%d to convert the timeout_time value; for context:

struct RuntimeOptions {
  int64_t timeout_time = 0;
  // …
};
// …
char *debug_arg = utils.monodroid_strdup_printf (
    "--debugger-agent=transport=dt_socket,loglevel=%d,address=%s:%d,%sembedding=1,timeout=%d",
    loglevel,
    options.host,
    options.sdb_port,
    options.server ? "server=y," : "",
    options.timeout_time
);

options is a RuntimeOptions, and options.timeout_time is thus a
int64_t, but it's being printfd via %d.

%d is supposed to be an int; from printf(3):

d, i
The int argument is converted to signed decimal notation.

which means using %d for an int64_t will only work properly on
ILP64 targets. Android, notably, is an ILP32 (32-bit) or
LP64 (64-bit) target, never ILP64; it's a wonder this worked
anywhere, with any degree of reliability.

The fix is to realize that it doesn't even make sense to be
forwarding RuntimeOptions::timeout_time in this manner in the first
place: RuntimeOptions::timeout_time is compared against
time(NULL), i.e. it's a Unix time value (seconds since
1970-01-01 UTC), not a value in milliseconds at all!

Replacing the use of options.timeout_time with 30000 allows for
a value that is reasonable for the target domain, and works
properly and consistently on both ILP32 (32-bit) and LP64 (64-bit)
Android targets.

Context #9573

Not sure why, but we are getting an odd problem were the
`timeout` value we pass to mono for the debugger is not
long enough. This is causing the debugger to timeout.

What we see is `timeout=3` rather than `timeout=1740583188`.
Lets upgrade to use `std:format` to see if that helps as it
with automatically take care of the conversion for us.
@dellis1972
Copy link
Contributor Author

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@dellis1972
Copy link
Contributor Author

Sorry opened the previous PR from a fork, have to reopen it.

@dellis1972
Copy link
Contributor Author

@akoeplinger any chance you can post the code you posted on the other PR? I had to close that one.

@akoeplinger
Copy link
Member

akoeplinger commented Mar 3, 2025

@dellis1972 the one from #9868 (comment)? basically all of the code is visible, I just pasted monodroid_strdup_vprintf and monodroid_strdup_printf into a blank C++ app in Android Studio and built for armeabi-v7a and deployed to an x86 emulator

@dellis1972
Copy link
Contributor Author

@akoeplinger was able to reproduce the wrong conversion issue with %d on a sample C++ armv7 app running on an x86 emulator so this should indeed fix it.

image

@dellis1972
Copy link
Contributor Author

never mind, I figured I could just copy and paste 😃

@jonpryor
Copy link
Contributor

jonpryor commented Mar 3, 2025

Fixes: https://github.com/dotnet/android/issues/9573

Context: 8e1c0e6e2f4c41c9a24904bb1cea943357d78ac4

A customer reports that they are unable to attach a debugger to
32-bit Android apps:

	> am start -a "android.intent.action.MAIN" -c "android.intent.category.LAUNCHER" -n "com.companyname.exemploandroid/crc64358cda76bdc6f75f.MainActivity"
	> Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.companyname.exemploandroid/crc64358cda76bdc6f75f.MainActivity }
	
	[monodroid-debug] Trying to initialize the debugger with options: --debugger-agent=transport=dt_socket,loglevel=0,address=127.0.0.1:8805,server=y,embedding=1,timeout=8
	
	[mono] Listening on 127.0.0.1:8805 (timeout=8 ms)...
	[mono] debugger-agent: Timed out waiting to connect.

Of particular note from the above log messages is the `timeout=8`
value, which is considerably lower than it needs to be, which is a
[value in *milliseconds*][0].  This low value is responsible for the
subsequent `debugger-agent: Timed out` log message.

The `timeout=` value was introduced in commit 8e1c0e6e, which used
`%d` to convert the `timeout_time` value; [for context][1]:

	struct RuntimeOptions {
	  int64_t timeout_time = 0;
	  // …
	};
	// …
	char *debug_arg = utils.monodroid_strdup_printf (
	    "--debugger-agent=transport=dt_socket,loglevel=%d,address=%s:%d,%sembedding=1,timeout=%d",
	    loglevel,
	    options.host,
	    options.sdb_port,
	    options.server ? "server=y," : "",
	    options.timeout_time
	);

`options` is a `RuntimeOptions`, and `options.timeout_time` is thus a
`int64_t`, but it's being `printf`d via `%d`.

`%d` is supposed to be an *int*; from [**printf**(3)][2]:

> **d**, **i**  
> The *int* argument is converted to signed decimal notation. 

which means using `%d` for an `int64_t` will only work properly on
ILP64 targets.  Android, notably, is an ILP32 (32-bit) or
LP64 (64-bit) target, *never* ILP64; it's a wonder this worked
*anywhere*, with any degree of reliability.

The fix is to realize that it doesn't even make sense to be
forwarding `RuntimeOptions::timeout_time` in this manner in the first
place: `RuntimeOptions::timeout_time` is compared against
`time(NULL)`, i.e. it's a [Unix time value][3] (*seconds* since
1970-01-01 UTC), not a value in milliseconds at all!

Replacing the use of `options.timeout_time` with 30000 allows for
a value that is reasonable for the target domain, *and* works
properly and consistently on both ILP32 (32-bit) and LP64 (64-bit)
Android targets.

[0]: https://github.com/dotnet/runtime/blob/9022f3a9b63b56234726606bc5547378b2d08f6b/src/mono/mono/component/debugger-agent.c#L581
[1]: https://github.com/dotnet/android/blob/8e1c0e6e2f4c41c9a24904bb1cea943357d78ac4/src/monodroid/jni/monodroid-glue-internal.hh#L98-L106
[2]: https://linux.die.net/man/3/printf
[3]: https://en.wikipedia.org/wiki/Unix_time

@@ -504,15 +504,10 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse
{
#if defined (DEBUG)
RuntimeOptions options{};
int64_t cur_time;
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't want to remove this check either. We want just the change to the --debugger-agent string.

@jonpryor jonpryor merged commit 93b17c0 into main Mar 4, 2025
54 of 57 checks passed
@jonpryor jonpryor deleted the dev/dellis1972/debuggeroverflow branch March 4, 2025 20:41
@github-actions github-actions bot locked and limited conversation to collaborators Apr 4, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ARM 32-bit] Unable to start debugging with an android physical device (Hot Reload)
3 participants