├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── penguin
│ │ │ │ └── opencore
│ │ │ │ └── tester
│ │ │ │ ├── LeakMemory.java
│ │ │ │ ├── TesterApp.java
│ │ │ │ └── MainActivity.java
│ │ └── cpp
│ │ │ ├── native-lib.cpp
│ │ │ └── CMakeLists.txt
│ ├── test
│ │ └── java
│ │ │ └── penguin
│ │ │ └── opencore
│ │ │ └── tester
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── penguin
│ │ └── opencore
│ │ └── tester
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── opencore
├── .gitignore
├── src
│ ├── main
│ │ ├── cpp
│ │ │ ├── VERSION
│ │ │ ├── eajni
│ │ │ │ ├── include
│ │ │ │ │ └── eajnis
│ │ │ │ │ │ ├── Log.h
│ │ │ │ │ │ ├── Thread.h
│ │ │ │ │ │ └── AndroidJNI.h
│ │ │ │ ├── Thread.cpp
│ │ │ │ └── AndroidJNI.cpp
│ │ │ ├── opencore
│ │ │ │ ├── arm
│ │ │ │ │ ├── opencore.h
│ │ │ │ │ └── opencore.cpp
│ │ │ │ ├── x86
│ │ │ │ │ ├── opencore.h
│ │ │ │ │ └── opencore.cpp
│ │ │ │ ├── riscv64
│ │ │ │ │ ├── opencore.h
│ │ │ │ │ └── opencore.cpp
│ │ │ │ ├── arm64
│ │ │ │ │ ├── opencore.h
│ │ │ │ │ └── opencore.cpp
│ │ │ │ ├── x86_64
│ │ │ │ │ ├── opencore.h
│ │ │ │ │ └── opencore.cpp
│ │ │ │ ├── lp32
│ │ │ │ │ ├── opencore.h
│ │ │ │ │ └── opencore.cpp
│ │ │ │ ├── lp64
│ │ │ │ │ ├── opencore.h
│ │ │ │ │ └── opencore.cpp
│ │ │ │ ├── opencore.h
│ │ │ │ └── opencore.cpp
│ │ │ ├── CMakeLists.txt
│ │ │ └── opencore_jni.cpp
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── penguin
│ │ │ └── opencore
│ │ │ └── sdk
│ │ │ └── Coredump.java
│ ├── test
│ │ └── java
│ │ │ └── penguin
│ │ │ └── opencore
│ │ │ └── sdk
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── penguin
│ │ └── opencore
│ │ └── sdk
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── jitpack.yml
├── script
├── build.sh
└── build_opencore.sh
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── gradlew
├── README.md
└── LICENSE
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/opencore/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/VERSION:
--------------------------------------------------------------------------------
1 | MAJOR=1
2 | MINOR=4
3 | PATCH=16
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='OpenCoreSDK'
2 | include ':app', ':opencore'
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OpenCoreSDK
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | before_install:
2 | - sdk install java 11.0.10-open
3 | - sdk use java 11.0.10-open
4 |
5 | jdk:
6 | - openjdk11
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Penguin38/OpenCoreSDK/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/opencore/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Jun 04 02:10:22 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/script/build.sh:
--------------------------------------------------------------------------------
1 | if [ -z $JAVA_HOME ];then
2 | echo "JAVA_HOME is not set"
3 | echo "Example:"
4 | echo " export JAVA_HOME=JDK_DIR"
5 | echo " ./script/build.sh"
6 | exit
7 | fi
8 | ./gradlew clean -Pgroup=com.github.Penguin38 -Pversion=opencore-1.4.16 -xtest -xlint assemble publishToMavenLocal
9 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | .idea
4 | /local.properties
5 | /.idea/caches
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | /.idea/navEditor.xml
10 | /.idea/assetWizardSettings.xml
11 | .DS_Store
12 | /build
13 | /captures
14 | .externalNativeBuild
15 | .cxx
16 | mybuild.sh
17 | clocline.sh
18 | /output
19 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/penguin/opencore/tester/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package penguin.opencore.tester;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/opencore/src/test/java/penguin/opencore/sdk/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package penguin.opencore.sdk;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/opencore/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/opencore/src/androidTest/java/penguin/opencore/sdk/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package penguin.opencore.sdk;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("penguin.opencore.sdk", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/penguin/opencore/tester/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package penguin.opencore.tester;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("penguin.opencore.tester", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/penguin/opencore/tester/LeakMemory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package penguin.opencore.tester;
18 |
19 | public class LeakMemory {
20 | private byte[] data = new byte[65536];
21 |
22 | public LeakMemory() {
23 | for (int i = 0; i < data.length; i++) {
24 | data[i] = (byte) 0xaa;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/cpp/native-lib.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | extern "C"
22 | JNIEXPORT void JNICALL
23 | Java_penguin_opencore_tester_MainActivity_nativeCrashJNI(JNIEnv *env, jobject thiz) {
24 | int *p = nullptr;
25 | *p = 1;
26 | }
27 |
28 | extern "C"
29 | JNIEXPORT void JNICALL
30 | Java_penguin_opencore_tester_MainActivity_nativeAbortJNI(JNIEnv *env, jobject thiz) {
31 | abort();
32 | }
33 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/eajni/include/eajnis/Log.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef EAJNI_LOG_H
18 | #define EAJNI_LOG_H
19 |
20 | #include
21 |
22 | #ifndef LOG_TAG
23 | #define LOG_TAG "JNI"
24 | #endif
25 |
26 | #ifdef __cplusplus
27 | extern "C" {
28 | #endif //__cplusplus
29 |
30 | #define JNI_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
31 | #define JNI_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
32 | #define JNI_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
33 | #define JNI_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
34 | #define JNI_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
35 | #define JNI_LOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
36 |
37 | #ifdef __cplusplus
38 | }
39 | #endif //__cplusplus
40 |
41 | #endif //EAJNI_LOG_H
42 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/eajni/include/eajnis/Thread.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef EAJNI_THREAD_H
18 | #define EAJNI_THREAD_H
19 |
20 | #include
21 |
22 | #ifdef __cplusplus
23 | extern "C" {
24 | #endif
25 |
26 | typedef void* android_thread_id_t;
27 | typedef int (*android_thread_func_t)(void*);
28 |
29 | #ifdef __cplusplus
30 | } // extern "C"
31 | #endif
32 |
33 | #ifdef __cplusplus
34 | enum {
35 | ANDROID_PRIORITY_BACKGROUND = 10,
36 | ANDROID_PRIORITY_NORMAL = 0,
37 | ANDROID_PRIORITY_DEFAULT = ANDROID_PRIORITY_NORMAL,
38 | };
39 |
40 | class Thread {
41 | public:
42 | static int androidCreateRawThreadEtc(
43 | android_thread_func_t entryFunction,
44 | void *userData,
45 | const char* threadName,
46 | int32_t threadPriority,
47 | size_t threadStackSize,
48 | int32_t threadCreate,
49 | android_thread_id_t *threadId);
50 | };
51 |
52 | #endif // __cplusplus
53 |
54 | #endif //EAJNI_THREAD_H
55 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 30
5 | buildToolsVersion "30.0.3"
6 |
7 | defaultConfig {
8 | applicationId "penguin.opencore.tester"
9 | minSdkVersion 21
10 | targetSdkVersion 30
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 |
16 | externalNativeBuild {
17 | cmake {
18 | abiFilters "arm64-v8a", "armeabi-v7a", "x86_64", "x86"
19 | cppFlags "-std=gnu++17"
20 | }
21 | }
22 |
23 | ndk{
24 | abiFilters "arm64-v8a", "armeabi-v7a", "x86_64", "x86"
25 | }
26 |
27 | ndkVersion "22.1.7171670"
28 | }
29 |
30 | buildTypes {
31 | release {
32 | minifyEnabled false
33 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
34 | }
35 | }
36 |
37 | externalNativeBuild {
38 | cmake {
39 | path "src/main/cpp/CMakeLists.txt"
40 | version "3.10.2"
41 | }
42 | }
43 | }
44 |
45 | dependencies {
46 | implementation fileTree(dir: 'libs', include: ['*.jar'])
47 |
48 | implementation 'androidx.appcompat:appcompat:1.1.0'
49 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
50 | testImplementation 'junit:junit:4.12'
51 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
52 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
53 | implementation project(path: ':opencore')
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/eajni/Thread.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include
18 | #include
19 |
20 | #include
21 | #include
22 |
23 | typedef void* (*android_pthread_entry)(void*);
24 |
25 | int Thread::androidCreateRawThreadEtc(android_thread_func_t entryFunction, void *userData,
26 | const char *threadName, int32_t threadPriority, size_t threadStackSize,
27 | int32_t threadCreate, android_thread_id_t *threadId) {
28 | pthread_attr_t attr;
29 | pthread_attr_init(&attr);
30 | pthread_attr_setdetachstate(&attr, threadCreate);
31 |
32 | if (threadStackSize) {
33 | pthread_attr_setstacksize(&attr, threadStackSize);
34 | }
35 |
36 | errno = 0;
37 | pthread_t thread;
38 | int result = pthread_create(&thread, &attr, (android_pthread_entry)entryFunction, userData);
39 |
40 | pthread_attr_destroy(&attr);
41 | if (result != 0) {
42 | JNI_LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d, threadPriority=%d)",
43 | entryFunction, result, errno, threadPriority);
44 | return 0;
45 | }
46 |
47 | if (threadId != NULL) {
48 | *threadId = (android_thread_id_t)thread;
49 | }
50 | return 1;
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # For more information about using CMake with Android Studio, read the
2 | # documentation: https://d.android.com/studio/projects/add-native-code.html
3 |
4 | # Sets the minimum version of CMake required to build the native library.
5 |
6 | cmake_minimum_required(VERSION 3.4.1)
7 |
8 | # Creates and names a library, sets it as either STATIC
9 | # or SHARED, and provides the relative paths to its source code.
10 | # You can define multiple libraries, and CMake builds them for you.
11 | # Gradle automatically packages shared libraries with your APK.
12 |
13 | add_library( # Sets the name of the library.
14 | native-lib
15 |
16 | # Sets the library as a shared library.
17 | SHARED
18 |
19 | # Provides a relative path to your source file(s).
20 | native-lib.cpp )
21 |
22 | # Searches for a specified prebuilt library and stores the path as a
23 | # variable. Because CMake includes system libraries in the search path by
24 | # default, you only need to specify the name of the public NDK library
25 | # you want to add. CMake verifies that the library exists before
26 | # completing its build.
27 |
28 | find_library( # Sets the name of the path variable.
29 | log-lib
30 |
31 | # Specifies the name of the NDK library that
32 | # you want CMake to locate.
33 | log )
34 |
35 | # Specifies libraries CMake should link to your target library. You
36 | # can link multiple libraries, such as libraries you define in this
37 | # build script, prebuilt third-party libraries, or system libraries.
38 |
39 | target_link_libraries( # Specifies the target library.
40 | native-lib
41 |
42 | # Links the target library to the log library
43 | # included in the NDK.
44 | ${log-lib} )
45 |
46 | set_target_properties(native-lib PROPERTIES LINK_FLAGS "-Wl,-z,max-page-size=16384")
47 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/eajni/include/eajnis/AndroidJNI.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef EAJNI_ANDROIDJNI_H
18 | #define EAJNI_ANDROIDJNI_H
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | #define ANDROID_JNI_VERSION "1.1"
25 |
26 | #ifdef __cplusplus
27 | namespace android {
28 |
29 | class AndroidJNI {
30 | public:
31 | static std::string getVersion() { return ANDROID_JNI_VERSION; }
32 |
33 | static void init(JavaVM *vm) { mJavaVM = vm; }
34 |
35 | static JavaVM *getJavaVM() { return mJavaVM; }
36 |
37 | static JNIEnv *getJNIEnv();
38 |
39 | static android_thread_id_t
40 | createJavaThread(const char *name, void (*start)(void *), void *arg);
41 | static android_thread_id_t
42 | createJavaThread(const char *name, void (*start)(void *), void *arg, bool canwait);
43 |
44 | private:
45 | static JavaVM *mJavaVM;
46 |
47 | static int javaCreateThreadEtc(
48 | android_thread_func_t entryFunction,
49 | void *userData,
50 | const char *threadName,
51 | int32_t threadPriority,
52 | size_t threadStackSize,
53 | int32_t threadCreate,
54 | android_thread_id_t *threadId);
55 |
56 | static int javaThreadShell(void *args);
57 | };
58 | }
59 | #endif // __cplusplus
60 |
61 | #endif //EAJNI_ANDROIDJNI_H
62 |
--------------------------------------------------------------------------------
/opencore/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'maven-publish'
4 | }
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.3"
9 |
10 | defaultConfig {
11 | //applicationId "penguin.opencore.sdk"
12 | //minSdkVersion 29
13 | //targetSdkVersion 30
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 |
19 | externalNativeBuild {
20 | cmake {
21 | abiFilters "arm64-v8a", "armeabi-v7a", "x86_64", "x86"
22 | cppFlags "-std=gnu++17"
23 | }
24 | }
25 |
26 | ndk{
27 | abiFilters "arm64-v8a", "armeabi-v7a", "x86_64", "x86"
28 | }
29 |
30 | ndkVersion "22.1.7171670"
31 | }
32 |
33 | buildTypes {
34 | release {
35 | minifyEnabled false
36 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
37 | }
38 | }
39 |
40 | externalNativeBuild {
41 | cmake {
42 | path "src/main/cpp/CMakeLists.txt"
43 | version "3.10.2"
44 | }
45 | }
46 | }
47 |
48 | dependencies {
49 | implementation fileTree(dir: 'libs', include: ['*.jar'])
50 |
51 | testImplementation 'junit:junit:4.12'
52 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
53 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
54 | }
55 |
56 | task androidSourcesJar(type: Jar) {
57 | classifier 'sources'
58 | from android.sourceSets.main.java.srcDirs
59 | }
60 |
61 | afterEvaluate {
62 | publishing {
63 | publications {
64 | release(MavenPublication) {
65 | from components.release
66 | artifact androidSourcesJar
67 | groupId = 'penguin.opencore.sdk'
68 | artifactId = 'opencore'
69 | version = '1.4.16'
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/script/build_opencore.sh:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2025-present, Guanyou.Chen. All rights reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | if [ -z "$BUILD_ANDROID_ABIS" ];then
16 | export BUILD_ANDROID_ABIS="arm64-v8a armeabi-v7a x86_64 x86"
17 | fi
18 | if [ -z $BUILD_TYPE ];then
19 | export BUILD_TYPE="Debug"
20 | fi
21 | if [ -z $BUILD_ANDROID_PLATFORM ];then
22 | export BUILD_ANDROID_PLATFORM="android-30"
23 | fi
24 | export BUILD_PRODUCT="aosp"
25 | export BUILD_TARGET_PAGESIZE_4K="4K"
26 | export BUILD_TARGET_PAGESIZE_16K="16K"
27 | export BUILD_TARGET_PAGESIZE_ANDROID=$BUILD_TARGET_PAGESIZE_16K
28 | export INSTALL_OUTPUT=output/$BUILD_PRODUCT/"$(echo $BUILD_TYPE | tr '[:upper:]' '[:lower:]')"
29 |
30 | if [ $BUILD_PRODUCT == "aosp" ];then
31 | if [ -z $ANDROID_NDK_HOME ];then
32 | echo "ANDROID_NDK_HOME is not set"
33 | echo "Example:"
34 | echo " export ANDROID_NDK_HOME=NDK_DIR"
35 | echo " ./script/build_opencore.sh"
36 | exit
37 | fi
38 | for CURRENT_ANDROID_ABI in $BUILD_ANDROID_ABIS
39 | do
40 | # build open-monitor
41 | cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
42 | -DANDROID_ABI=$CURRENT_ANDROID_ABI \
43 | -DANDROID_NDK=$ANDROID_NDK_HOME \
44 | -DANDROID_PLATFORM=$BUILD_ANDROID_PLATFORM \
45 | -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
46 | opencore/src/main/cpp/CMakeLists.txt \
47 | -B $INSTALL_OUTPUT/android/$CURRENT_ANDROID_ABI/lib
48 |
49 | make -C $INSTALL_OUTPUT/android/$CURRENT_ANDROID_ABI/lib -j8
50 | done
51 | fi
52 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/arm/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_ARM_OPENCORE_IMPL_H_
18 | #define OPENCORE_ARM_OPENCORE_IMPL_H_
19 |
20 | #include "opencore/lp32/opencore.h"
21 |
22 | namespace arm {
23 |
24 | struct pt_regs {
25 | uint32_t regs[13];
26 | uint32_t sp;
27 | uint32_t lr;
28 | uint32_t pc;
29 | uint32_t cpsr;
30 | };
31 |
32 | typedef struct elf32_prstatus {
33 | uint32_t pr_si_signo;
34 | uint32_t pr_si_code;
35 | uint32_t pr_si_errno;
36 | uint16_t pr_cursig;
37 | uint16_t __padding1;
38 | uint32_t pr_sigpend;
39 | uint32_t pr_sighold;
40 | uint32_t pr_pid;
41 | uint32_t pr_ppid;
42 | uint32_t pr_pgrp;
43 | uint32_t pd_sid;
44 | uint64_t pr_utime;
45 | uint64_t pr_stime;
46 | uint64_t pr_cutime;
47 | uint64_t pr_cstime;
48 | struct pt_regs pr_reg;
49 | uint32_t pr_fpvalid;
50 | uint32_t __padding2;
51 | } __attribute__((packed, aligned(1))) Elf32_prstatus;
52 |
53 | class Opencore : public lp32::OpencoreImpl {
54 | public:
55 | Opencore() : lp32::OpencoreImpl(),
56 | prnum(0), prstatus(nullptr) {}
57 | void Finish();
58 | void CreateCorePrStatus(int pid);
59 | void WriteCorePrStatus(FILE* fp);
60 | int IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma);
61 | int getMachine() { return EM_ARM; }
62 | private:
63 | int prnum;
64 | Elf32_prstatus *prstatus;
65 | };
66 |
67 | } // namespace arm
68 |
69 | #endif // OPENCORE_ARM_OPENCORE_IMPL_H_
70 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/x86/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_X86_OPENCORE_IMPL_H_
18 | #define OPENCORE_X86_OPENCORE_IMPL_H_
19 |
20 | #include "opencore/lp32/opencore.h"
21 |
22 | namespace x86 {
23 |
24 | struct pt_regs {
25 | uint32_t ebx, ecx, edx, esi, edi, ebp, eax;
26 | uint16_t ds, __ds, es, __es;
27 | uint16_t fs, __fs, gs, __gs;
28 | uint32_t orig_eax, eip;
29 | uint16_t cs, __cs;
30 | uint32_t eflags, esp;
31 | uint16_t ss, __ss;
32 | };
33 |
34 | typedef struct elf32_prstatus {
35 | uint32_t pr_si_signo;
36 | uint32_t pr_si_code;
37 | uint32_t pr_si_errno;
38 | uint16_t pr_cursig;
39 | uint16_t __padding1;
40 | uint32_t pr_sigpend;
41 | uint32_t pr_sighold;
42 | uint32_t pr_pid;
43 | uint32_t pr_ppid;
44 | uint32_t pr_pgrp;
45 | uint32_t pd_sid;
46 | uint64_t pr_utime;
47 | uint64_t pr_stime;
48 | uint64_t pr_cutime;
49 | uint64_t pr_cstime;
50 | struct pt_regs pr_reg;
51 | uint32_t pr_fpvalid;
52 | } Elf32_prstatus;
53 |
54 | class Opencore : public lp32::OpencoreImpl {
55 | public:
56 | Opencore() : lp32::OpencoreImpl(),
57 | prnum(0), prstatus(nullptr) {}
58 | void Finish();
59 | void CreateCorePrStatus(int pid);
60 | void WriteCorePrStatus(FILE* fp);
61 | int IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma);
62 | int getMachine() { return EM_386; }
63 | private:
64 | int prnum;
65 | Elf32_prstatus *prstatus;
66 | };
67 |
68 | } // namespace x86
69 |
70 | #endif // OPENCORE_X86_OPENCORE_IMPL_H_
71 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | cmake_minimum_required(VERSION 3.10.2)
17 | project("opencore")
18 |
19 | file(READ ${CMAKE_SOURCE_DIR}/VERSION version_contents)
20 | string(REGEX MATCH "MAJOR=([0-9]+)" _ ${version_contents})
21 | set(MAJOR ${CMAKE_MATCH_1})
22 | string(REGEX MATCH "MINOR=([0-9]+)" _ ${version_contents})
23 | set(MINOR ${CMAKE_MATCH_1})
24 | string(REGEX MATCH "PATCH=([0-9]+)" _ ${version_contents})
25 | set(PATCH ${CMAKE_MATCH_1})
26 | add_definitions(-D__OPENCORE_VERSION__="opencore-${MAJOR}.${MINOR}.${PATCH}")
27 |
28 | include_directories(.)
29 | include_directories(eajni/include/)
30 | aux_source_directory(eajni SRC_LIST)
31 | add_library(eajni STATIC ${SRC_LIST})
32 | find_library(log-lib log)
33 | target_link_libraries(eajni ${log-lib})
34 |
35 | if (ANDROID_ABI STREQUAL "arm64-v8a")
36 | set(OPENCORE_IMPL
37 | opencore/lp64/opencore.cpp
38 | opencore/arm64/opencore.cpp)
39 | elseif(ANDROID_ABI STREQUAL "armeabi-v7a")
40 | set(OPENCORE_IMPL
41 | opencore/lp32/opencore.cpp
42 | opencore/arm/opencore.cpp)
43 | elseif(ANDROID_ABI STREQUAL "armeabi")
44 | set(OPENCORE_IMPL
45 | opencore/lp32/opencore.cpp
46 | opencore/arm/opencore.cpp)
47 | elseif(ANDROID_ABI STREQUAL "x86_64")
48 | set(OPENCORE_IMPL
49 | opencore/lp64/opencore.cpp
50 | opencore/x86_64/opencore.cpp)
51 | elseif(ANDROID_ABI STREQUAL "x86")
52 | set(OPENCORE_IMPL
53 | opencore/lp32/opencore.cpp
54 | opencore/x86/opencore.cpp)
55 | elseif(ANDROID_ABI STREQUAL "riscv64")
56 | set(OPENCORE_IMPL
57 | opencore/lp64/opencore.cpp
58 | opencore/riscv64/opencore.cpp)
59 | endif()
60 |
61 | add_library(opencore SHARED
62 | opencore/opencore.cpp
63 | ${OPENCORE_IMPL}
64 | opencore_jni.cpp)
65 | target_link_libraries(opencore eajni)
66 | set_target_properties(opencore PROPERTIES LINK_FLAGS "-Wl,-z,max-page-size=16384")
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
30 |
31 |
41 |
42 |
51 |
52 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/penguin/opencore/tester/TesterApp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package penguin.opencore.tester;
18 |
19 | import android.app.Application;
20 | import android.util.Log;
21 | import penguin.opencore.sdk.Coredump;
22 |
23 | public class TesterApp extends Application {
24 | @Override
25 | public void onCreate() {
26 | super.onCreate();
27 |
28 | Coredump.getInstance().init();
29 |
30 | Coredump.getInstance().setCoreTimeout(Coredump.DEF_TIMEOUT);
31 |
32 | //Coredump.getInstance().setCoreDir(getFilesDir().getAbsolutePath());
33 | //Coredump.getInstance().setCoreDir("/data/local/tmp");
34 | Coredump.getInstance().setCoreDir(getExternalFilesDir(null).getAbsolutePath());
35 | Coredump.getInstance().setCoreFlag(Coredump.FLAG_CORE
36 | | Coredump.FLAG_PROCESS_COMM
37 | | Coredump.FLAG_PID
38 | // | Coredump.FLAG_THREAD_COMM
39 | // | Coredump.FLAG_TID
40 | | Coredump.FLAG_TIMESTAMP);
41 |
42 | Coredump.getInstance().setCoreFilter(Coredump.FILTER_SPECIAL_VMA
43 | // | Coredump.FILTER_FILE_VMA
44 | // | Coredump.FILTER_SHARED_VMA
45 | | Coredump.FILTER_SANITIZER_SHADOW_VMA
46 | | Coredump.FILTER_NON_READ_VMA
47 | | Coredump.FILTER_SIGNAL_CONTEXT
48 | // | Coredump.FILTER_JAVAHEAP_VMA
49 | // | Coredump.FILTER_JIT_CACHE_VMA
50 | /* | Coredump.FILTER_MINIDUMP */);
51 |
52 | Coredump.getInstance().enable(Coredump.JAVA);
53 | Coredump.getInstance().enable(Coredump.NATIVE);
54 |
55 | Log.i(Coredump.TAG, Coredump.getInstance().toString());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/riscv64/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_RISCV64_OPENCORE_IMPL_H_
18 | #define OPENCORE_RISCV64_OPENCORE_IMPL_H_
19 |
20 | #include "opencore/lp64/opencore.h"
21 |
22 | namespace riscv64 {
23 |
24 | struct pt_regs {
25 | uint64_t pc;
26 | uint64_t ra;
27 | uint64_t sp;
28 | uint64_t gp;
29 | uint64_t tp;
30 | uint64_t t0;
31 | uint64_t t1;
32 | uint64_t t2;
33 | uint64_t s0;
34 | uint64_t s1;
35 | uint64_t a0;
36 | uint64_t a1;
37 | uint64_t a2;
38 | uint64_t a3;
39 | uint64_t a4;
40 | uint64_t a5;
41 | uint64_t a6;
42 | uint64_t a7;
43 | uint64_t s2;
44 | uint64_t s3;
45 | uint64_t s4;
46 | uint64_t s5;
47 | uint64_t s6;
48 | uint64_t s7;
49 | uint64_t s8;
50 | uint64_t s9;
51 | uint64_t s10;
52 | uint64_t s11;
53 | uint64_t t3;
54 | uint64_t t4;
55 | uint64_t t5;
56 | uint64_t t6;
57 | };
58 |
59 | typedef struct elf64_prstatus {
60 | uint32_t pr_si_signo;
61 | uint32_t pr_si_code;
62 | uint32_t pr_si_errno;
63 | uint16_t pr_cursig;
64 | uint64_t pr_sigpend;
65 | uint64_t pr_sighold;
66 | uint32_t pr_pid;
67 | uint32_t pr_ppid;
68 | uint32_t pr_pgrp;
69 | uint32_t pd_sid;
70 | uint64_t pr_utime[2];
71 | uint64_t pr_stime[2];
72 | uint64_t pr_cutime[2];
73 | uint64_t pr_cstime[2];
74 | struct pt_regs pr_reg;
75 | uint32_t pr_fpvalid;
76 | } Elf64_prstatus;
77 |
78 | class Opencore : public lp64::OpencoreImpl {
79 | public:
80 | Opencore() : lp64::OpencoreImpl(),
81 | prnum(0), prstatus(nullptr) {}
82 | void Finish();
83 | void CreateCorePrStatus(int pid);
84 | void WriteCorePrStatus(FILE* fp);
85 | int IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma);
86 | int getMachine() { return EM_RISCV; }
87 | private:
88 | int prnum;
89 | Elf64_prstatus *prstatus;
90 | };
91 |
92 | } // namespace riscv64
93 |
94 | #endif // OPENCORE_RISCV64_OPENCORE_IMPL_H_
95 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/arm64/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_ARM64_OPENCORE_IMPL_H_
18 | #define OPENCORE_ARM64_OPENCORE_IMPL_H_
19 |
20 | #include "opencore/lp64/opencore.h"
21 |
22 | namespace arm64 {
23 |
24 | struct pt_regs {
25 | uint64_t regs[31];
26 | uint64_t sp;
27 | uint64_t pc;
28 | uint64_t pstate;
29 | };
30 |
31 | typedef struct elf64_prstatus {
32 | uint32_t pr_si_signo;
33 | uint32_t pr_si_code;
34 | uint32_t pr_si_errno;
35 | uint16_t pr_cursig;
36 | uint64_t pr_sigpend;
37 | uint64_t pr_sighold;
38 | uint32_t pr_pid;
39 | uint32_t pr_ppid;
40 | uint32_t pr_pgrp;
41 | uint32_t pd_sid;
42 | uint64_t pr_utime[2];
43 | uint64_t pr_stime[2];
44 | uint64_t pr_cutime[2];
45 | uint64_t pr_cstime[2];
46 | struct pt_regs pr_reg;
47 | uint32_t pr_fpvalid;
48 | } Elf64_prstatus;
49 |
50 | struct fpsimd_state {
51 | uint64_t vregs[64]; // __uint128_t vregs[32]
52 | uint32_t fpsr;
53 | uint32_t fpcr;
54 | uint32_t __reserved[2];
55 | };
56 |
57 | typedef struct elf64_fpregset {
58 | struct fpsimd_state regs;
59 | } Elf64_fpregset;
60 |
61 | struct tls {
62 | uint64_t tpidr_el0;
63 | uint64_t tpidr2_el0;
64 | };
65 |
66 | typedef struct elf64_tls {
67 | struct tls regs;
68 | } Elf64_tls;
69 |
70 | class Opencore : public lp64::OpencoreImpl {
71 | public:
72 | Opencore() : lp64::OpencoreImpl(),
73 | prnum(0), prstatus(nullptr) {}
74 | void Finish();
75 | void CreateCorePrStatus(int pid);
76 | void WriteCorePrStatus(FILE* fp);
77 | int IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma);
78 | void WriteCoreFpRegs(int tid, FILE* fp);
79 | void WriteCoreTLS(int tid, FILE* fp);
80 | void WriteCorePAC(int tid, FILE* fp);
81 | void WriteCoreMTE(int tid, FILE* fp);
82 | int getMachine() { return EM_AARCH64; }
83 | private:
84 | int prnum;
85 | Elf64_prstatus *prstatus;
86 | };
87 |
88 | } // namespace arm64
89 |
90 | #endif // OPENCORE_ARM64_OPENCORE_IMPL_H_
91 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/x86_64/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_X86_64_OPENCORE_IMPL_H_
18 | #define OPENCORE_X86_64_OPENCORE_IMPL_H_
19 |
20 | #include "opencore/lp64/opencore.h"
21 |
22 | namespace x86_64 {
23 |
24 | struct pt_regs {
25 | uint64_t r15;
26 | uint64_t r14;
27 | uint64_t r13;
28 | uint64_t r12;
29 | uint64_t rbp;
30 | uint64_t rbx;
31 | uint64_t r11;
32 | uint64_t r10;
33 | uint64_t r9;
34 | uint64_t r8;
35 | uint64_t rax;
36 | uint64_t rcx;
37 | uint64_t rdx;
38 | uint64_t rsi;
39 | uint64_t rdi;
40 | uint64_t orig_rax;
41 | uint64_t rip;
42 | uint32_t cs;
43 | uint32_t __cs;
44 | uint64_t flags;
45 | uint64_t rsp;
46 | uint32_t ss;
47 | uint32_t __ss;
48 | uint64_t fs_base;
49 | uint64_t gs_base;
50 | uint32_t ds;
51 | uint32_t __ds;
52 | uint32_t es;
53 | uint32_t __es;
54 | uint32_t fs;
55 | uint32_t __fs;
56 | uint32_t gs;
57 | uint32_t __gs;
58 | };
59 |
60 | typedef struct elf64_prstatus {
61 | uint32_t pr_si_signo;
62 | uint32_t pr_si_code;
63 | uint32_t pr_si_errno;
64 | uint16_t pr_cursig;
65 | uint64_t pr_sigpend;
66 | uint64_t pr_sighold;
67 | uint32_t pr_pid;
68 | uint32_t pr_ppid;
69 | uint32_t pr_pgrp;
70 | uint32_t pd_sid;
71 | uint64_t pr_utime[2];
72 | uint64_t pr_stime[2];
73 | uint64_t pr_cutime[2];
74 | uint64_t pr_cstime[2];
75 | struct pt_regs pr_reg;
76 | uint32_t pr_fpvalid;
77 | } Elf64_prstatus;
78 |
79 | class Opencore : public lp64::OpencoreImpl {
80 | public:
81 | Opencore() : lp64::OpencoreImpl(),
82 | prnum(0), prstatus(nullptr) {}
83 | void Finish();
84 | void CreateCorePrStatus(int pid);
85 | void WriteCorePrStatus(FILE* fp);
86 | int IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma);
87 | int getMachine() { return EM_X86_64; }
88 | private:
89 | int prnum;
90 | Elf64_prstatus *prstatus;
91 | };
92 |
93 | } // namespace x86_64
94 |
95 | #endif // OPENCORE_X86_64_OPENCORE_IMPL_H_
96 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/lp32/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_LP32_OPENCORE_IMPL_H_
18 | #define OPENCORE_LP32_OPENCORE_IMPL_H_
19 |
20 | #include "opencore/opencore.h"
21 | #include
22 |
23 | namespace lp32 {
24 |
25 | class Auxv {
26 | public:
27 | Auxv() : type(0), value(0) {}
28 | void init(uint32_t t, uint32_t v) {
29 | type = t;
30 | value = v;
31 | }
32 | uint32_t type;
33 | uint32_t value;
34 | };
35 |
36 | class File {
37 | public:
38 | File() : begin(0), end(0), offset(0) {}
39 | uint32_t begin;
40 | uint32_t end;
41 | uint32_t offset;
42 | };
43 |
44 | class OpencoreImpl : public Opencore {
45 | public:
46 | OpencoreImpl() : Opencore(),
47 | phdr(nullptr), phnum(0),
48 | auxv(nullptr), auxvnum(0),
49 | file(nullptr), fileslen(0) {}
50 | void Finish();
51 | bool DoCoredump(const char* filename);
52 | int NeedFilterFile(Opencore::VirtualMemoryArea& vma);
53 | void Prepare(const char* filename);
54 | void ParseProcessMapsVma(int pid);
55 | void ParserPhdr(int index, Opencore::VirtualMemoryArea& vma);
56 | void ParserNtFile(int index, Opencore::VirtualMemoryArea& vma);
57 | void CreateCoreHeader();
58 | void CreateCoreNoteHeader();
59 | void CreateCoreAUXV(int pid);
60 | void SpecialCoreFilter();
61 |
62 | // ELF Header
63 | void WriteCoreHeader(FILE* fp);
64 |
65 | // Program Headers
66 | void WriteCoreNoteHeader(FILE* fp);
67 | void WriteCoreProgramHeaders(FILE* fp);
68 |
69 | // Segments
70 | void WriteCoreSignalInfo(FILE* fp);
71 | void WriteCoreAUXV(FILE* fp);
72 | void WriteNtFile(FILE* fp);
73 | void AlignNoteSegment(FILE* fp);
74 | void WriteCoreLoadSegment(int pid, FILE* fp);
75 |
76 | uint32_t FindAuxv(uint32_t type);
77 |
78 | virtual void CreateCorePrStatus(int pid) = 0;
79 | virtual void WriteCorePrStatus(FILE* fp) = 0;
80 | virtual int IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma) = 0;
81 | protected:
82 | Elf32_Ehdr ehdr;
83 | Elf32_Phdr *phdr;
84 | int phnum;
85 | Elf32_Phdr note;
86 | lp32::Auxv *auxv;
87 | int auxvnum;
88 | lp32::File *file;
89 | int fileslen;
90 | };
91 |
92 | } // namespace lp32
93 |
94 | #endif // OPENCORE_LP32_OPENCORE_IMPL_H_
95 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/lp64/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_LP64_OPENCORE_IMPL_H_
18 | #define OPENCORE_LP64_OPENCORE_IMPL_H_
19 |
20 | #include "opencore/opencore.h"
21 | #include
22 |
23 | namespace lp64 {
24 |
25 | class Auxv {
26 | public:
27 | Auxv() : type(0), value(0) {}
28 | void init(uint64_t t, uint64_t v) {
29 | type = t;
30 | value = v;
31 | }
32 | uint64_t type;
33 | uint64_t value;
34 | };
35 |
36 | class File {
37 | public:
38 | File() : begin(0), end(0), offset(0) {}
39 | uint64_t begin;
40 | uint64_t end;
41 | uint64_t offset;
42 | };
43 |
44 | class OpencoreImpl : public Opencore {
45 | public:
46 | OpencoreImpl() : Opencore(),
47 | phdr(nullptr), phnum(0),
48 | auxv(nullptr), auxvnum(0),
49 | file(nullptr), fileslen(0) {}
50 | void Finish();
51 | bool DoCoredump(const char* filename);
52 | int NeedFilterFile(Opencore::VirtualMemoryArea& vma);
53 | void Prepare(const char* filename);
54 | void ParseProcessMapsVma(int pid);
55 | void ParserPhdr(int index, Opencore::VirtualMemoryArea& vma);
56 | void ParserNtFile(int index, Opencore::VirtualMemoryArea& vma);
57 | void CreateCoreHeader();
58 | void CreateCoreNoteHeader();
59 | void CreateCoreAUXV(int pid);
60 | void SpecialCoreFilter();
61 |
62 | // ELF Header
63 | void WriteCoreHeader(FILE* fp);
64 |
65 | // Program Headers
66 | void WriteCoreNoteHeader(FILE* fp);
67 | void WriteCoreProgramHeaders(FILE* fp);
68 |
69 | // Segments
70 | void WriteCoreSignalInfo(FILE* fp);
71 | void WriteCoreAUXV(FILE* fp);
72 | void WriteNtFile(FILE* fp);
73 | void AlignNoteSegment(FILE* fp);
74 | void WriteCoreLoadSegment(int pid, FILE* fp);
75 |
76 | uint64_t FindAuxv(uint64_t type);
77 |
78 | virtual void CreateCorePrStatus(int pid) = 0;
79 | virtual void WriteCorePrStatus(FILE* fp) = 0;
80 | virtual int IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma) = 0;
81 | protected:
82 | Elf64_Ehdr ehdr;
83 | Elf64_Phdr *phdr;
84 | int phnum;
85 | Elf64_Phdr note;
86 | lp64::Auxv *auxv;
87 | int auxvnum;
88 | lp64::File *file;
89 | int fileslen;
90 | };
91 |
92 | } // namespace lp64
93 |
94 | #endif // OPENCORE_LP64_OPENCORE_IMPL_H_
95 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/eajni/AndroidJNI.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | #include
22 | #include
23 |
24 | namespace android {
25 | JavaVM *AndroidJNI::mJavaVM = NULL;
26 |
27 | static int javaAttachThread(const char *threadName, JNIEnv **pEnv) {
28 | JavaVMAttachArgs args;
29 | JavaVM *vm;
30 | jint result;
31 |
32 | vm = AndroidJNI::getJavaVM();
33 | assert(vm != NULL);
34 |
35 | args.version = JNI_VERSION_1_4;
36 | args.name = (char *) threadName;
37 | args.group = NULL;
38 |
39 | result = vm->AttachCurrentThread(pEnv, (void *) &args);
40 |
41 | if (result != JNI_OK)
42 | JNI_LOGE("attach of thread '%s' failed\n", threadName);
43 |
44 | return result;
45 | }
46 |
47 | static int javaDetachThread(void) {
48 | JavaVM *vm;
49 | jint result;
50 |
51 | vm = AndroidJNI::getJavaVM();
52 | assert(vm != NULL);
53 |
54 | result = vm->DetachCurrentThread();
55 | if (result != JNI_OK)
56 | JNI_LOGE("thread detach failed\n");
57 |
58 | return result;
59 | }
60 |
61 | JNIEnv *AndroidJNI::getJNIEnv() {
62 | JNIEnv *env;
63 | JavaVM *vm = AndroidJNI::getJavaVM();
64 | assert(vm != NULL);
65 |
66 | if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK)
67 | return NULL;
68 |
69 | return env;
70 | }
71 |
72 | int AndroidJNI::javaThreadShell(void *args) {
73 | void *start = ((void **) args)[0];
74 | void *userData = ((void **) args)[1];
75 | char *name = (char *) ((void **) args)[2];
76 | free(args);
77 |
78 | JNIEnv *env;
79 | int result;
80 |
81 | if (javaAttachThread(name, &env) != JNI_OK)
82 | return -1;
83 |
84 | result = (*(android_thread_func_t) start)(userData);
85 |
86 | javaDetachThread();
87 | free(name);
88 |
89 | return result;
90 | }
91 |
92 | int AndroidJNI::javaCreateThreadEtc(
93 | android_thread_func_t entryFunction,
94 | void *userData,
95 | const char *threadName,
96 | int32_t threadPriority,
97 | size_t threadStackSize,
98 | int32_t threadCreate,
99 | android_thread_id_t *threadId) {
100 |
101 | void **args = (void **) malloc(3 * sizeof(void *));
102 | int result;
103 |
104 | if (!threadName)
105 | threadName = "unnamed thread";
106 |
107 | args[0] = (void *) entryFunction;
108 | args[1] = userData;
109 | args[2] = (void *) strdup(threadName);
110 |
111 | result = Thread::androidCreateRawThreadEtc(AndroidJNI::javaThreadShell, args,
112 | threadName, threadPriority, threadStackSize,
113 | threadCreate, threadId);
114 |
115 | return result;
116 | }
117 |
118 | android_thread_id_t
119 | AndroidJNI::createJavaThread(const char *name, void (*start)(void *), void *arg) {
120 | android_thread_id_t thread_id = 0;
121 | javaCreateThreadEtc((android_thread_func_t) start, arg, name, ANDROID_PRIORITY_DEFAULT, 0,
122 | PTHREAD_CREATE_DETACHED, &thread_id);
123 | return thread_id;
124 | }
125 |
126 | android_thread_id_t
127 | AndroidJNI::createJavaThread(const char *name, void (*start)(void *), void *arg, bool canwait) {
128 | android_thread_id_t thread_id = 0;
129 | javaCreateThreadEtc((android_thread_func_t) start, arg, name, ANDROID_PRIORITY_DEFAULT, 0,
130 | canwait? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED, &thread_id);
131 | return thread_id;
132 | }
133 | } // namespace android
134 |
--------------------------------------------------------------------------------
/app/src/main/java/penguin/opencore/tester/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package penguin.opencore.tester;
18 |
19 | import androidx.appcompat.app.AppCompatActivity;
20 |
21 | import android.os.Bundle;
22 | import android.os.Process;
23 | import android.util.Log;
24 | import android.view.View;
25 | import android.widget.Button;
26 | import android.widget.Toast;
27 |
28 | import java.text.SimpleDateFormat;
29 | import java.util.Date;
30 | import java.util.ArrayList;
31 |
32 | import penguin.opencore.sdk.Coredump;
33 |
34 | public class MainActivity extends AppCompatActivity
35 | implements View.OnClickListener, Coredump.Listener {
36 |
37 | // Used to load the 'native-lib' library on application startup.
38 | static {
39 | System.loadLibrary("native-lib");
40 | }
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_main);
46 |
47 | Coredump.getInstance().setListener(this);
48 | findViewById(R.id.button).setOnClickListener(this);
49 | findViewById(R.id.button2).setOnClickListener(this);
50 | findViewById(R.id.button3).setOnClickListener(this);
51 | findViewById(R.id.button4).setOnClickListener(this);
52 | findViewById(R.id.button5).setOnClickListener(this);
53 | }
54 |
55 | private void doJavaCrash() {
56 | new Thread(new Runnable() {
57 | @Override
58 | public void run() {
59 | View view = null;
60 | view.callOnClick();
61 | }
62 | }).start();
63 | }
64 |
65 | private void doNativeCrash() {
66 | new Thread(new Runnable() {
67 | @Override
68 | public void run() {
69 | nativeCrashJNI();
70 | }
71 | }).start();
72 | }
73 |
74 | private void doDirectJavaCore() {
75 | SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
76 | Date date = new Date(System.currentTimeMillis());
77 | Coredump.getInstance().doCoredump(format.format(date) + ".core." + Process.myTid());
78 | }
79 |
80 | private void doAbort() {
81 | new Thread(new Runnable() {
82 | @Override
83 | public void run() {
84 | nativeAbortJNI();
85 | }
86 | }).start();
87 | }
88 |
89 | private void doOOM() {
90 | new Thread(new Runnable() {
91 | @Override
92 | public void run() {
93 | ArrayList array = new ArrayList();
94 | while (true) {
95 | array.add(new LeakMemory());
96 | }
97 | }
98 | }).start();
99 | }
100 |
101 | @Override
102 | public void onClick(View view) {
103 | switch (view.getId()) {
104 | case R.id.button:
105 | doJavaCrash();
106 | break;
107 | case R.id.button2:
108 | doNativeCrash();
109 | break;
110 | case R.id.button3:
111 | doDirectJavaCore();
112 | break;
113 | case R.id.button4:
114 | doAbort();
115 | break;
116 | case R.id.button5:
117 | doOOM();
118 | break;
119 | }
120 | }
121 |
122 | @Override
123 | public void onCompleted(String path) {
124 | Log.i(Coredump.TAG, path);
125 | Toast.makeText(MainActivity.this, path, Toast.LENGTH_LONG).show();
126 | }
127 | /**
128 | * A native method that is implemented by the 'native-lib' native library,
129 | * which is packaged with this application.
130 | */
131 | public native void nativeCrashJNI();
132 | public native void nativeAbortJNI();
133 | }
134 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/arm/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "arm-opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/arm/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | namespace arm {
30 |
31 | void Opencore::CreateCorePrStatus(int pid) {
32 | if (!threads.size()) return;
33 |
34 | prnum = threads.size();
35 | prstatus = (Elf32_prstatus *)malloc(prnum * sizeof(Elf32_prstatus));
36 | memset(prstatus, 0, prnum * sizeof(Elf32_prstatus));
37 |
38 | int cur = 1;
39 | for (int index = 0; index < prnum; index++) {
40 | pid_t tid = threads[index].pid;
41 | int idx;
42 | if (tid == getTid()) {
43 | idx = 0;
44 | prstatus[idx].pr_pid = tid;
45 | // top thread maybe use ucontext prs
46 | if (getContext()) {
47 | struct ucontext *context = (struct ucontext *) getContext();
48 | memcpy(&prstatus[idx].pr_reg, &context->uc_mcontext.arm_r0, sizeof(arm::pt_regs));
49 | continue;
50 | }
51 | } else {
52 | // 0 top thread was truncated
53 | idx = (cur >= prnum) ? 0 : cur;
54 | ++cur;
55 | prstatus[idx].pr_pid = tid;
56 | }
57 |
58 | struct iovec ioVec = {
59 | &prstatus[idx].pr_reg,
60 | sizeof(arm::pt_regs),
61 | };
62 |
63 | if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &ioVec) < 0)
64 | continue;
65 | }
66 |
67 | extra_note_filesz += (sizeof(Elf32_prstatus) + sizeof(Elf32_Nhdr) + 8) * prnum;
68 | extra_note_filesz += sizeof(siginfo_t) + sizeof(Elf32_Nhdr) + 8; // NT_SIGINFO
69 | }
70 |
71 | void Opencore::WriteCorePrStatus(FILE* fp) {
72 | Elf32_Nhdr elf_nhdr;
73 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
74 | elf_nhdr.n_descsz = sizeof(Elf32_prstatus);
75 | elf_nhdr.n_type = NT_PRSTATUS;
76 |
77 | char magic[8];
78 | memset(magic, 0, sizeof(magic));
79 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
80 |
81 | for (int index = 0; index < prnum; index++) {
82 | fwrite(&elf_nhdr, sizeof(Elf32_Nhdr), 1, fp);
83 | fwrite(magic, sizeof(magic), 1, fp);
84 | fwrite(&prstatus[index], sizeof(Elf32_prstatus), 1, fp);
85 | if (!index) WriteCoreSignalInfo(fp);
86 | }
87 | }
88 |
89 | int Opencore::IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma) {
90 | int filter = getFilter();
91 | if (filter & FILTER_MINIDUMP) {
92 | if (!prnum)
93 | return VMA_NULL;
94 |
95 | arm::pt_regs *regs = &prstatus[0].pr_reg;
96 | if (regs->pc >= vma.begin && regs->pc < vma.end
97 | || regs->regs[0] >= vma.begin && regs->regs[0] < vma.end
98 | || regs->regs[1] >= vma.begin && regs->regs[1] < vma.end
99 | || regs->regs[2] >= vma.begin && regs->regs[2] < vma.end
100 | || regs->regs[3] >= vma.begin && regs->regs[3] < vma.end
101 | || regs->regs[4] >= vma.begin && regs->regs[4] < vma.end
102 | || regs->regs[5] >= vma.begin && regs->regs[5] < vma.end
103 | || regs->regs[6] >= vma.begin && regs->regs[6] < vma.end
104 | || regs->regs[7] >= vma.begin && regs->regs[7] < vma.end
105 | || regs->regs[8] >= vma.begin && regs->regs[8] < vma.end
106 | || regs->regs[9] >= vma.begin && regs->regs[9] < vma.end
107 | || regs->regs[10] >= vma.begin && regs->regs[10] < vma.end
108 | || regs->regs[11] >= vma.begin && regs->regs[11] < vma.end
109 | || regs->regs[12] >= vma.begin && regs->regs[12] < vma.end
110 | || regs->sp >= vma.begin && regs->sp < vma.end
111 | || regs->lr >= vma.begin && regs->lr < vma.end) {
112 | return VMA_INCLUDE;
113 | }
114 |
115 | return VMA_NULL;
116 | }
117 | return VMA_NORMAL;
118 | }
119 |
120 | void Opencore::Finish() {
121 | if (prstatus) free(prstatus);
122 | lp32::OpencoreImpl::Finish();
123 | }
124 |
125 | } // namespace arm
126 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/x86/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "x86-opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/x86/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | namespace x86 {
30 |
31 | void Opencore::CreateCorePrStatus(int pid) {
32 | if (!threads.size()) return;
33 |
34 | prnum = threads.size();
35 | prstatus = (Elf32_prstatus *)malloc(prnum * sizeof(Elf32_prstatus));
36 | memset(prstatus, 0, prnum * sizeof(Elf32_prstatus));
37 |
38 | int cur = 1;
39 | for (int index = 0; index < prnum; index++) {
40 | pid_t tid = threads[index].pid;
41 | int idx;
42 | if (tid == getTid()) {
43 | idx = 0;
44 | prstatus[idx].pr_pid = tid;
45 | // top thread maybe use ucontext prs
46 | if (getContext()) {
47 | struct ucontext *context = (struct ucontext *) getContext();
48 | x86::pt_regs uc_regs;
49 | memset(&uc_regs, 0x0, sizeof(x86::pt_regs));
50 | uc_regs.ebx = context->uc_mcontext.gregs[8];
51 | uc_regs.ecx = context->uc_mcontext.gregs[10];
52 | uc_regs.edx = context->uc_mcontext.gregs[9];
53 | uc_regs.esi = context->uc_mcontext.gregs[5];
54 | uc_regs.edi = context->uc_mcontext.gregs[4];
55 | uc_regs.ebp = context->uc_mcontext.gregs[6];
56 | uc_regs.eax = context->uc_mcontext.gregs[11];
57 | uc_regs.ds = context->uc_mcontext.gregs[3];
58 | uc_regs.es = context->uc_mcontext.gregs[2];
59 | uc_regs.fs = context->uc_mcontext.gregs[1];
60 | uc_regs.gs = context->uc_mcontext.gregs[0];
61 | uc_regs.orig_eax = context->uc_mcontext.gregs[11];
62 | uc_regs.eip = context->uc_mcontext.gregs[14];
63 | uc_regs.eflags = context->uc_mcontext.gregs[16];
64 | uc_regs.esp = context->uc_mcontext.gregs[7];
65 | uc_regs.ss = context->uc_mcontext.gregs[15];
66 | memcpy(&prstatus[idx].pr_reg, &uc_regs, sizeof(x86::pt_regs));
67 | continue;
68 | }
69 | } else {
70 | // 0 top thread was truncated
71 | idx = (cur >= prnum) ? 0 : cur;
72 | ++cur;
73 | prstatus[idx].pr_pid = tid;
74 | }
75 |
76 | struct iovec ioVec = {
77 | &prstatus[idx].pr_reg,
78 | sizeof(x86::pt_regs),
79 | };
80 |
81 | if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &ioVec) < 0)
82 | continue;
83 | }
84 |
85 | extra_note_filesz += (sizeof(Elf32_prstatus) + sizeof(Elf32_Nhdr) + 8) * prnum;
86 | extra_note_filesz += sizeof(siginfo_t) + sizeof(Elf32_Nhdr) + 8; // NT_SIGINFO
87 | }
88 |
89 | void Opencore::WriteCorePrStatus(FILE* fp) {
90 | Elf32_Nhdr elf_nhdr;
91 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
92 | elf_nhdr.n_descsz = sizeof(Elf32_prstatus);
93 | elf_nhdr.n_type = NT_PRSTATUS;
94 |
95 | char magic[8];
96 | memset(magic, 0, sizeof(magic));
97 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
98 |
99 | for (int index = 0; index < prnum; index++) {
100 | fwrite(&elf_nhdr, sizeof(Elf32_Nhdr), 1, fp);
101 | fwrite(magic, sizeof(magic), 1, fp);
102 | fwrite(&prstatus[index], sizeof(Elf32_prstatus), 1, fp);
103 | if (!index) WriteCoreSignalInfo(fp);
104 | }
105 | }
106 |
107 | int Opencore::IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma) {
108 | int filter = getFilter();
109 | if (filter & FILTER_MINIDUMP) {
110 | if (!prnum)
111 | return VMA_NULL;
112 |
113 | x86::pt_regs *regs = &prstatus[0].pr_reg;
114 | if (regs->ebx >= vma.begin && regs->ebx < vma.end
115 | || regs->edx >= vma.begin && regs->edx < vma.end
116 | || regs->esi >= vma.begin && regs->esi < vma.end
117 | || regs->edi >= vma.begin && regs->edi < vma.end
118 | || regs->ebp >= vma.begin && regs->ebp < vma.end
119 | || regs->eax >= vma.begin && regs->eax < vma.end
120 | || regs->eip >= vma.begin && regs->eip < vma.end
121 | || regs->esp >= vma.begin && regs->esp < vma.end) {
122 | return VMA_INCLUDE;
123 | }
124 |
125 | return VMA_NULL;
126 | }
127 | return VMA_NORMAL;
128 | }
129 |
130 | void Opencore::Finish() {
131 | if (prstatus) free(prstatus);
132 | lp32::OpencoreImpl::Finish();
133 | }
134 |
135 | } // namespace x86
136 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/riscv64/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "riscv64-opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/riscv64/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | namespace riscv64 {
30 |
31 | void Opencore::CreateCorePrStatus(int pid) {
32 | if (!threads.size()) return;
33 |
34 | prnum = threads.size();
35 | prstatus = (Elf64_prstatus *)malloc(prnum * sizeof(Elf64_prstatus));
36 | memset(prstatus, 0, prnum * sizeof(Elf64_prstatus));
37 |
38 | int cur = 1;
39 | for (int index = 0; index < prnum; index++) {
40 | pid_t tid = threads[index].pid;
41 | int idx;
42 | if (tid == getTid()) {
43 | idx = 0;
44 | prstatus[idx].pr_pid = tid;
45 | // top thread maybe use ucontext prs
46 | if (getContext()) {
47 | struct ucontext *context = (struct ucontext *) getContext();
48 | memcpy(&prstatus[idx].pr_reg, &context->uc_mcontext.sc_regs, sizeof(riscv64::pt_regs));
49 | continue;
50 | }
51 | } else {
52 | // 0 top thread was truncated
53 | idx = (cur >= prnum) ? 0 : cur;
54 | ++cur;
55 | prstatus[idx].pr_pid = tid;
56 | }
57 |
58 | struct iovec ioVec = {
59 | &prstatus[idx].pr_reg,
60 | sizeof(riscv64::pt_regs),
61 | };
62 |
63 | if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &ioVec) < 0)
64 | continue;
65 | }
66 |
67 | extra_note_filesz += (sizeof(Elf64_prstatus) + sizeof(Elf64_Nhdr) + 8) * prnum;
68 | extra_note_filesz += sizeof(siginfo_t) + sizeof(Elf64_Nhdr) + 8; // NT_SIGINFO
69 | }
70 |
71 | void Opencore::WriteCorePrStatus(FILE* fp) {
72 | Elf64_Nhdr elf_nhdr;
73 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
74 | elf_nhdr.n_descsz = sizeof(Elf64_prstatus);
75 | elf_nhdr.n_type = NT_PRSTATUS;
76 |
77 | char magic[8];
78 | memset(magic, 0, sizeof(magic));
79 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
80 |
81 | for (int index = 0; index < prnum; index++) {
82 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
83 | fwrite(magic, sizeof(magic), 1, fp);
84 | fwrite(&prstatus[index], sizeof(Elf64_prstatus), 1, fp);
85 | if (!index) WriteCoreSignalInfo(fp);
86 | }
87 | }
88 |
89 | int Opencore::IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma) {
90 | int filter = getFilter();
91 | if (filter & FILTER_MINIDUMP) {
92 | if (!prnum)
93 | return VMA_NULL;
94 |
95 | riscv64::pt_regs *regs = &prstatus[0].pr_reg;
96 | if (regs->pc >= vma.begin && regs->pc < vma.end
97 | || regs->ra >= vma.begin && regs->ra < vma.end
98 | || regs->sp >= vma.begin && regs->sp < vma.end
99 | || regs->gp >= vma.begin && regs->gp < vma.end
100 | || regs->tp >= vma.begin && regs->tp < vma.end
101 | || regs->t0 >= vma.begin && regs->t0 < vma.end
102 | || regs->t1 >= vma.begin && regs->t1 < vma.end
103 | || regs->t2 >= vma.begin && regs->t2 < vma.end
104 | || regs->s0 >= vma.begin && regs->s0 < vma.end
105 | || regs->s1 >= vma.begin && regs->s1 < vma.end
106 | || regs->a0 >= vma.begin && regs->a0 < vma.end
107 | || regs->a1 >= vma.begin && regs->a1 < vma.end
108 | || regs->a2 >= vma.begin && regs->a2 < vma.end
109 | || regs->a3 >= vma.begin && regs->a3 < vma.end
110 | || regs->a4 >= vma.begin && regs->a4 < vma.end
111 | || regs->a5 >= vma.begin && regs->a5 < vma.end
112 | || regs->a6 >= vma.begin && regs->a6 < vma.end
113 | || regs->a7 >= vma.begin && regs->a7 < vma.end
114 | || regs->s2 >= vma.begin && regs->s2 < vma.end
115 | || regs->s3 >= vma.begin && regs->s3 < vma.end
116 | || regs->s4 >= vma.begin && regs->s4 < vma.end
117 | || regs->s5 >= vma.begin && regs->s5 < vma.end
118 | || regs->s6 >= vma.begin && regs->s6 < vma.end
119 | || regs->s7 >= vma.begin && regs->s7 < vma.end
120 | || regs->s8 >= vma.begin && regs->s8 < vma.end
121 | || regs->s9 >= vma.begin && regs->s9 < vma.end
122 | || regs->s10 >= vma.begin && regs->s10 < vma.end
123 | || regs->s11 >= vma.begin && regs->s11 < vma.end
124 | || regs->t3 >= vma.begin && regs->t3 < vma.end
125 | || regs->t4 >= vma.begin && regs->t4 < vma.end
126 | || regs->t5 >= vma.begin && regs->t5 < vma.end
127 | || regs->t6 >= vma.begin && regs->t6 < vma.end) {
128 | return VMA_INCLUDE;
129 | }
130 |
131 | return VMA_NULL;
132 | }
133 | return VMA_NORMAL;
134 | }
135 |
136 | void Opencore::Finish() {
137 | if (prstatus) free(prstatus);
138 | lp64::OpencoreImpl::Finish();
139 | }
140 |
141 | } // namespace riscv64
142 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/x86_64/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "x86_64-opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/x86_64/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | namespace x86_64 {
30 |
31 | void Opencore::CreateCorePrStatus(int pid) {
32 | if (!threads.size()) return;
33 |
34 | prnum = threads.size();
35 | prstatus = (Elf64_prstatus *)malloc(prnum * sizeof(Elf64_prstatus));
36 | memset(prstatus, 0, prnum * sizeof(Elf64_prstatus));
37 |
38 | int cur = 1;
39 | for (int index = 0; index < prnum; index++) {
40 | pid_t tid = threads[index].pid;
41 | int idx;
42 | if (tid == getTid()) {
43 | idx = 0;
44 | prstatus[idx].pr_pid = tid;
45 | // top thread maybe use ucontext prs
46 | if (getContext()) {
47 | struct ucontext *context = (struct ucontext *) getContext();
48 | x86_64::pt_regs uc_regs;
49 | memset(&uc_regs, 0x0, sizeof(x86_64::pt_regs));
50 | uc_regs.r15 = context->uc_mcontext.gregs[7];
51 | uc_regs.r14 = context->uc_mcontext.gregs[6];
52 | uc_regs.r13 = context->uc_mcontext.gregs[5];
53 | uc_regs.r12 = context->uc_mcontext.gregs[4];
54 | uc_regs.rbp = context->uc_mcontext.gregs[10];
55 | uc_regs.rbx = context->uc_mcontext.gregs[11];
56 | uc_regs.r11 = context->uc_mcontext.gregs[3];
57 | uc_regs.r10 = context->uc_mcontext.gregs[2];
58 | uc_regs.r9 = context->uc_mcontext.gregs[1];
59 | uc_regs.r8 = context->uc_mcontext.gregs[0];
60 | uc_regs.rax = context->uc_mcontext.gregs[13];
61 | uc_regs.rcx = context->uc_mcontext.gregs[14];
62 | uc_regs.rdx = context->uc_mcontext.gregs[12];
63 | uc_regs.rsi = context->uc_mcontext.gregs[9];
64 | uc_regs.rdi = context->uc_mcontext.gregs[8];
65 | uc_regs.rip = context->uc_mcontext.gregs[16];
66 | uc_regs.cs = context->uc_mcontext.gregs[18];
67 | uc_regs.flags = context->uc_mcontext.gregs[17];
68 | uc_regs.rsp = context->uc_mcontext.gregs[15];
69 | uc_regs.ss = context->uc_mcontext.gregs[21];
70 | uc_regs.fs = context->uc_mcontext.gregs[20];
71 | uc_regs.gs = context->uc_mcontext.gregs[19];
72 | memcpy(&prstatus[idx].pr_reg, &uc_regs, sizeof(x86_64::pt_regs));
73 | continue;
74 | }
75 | } else {
76 | // 0 top thread was truncated
77 | idx = (cur >= prnum) ? 0 : cur;
78 | ++cur;
79 | prstatus[idx].pr_pid = tid;
80 | }
81 |
82 | struct iovec ioVec = {
83 | &prstatus[idx].pr_reg,
84 | sizeof(x86_64::pt_regs),
85 | };
86 |
87 | if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &ioVec) < 0)
88 | continue;
89 | }
90 |
91 | extra_note_filesz += (sizeof(Elf64_prstatus) + sizeof(Elf64_Nhdr) + 8) * prnum;
92 | extra_note_filesz += sizeof(siginfo_t) + sizeof(Elf64_Nhdr) + 8; // NT_SIGINFO
93 | }
94 |
95 | void Opencore::WriteCorePrStatus(FILE* fp) {
96 | Elf64_Nhdr elf_nhdr;
97 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
98 | elf_nhdr.n_descsz = sizeof(Elf64_prstatus);
99 | elf_nhdr.n_type = NT_PRSTATUS;
100 |
101 | char magic[8];
102 | memset(magic, 0, sizeof(magic));
103 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
104 |
105 | for (int index = 0; index < prnum; index++) {
106 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
107 | fwrite(magic, sizeof(magic), 1, fp);
108 | fwrite(&prstatus[index], sizeof(Elf64_prstatus), 1, fp);
109 | if (!index) WriteCoreSignalInfo(fp);
110 | }
111 | }
112 |
113 | int Opencore::IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma) {
114 | int filter = getFilter();
115 | if (filter & FILTER_MINIDUMP) {
116 | if (!prnum)
117 | return VMA_NULL;
118 |
119 | x86_64::pt_regs *regs = &prstatus[0].pr_reg;
120 | if (regs->r15 >= vma.begin && regs->r15 < vma.end
121 | || regs->r14 >= vma.begin && regs->r14 < vma.end
122 | || regs->r13 >= vma.begin && regs->r13 < vma.end
123 | || regs->r12 >= vma.begin && regs->r12 < vma.end
124 | || regs->rbp >= vma.begin && regs->rbp < vma.end
125 | || regs->rbx >= vma.begin && regs->rbx < vma.end
126 | || regs->r11 >= vma.begin && regs->r11 < vma.end
127 | || regs->r10 >= vma.begin && regs->r10 < vma.end
128 | || regs->r9 >= vma.begin && regs->r9 < vma.end
129 | || regs->r8 >= vma.begin && regs->r8 < vma.end
130 | || regs->rax >= vma.begin && regs->rax < vma.end
131 | || regs->rcx >= vma.begin && regs->rcx < vma.end
132 | || regs->rdx >= vma.begin && regs->rdx < vma.end
133 | || regs->rsi >= vma.begin && regs->rsi < vma.end
134 | || regs->rdi >= vma.begin && regs->rdi < vma.end
135 | || regs->rip >= vma.begin && regs->rip < vma.end) {
136 | return VMA_INCLUDE;
137 | }
138 |
139 | return VMA_NULL;
140 | }
141 | return VMA_NORMAL;
142 | }
143 |
144 | void Opencore::Finish() {
145 | if (prstatus) free(prstatus);
146 | lp64::OpencoreImpl::Finish();
147 | }
148 |
149 | } // namespace x86_64
150 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/opencore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef OPENCORE_OPENCORE_H_
18 | #define OPENCORE_OPENCORE_H_
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #define EM_NONE 0
30 | #define EM_386 3
31 | #define EM_ARM 40
32 | #define EM_X86_64 62
33 | #define EM_AARCH64 183
34 | #define EM_RISCV 243
35 |
36 | #define ELF_PAGE_SIZE 0x1000
37 |
38 | #define ELFCOREMAGIC "CORE"
39 | #define NOTE_CORE_NAME_SZ 5
40 | #define ELFLINUXMAGIC "LINUX"
41 | #define NOTE_LINUX_NAME_SZ 6
42 |
43 | #define GENMASK_UL(h, l) (((~0ULL) << (l)) & (~0ULL >> (64 - 1 - (h))))
44 |
45 | typedef void (*DumpCallback)(const char* path);
46 |
47 | template
48 | constexpr T RoundDown(T x, std::remove_reference_t n) {
49 | return (x & -n);
50 | }
51 |
52 | template
53 | constexpr T RoundUp(T x, std::remove_reference_t n) {
54 | return RoundDown(x + n - 1, n);
55 | }
56 |
57 | class Opencore {
58 | public:
59 | static constexpr int FLAG_CORE = 1 << 0;
60 | static constexpr int FLAG_PROCESS_COMM = 1 << 1;
61 | static constexpr int FLAG_PID = 1 << 2;
62 | static constexpr int FLAG_THREAD_COMM = 1 << 3;
63 | static constexpr int FLAG_TID = 1 << 4;
64 | static constexpr int FLAG_TIMESTAMP = 1 << 5;
65 | static constexpr int FLAG_ALL = FLAG_CORE | FLAG_PROCESS_COMM | FLAG_PID
66 | | FLAG_THREAD_COMM | FLAG_TID | FLAG_TIMESTAMP;
67 |
68 | static constexpr int INVALID_TID = 0;
69 |
70 | static constexpr int FILTER_NONE = 0x0;
71 | static constexpr int FILTER_SPECIAL_VMA = 1 << 0;
72 | static constexpr int FILTER_FILE_VMA = 1 << 1;
73 | static constexpr int FILTER_SHARED_VMA = 1 << 2;
74 | static constexpr int FILTER_SANITIZER_SHADOW_VMA = 1 << 3;
75 | static constexpr int FILTER_NON_READ_VMA = 1 << 4;
76 | static constexpr int FILTER_SIGNAL_CONTEXT = 1 << 5;
77 | static constexpr int FILTER_MINIDUMP = 1 << 6;
78 | static constexpr int FILTER_JAVAHEAP_VMA = 1 << 7;
79 | static constexpr int FILTER_JIT_CACHE_VMA = 1 << 8;
80 |
81 | static constexpr int VMA_NORMAL = 0;
82 | static constexpr int VMA_NULL = 1 << 0;
83 | static constexpr int VMA_INCLUDE = 1 << 1;
84 |
85 | /** only opencore-sdk append **/
86 | static constexpr int DEF_TIMEOUT = 120;
87 |
88 | Opencore() {
89 | flag = FLAG_CORE
90 | | FLAG_PID
91 | | FLAG_PROCESS_COMM
92 | | FLAG_TIMESTAMP;
93 | pid = INVALID_TID;
94 | tid = INVALID_TID;
95 | filter = FILTER_NONE;
96 | extra_note_filesz = 0;
97 | page_size = sysconf(_SC_PAGE_SIZE);
98 | align_size = ELF_PAGE_SIZE;
99 | zero = nullptr;
100 |
101 | /** only opencore-sdk append **/
102 | ucontext_raw = nullptr;
103 | siginfo = nullptr;
104 | cb = nullptr;
105 | timeout = DEF_TIMEOUT;
106 | }
107 |
108 | struct VirtualMemoryArea {
109 | uint64_t begin;
110 | uint64_t end;
111 | char flags[4];
112 | uint32_t offset;
113 | uint32_t major;
114 | uint32_t minor;
115 | uint64_t inode;
116 | std::string file;
117 | };
118 |
119 | struct ThreadRecord {
120 | int pid;
121 | bool attached;
122 | };
123 |
124 | void setDir(const char* d) { dir = d; }
125 | void setPid(int p) { pid = p; }
126 | void setTid(int t) { tid = t; }
127 | void setFilter(int f) { filter = f; }
128 | std::string& getDir() { return dir; }
129 | int getFlag() { return flag; }
130 | int getPid() { return pid; }
131 | int getTid() { return tid; }
132 | int getFilter() { return filter; }
133 | int getExtraNoteFilesz() { return extra_note_filesz; }
134 | bool Coredump(const char* filename);
135 | virtual void Finish();
136 | virtual bool DoCoredump(const char* filename) { return false; }
137 | virtual int NeedFilterFile(Opencore::VirtualMemoryArea& vma) { return VMA_NORMAL; }
138 | virtual int getMachine() { return EM_NONE; }
139 | int IsFilterSegment(Opencore::VirtualMemoryArea& vma);
140 | void StopTheWorld(int pid);
141 | bool StopTheThread(int tid);
142 | void Continue();
143 | static void ParseMaps(int pid, std::vector& maps);
144 |
145 | /** only opencore-sdk append **/
146 | void setFlag(int f) { flag = f; }
147 | void setTimeout(int sec) { timeout = sec; }
148 | void setContext(void *raw) { ucontext_raw = raw; }
149 | void setSignalInfo(void* info) { siginfo = info; }
150 | void setCallback(DumpCallback callback) { cb = callback; }
151 | int getTimeout() { return timeout; }
152 | void* getContext() { return ucontext_raw; }
153 | void* getSignalInfo() { return siginfo; }
154 | DumpCallback getCallback() { return cb; }
155 |
156 | static Opencore* GetInstance();
157 | static const char* GetVersion() { return __OPENCORE_VERSION__; }
158 | static void HandleSignal(int signal, siginfo_t* siginfo, void* ucontext_raw);
159 |
160 | class DumpOption {
161 | public:
162 | DumpOption()
163 | : filename(nullptr),
164 | pid(INVALID_TID), tid(INVALID_TID),
165 | siginfo(nullptr), context(nullptr) {}
166 | char* filename;
167 | int pid;
168 | int tid;
169 | void* siginfo;
170 | void* context;
171 | };
172 |
173 | static void Dump();
174 | static void Dump(const char* filename);
175 | static void Dump(const char* filename, int tid);
176 | static void Dump(siginfo_t* siginfo, void* ucontext_raw);
177 | static void Dump(DumpOption* option);
178 | static bool Enable();
179 | static bool Disable();
180 | static bool IsEnabled();
181 | static void IgnoreHandler();
182 | static void SetDir(const char* dir);
183 | static void SetCallback(DumpCallback cb);
184 | static void SetFlag(int flag);
185 | static void SetTimeout(int sec);
186 | static void SetFilter(int filter);
187 | static void TimeoutHandle(int);
188 | static const char* GetDir();
189 | static int GetFlag();
190 | static int GetTimeout();
191 | static int GetFilter();
192 | protected:
193 | int extra_note_filesz;
194 | std::vector threads;
195 | std::vector maps;
196 | uint8_t* zero;
197 | uint32_t align_size;
198 | uint32_t page_size;
199 |
200 | /** only opencore-sdk append **/
201 | void* ucontext_raw;
202 | void* siginfo;
203 | private:
204 | std::string dir;
205 | int flag;
206 | int pid;
207 | int tid;
208 | int filter;
209 |
210 | /** only opencore-sdk append **/
211 | DumpCallback cb;
212 | int timeout;
213 | };
214 |
215 | #endif // OPENCORE_OPENCORE_H_
216 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore_jni.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include
18 | #include
19 |
20 | #ifndef LOG_TAG
21 | #define LOG_TAG "opencore"
22 | #endif
23 |
24 | #include "opencore/opencore.h"
25 | #include "eajnis/AndroidJNI.h"
26 | #include "eajnis/Log.h"
27 |
28 | #include
29 | #include
30 |
31 | struct userdata {
32 | jclass gCoredump;
33 | jmethodID gCallbackEvent;
34 | };
35 |
36 | static userdata gUser;
37 |
38 | static void penguin_opencore_sdk_coredump_docallback(void *arg) {
39 | if (gUser.gCoredump && gUser.gCallbackEvent) {
40 | const char* path = reinterpret_cast(arg);
41 | JNIEnv *env = android::AndroidJNI::getJNIEnv();
42 | jstring filepath = env->NewStringUTF(path);
43 | env->CallStaticVoidMethod(gUser.gCoredump, gUser.gCallbackEvent, filepath);
44 | } else {
45 | JNI_LOGE("coredump callback err!");
46 | }
47 | }
48 |
49 | static void penguin_opencore_sdk_coredump_callback(const char* filepath) {
50 | pthread_t thread = (pthread_t) android::AndroidJNI::createJavaThread("opencore-cb",
51 | penguin_opencore_sdk_coredump_docallback,
52 | (void *)filepath, true);
53 | if (thread) pthread_join(thread, NULL);
54 | }
55 |
56 | static jstring penguin_opencore_sdk_Coredump_nativeVersion(JNIEnv* env, jclass /*clazz*/) {
57 | return env->NewStringUTF(Opencore::GetVersion());
58 | }
59 |
60 | static jboolean penguin_opencore_sdk_Coredump_nativeEnable(JNIEnv* /*env*/, jclass /*clazz*/) {
61 | return Opencore::Enable();
62 | }
63 |
64 | static jboolean penguin_opencore_sdk_Coredump_nativeDisable(JNIEnv* /*env*/, jclass /*clazz*/) {
65 | return Opencore::Disable();
66 | }
67 |
68 | static jboolean penguin_opencore_sdk_Coredump_nativeCoredump(JNIEnv* env, jclass /*clazz*/, jint tid, jstring filename) {
69 | jboolean isCopy;
70 | if (filename != NULL) {
71 | const char *cstr = env->GetStringUTFChars(filename, &isCopy);
72 | Opencore::Dump(cstr, tid);
73 | env->ReleaseStringUTFChars(filename, cstr);
74 | } else {
75 | Opencore::Dump(nullptr, tid);
76 | }
77 | return true;
78 | }
79 |
80 | static void penguin_opencore_sdk_Coredump_nativeSetDir(JNIEnv* env, jclass /*clazz*/, jstring dir) {
81 | jboolean isCopy;
82 | if (dir != NULL) {
83 | const char *cstr = env->GetStringUTFChars(dir, &isCopy);
84 | Opencore::SetDir(cstr);
85 | env->ReleaseStringUTFChars(dir, cstr);
86 | }
87 | }
88 |
89 | static void penguin_opencore_sdk_Coredump_nativeSetFlag(JNIEnv* /*env*/, jclass /*clazz*/, jint flag) {
90 | Opencore::SetFlag(flag);
91 | }
92 |
93 | static void penguin_opencore_sdk_Coredump_nativeSetTimeout(JNIEnv* /*env*/, jclass /*clazz*/, jint sec) {
94 | Opencore::SetTimeout(sec);
95 | }
96 |
97 | static void penguin_opencore_sdk_Coredump_nativeSetFilter(JNIEnv* /*env*/, jclass /*clazz*/, jint filter) {
98 | Opencore::SetFilter(filter);
99 | }
100 |
101 | static jboolean penguin_opencore_sdk_Coredump_nativeIsEnabled(JNIEnv* /*env*/, jclass /*clazz*/) {
102 | return Opencore::IsEnabled();
103 | }
104 |
105 | static jstring penguin_opencore_sdk_Coredump_nativeGetDir(JNIEnv* env, jclass /*clazz*/) {
106 | const char* dir = Opencore::GetDir();
107 | return env->NewStringUTF(dir);
108 | }
109 |
110 | static jint penguin_opencore_sdk_Coredump_nativeGetFlag(JNIEnv* /*env*/, jclass /*clazz*/) {
111 | return Opencore::GetFlag();
112 | }
113 |
114 | static jint penguin_opencore_sdk_Coredump_nativeGetTimeout(JNIEnv* /*env*/, jclass /*clazz*/) {
115 | return Opencore::GetTimeout();
116 | }
117 |
118 | static jint penguin_opencore_sdk_Coredump_nativeGetFilter(JNIEnv* /*env*/, jclass /*clazz*/) {
119 | return Opencore::GetFilter();
120 | }
121 |
122 | static JNINativeMethod gMethods[] = {
123 | {
124 | "nativeVersion",
125 | "()Ljava/lang/String;",
126 | (void *)penguin_opencore_sdk_Coredump_nativeVersion
127 | },
128 | {
129 | "nativeEnable",
130 | "()Z",
131 | (void *)penguin_opencore_sdk_Coredump_nativeEnable
132 | },
133 | {
134 | "nativeDisable",
135 | "()Z",
136 | (void *)penguin_opencore_sdk_Coredump_nativeDisable
137 | },
138 | {
139 | "nativeCoredump",
140 | "(ILjava/lang/String;)Z",
141 | (void *)penguin_opencore_sdk_Coredump_nativeCoredump
142 | },
143 | {
144 | "nativeSetDir",
145 | "(Ljava/lang/String;)V",
146 | (void *)penguin_opencore_sdk_Coredump_nativeSetDir
147 | },
148 | {
149 | "nativeSetFlag",
150 | "(I)V",
151 | (void *)penguin_opencore_sdk_Coredump_nativeSetFlag
152 | },
153 | {
154 | "nativeSetTimeout",
155 | "(I)V",
156 | (void *)penguin_opencore_sdk_Coredump_nativeSetTimeout
157 | },
158 | {
159 | "nativeSetFilter",
160 | "(I)V",
161 | (void *)penguin_opencore_sdk_Coredump_nativeSetFilter
162 | },
163 | {
164 | "nativeIsEnabled",
165 | "()Z",
166 | (void *)penguin_opencore_sdk_Coredump_nativeIsEnabled
167 | },
168 | {
169 | "nativeGetDir",
170 | "()Ljava/lang/String;",
171 | (void *)penguin_opencore_sdk_Coredump_nativeGetDir
172 | },
173 | {
174 | "nativeGetFlag",
175 | "()I",
176 | (void *)penguin_opencore_sdk_Coredump_nativeGetFlag
177 | },
178 | {
179 | "nativeGetTimeout",
180 | "()I",
181 | (void *)penguin_opencore_sdk_Coredump_nativeGetTimeout
182 | },
183 | {
184 | "nativeGetFilter",
185 | "()I",
186 | (void *)penguin_opencore_sdk_Coredump_nativeGetFilter
187 | },
188 | };
189 |
190 | extern "C"
191 | JNIEXPORT jboolean JNICALL
192 | Java_penguin_opencore_sdk_Coredump_nativeInit(JNIEnv* env, jclass clazz) {
193 | gUser.gCoredump = (jclass)env->NewGlobalRef(clazz);
194 | if (env->RegisterNatives(gUser.gCoredump, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
195 | JNI_LOGE("Init native environment fail.");
196 | return false;
197 | }
198 | gUser.gCallbackEvent = env->GetStaticMethodID(gUser.gCoredump, "callbackEvent", "(Ljava/lang/String;)V");
199 | Opencore::SetCallback(penguin_opencore_sdk_coredump_callback);
200 | return true;
201 | }
202 |
203 | extern "C"
204 | JNIEXPORT jint JNICALL
205 | JNI_OnLoad(JavaVM *vm, void * /*reserved*/) {
206 | JNI_LOGI("Init %s environment..", Opencore::GetVersion());
207 | android::AndroidJNI::init(vm);
208 | return JNI_VERSION_1_4;
209 | }
210 |
211 | // #define INJECT_OPENCORE_DIR "/sdcard/Android/data/penguin.opencore.sdk/files"
212 | /*
213 | * build inject version if define macro "INJECT_OPENCORE_DIR" topath save dir.
214 | * exp:
215 | * #define INJECT_OPENCORE_DIR "/sdcard/Android/data/penguin.opencore.sdk/files"
216 | * core-parser> remote hook --inject -l libopencore.so
217 | * it will inject target process to enable opencore native crash handler.
218 | */
219 | #if defined(INJECT_OPENCORE_DIR)
220 | extern "C"
221 | void __attribute__((constructor)) opencore_ctor_init() {
222 | Opencore::SetDir(INJECT_OPENCORE_DIR);
223 | Opencore::SetTimeout(180);
224 | Opencore::SetFlag(Opencore::FLAG_CORE
225 | | Opencore::FLAG_PROCESS_COMM
226 | | Opencore::FLAG_PID
227 | | Opencore::FLAG_TIMESTAMP);
228 | Opencore::SetFilter(Opencore::FILTER_SPECIAL_VMA
229 | // | Opencore::FILTER_FILE_VMA
230 | // | Opencore::FILTER_SHARED_VMA
231 | | Opencore::FILTER_SANITIZER_SHADOW_VMA
232 | | Opencore::FILTER_NON_READ_VMA
233 | | Opencore::FILTER_SIGNAL_CONTEXT
234 | // | Opencore::FILTER_JAVAHEAP_VMA
235 | // | Opencore::FILTER_JIT_CACHE_VMA
236 | /* | Opencore::FILTER_MINIDUMP */);
237 | Opencore::Enable();
238 | JNI_LOGI("Init inject %s environment..", Opencore::GetVersion());
239 | }
240 |
241 | extern "C"
242 | void __attribute__((destructor)) opencore_dtor_init() {
243 | Opencore::Disable();
244 | JNI_LOGI("Remove opencore environment.");
245 | }
246 | #endif
247 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Techincal System
2 | 
3 |
4 | | Project | Path |
5 | |:------------:|---------------------------------------------------|
6 | |core-parser | https://github.com/Penguin38/OpenCoreAnalysisKit |
7 | |linux-parser | https://github.com/Penguin38/OpenLinuxAnalysisKit |
8 | |crash-android | https://github.com/Penguin38/crash-android |
9 | |OpenCoreSDK | https://github.com/Penguin38/OpenCoreSDK |
10 |
11 | ## Build
12 | ```
13 | allprojects {
14 | repositories {
15 | ...
16 | maven { url 'https://jitpack.io' }
17 | }
18 | }
19 | ```
20 | or
21 | ```
22 | dependencyResolutionManagement {
23 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
24 | repositories {
25 | ...
26 | maven { url 'https://jitpack.io' }
27 | }
28 | }
29 | ```
30 | ```
31 | dependencies {
32 | ...
33 | implementation 'com.github.Penguin38:OpenCoreSDK:opencore-1.4.16'
34 | }
35 | ```
36 | ## Simple
37 | ```
38 | {
39 | // init opencore env
40 | Coredump.getInstance().init();
41 |
42 | // setting timeout (second)
43 | Coredump.getInstance().setCoreTimeout(Coredump.DEF_TIMEOUT);
44 |
45 | // setting core filename rule
46 | Coredump.getInstance().setCoreFlag(Coredump.FLAG_CORE
47 | | Coredump.FLAG_PROCESS_COMM
48 | | Coredump.FLAG_PID
49 | | Coredump.FLAG_THREAD_COMM
50 | | Coredump.FLAG_TID
51 | | Coredump.FLAG_TIMESTAMP);
52 |
53 | // setting core filter
54 | Coredump.getInstance().setCoreFilter(Coredump.FILTER_SPECIAL_VMA
55 | // | Coredump.FILTER_FILE_VMA
56 | // | Coredump.FILTER_SHARED_VMA
57 | | Coredump.FILTER_SANITIZER_SHADOW_VMA
58 | | Coredump.FILTER_NON_READ_VMA
59 | | Coredump.FILTER_SIGNAL_CONTEXT
60 | // | Coredump.FILTER_JAVAHEAP_VMA
61 | // | Coredump.FILTER_JIT_CACHE_VMA
62 | /* | Coredump.FILTER_MINIDUMP */);
63 |
64 | // setting core save dir
65 | Coredump.getInstance().setCoreDir(...);
66 |
67 | // Java Crash
68 | Coredump.getInstance().enable(Coredump.JAVA);
69 |
70 | // Native Crash
71 | Coredump.getInstance().enable(Coredump.NATIVE);
72 |
73 | // setting core listener
74 | Coredump.getInstance().setListener(new Coredump.Listener() {
75 | @Override
76 | public void onCompleted(String path) {
77 | // do anything
78 | }
79 | });
80 |
81 | // current time core
82 | Coredump.getInstance().doCoredump();
83 | }
84 | ```
85 | ```
86 | 01-12 00:15:33.949 28421 28421 I Opencore: Init opencore-1.4.7 environment..
87 | 01-12 00:15:35.479 28471 28471 I Opencore: Coredump /storage/emulated/0/Android/data/penguin.opencore.tester/files/core.opencore.tester_28421_Thread-2_28470_1736612135 ...
88 | 01-12 00:15:35.479 28421 28470 I Opencore: Wait (28471) coredump
89 | 01-12 00:15:37.927 28471 28471 I Opencore: Finish done.
90 | ```
91 |
92 | ```
93 | $ core-parser -c core.opencore.tester_28421_Thread-2_28470_1736612135
94 |
95 | core-parser> sysroot symbols
96 | Mmap segment [5c8d0ba000, 5c8d0bc000) symbols/system/bin/app_process64 [0]
97 | Mmap segment [5c8d0bc000, 5c8d0bd000) symbols/system/bin/app_process64 [2000]
98 | Read symbols[18] (/system/bin/app_process64)
99 | Mmap segment [717a200000, 717a34a000) symbols/apex/com.android.art/lib64/libart.so [0]
100 | Mmap segment [717a400000, 717a9d7000) symbols/apex/com.android.art/lib64/libart.so [200000]
101 | Read symbols[11831] (/apex/com.android.art/lib64/libart.so)
102 | Mmap segment [714eee9000, 714eeea000) symbols/data/app/~~t-3m0JHw8Ez4qv9bddEVKg==/penguin.opencore.tester-rYieubZRUEwwTqkECUNBYQ==/lib/arm64/libnative-lib.so [0]
103 | Read symbols[10] (/data/app/~~t-3m0JHw8Ez4qv9bddEVKg==/penguin.opencore.tester-rYieubZRUEwwTqkECUNBYQ==/lib/arm64/libnative-lib.so)
104 |
105 | core-parser> bt
106 | Switch oat version(199) env.
107 | "Thread-2" sysTid=28470 Native
108 | | group="main" daemon=0 prio=5 target=0x131e9438 uncaught_exception=0x0
109 | | tid=28 sCount=0 flags=0 obj=0x131e93c0 self=0xb4000070fb248800 env=0xb4000070fb110380
110 | | stack=0x70e1e41000-0x70e1e43000 stackSize=0x103cb0 handle=0x70e1f44cb0
111 | | mutexes=0xb4000070fb248fa8 held=
112 | x0 0xb4000070fb110380 x1 0x00000070e1f43f68 x2 0x0000000000000000 x3 0x0000000000000000
113 | x4 0x0000000000000000 x5 0x0000000000000000 x6 0x0000000000000000 x7 0x0000000000000000
114 | x8 0x0000000000000000 x9 0x0000000000000001 x10 0x0000000000430000 x11 0x0000007140000000
115 | x12 0x0000000000000000 x13 0x0000000000000228 x14 0x0092b9b7e4df6987 x15 0xffffffffffffffff
116 | x16 0x0000007204fced50 x17 0x000000714eee95f0 x18 0x00000070e0fd0000 x19 0xb4000070fb248800
117 | x20 0x0000000000000000 x21 0xb4000070fb248800 x22 0x00000070e1f45000 x23 0xb4000070fb2488b0
118 | x24 0x0000007158b31a30 x25 0xb40000721ece1000 x26 0x00000070e1f45000 x27 0x000000000000000b
119 | x28 0x00000070e1f43e80 fp 0x00000070e1f43e80
120 | lr 0x000000717a422248 sp 0x00000070e1f43e50 pc 0x000000714eee9608 pst 0x0000000060001000
121 | Native: #0 000000714eee9608 Java_penguin_opencore_tester_MainActivity_nativeCrashJNI+0x18
122 | Native: #1 000000717a422244 art_quick_generic_jni_trampoline+0x94
123 | JavaKt: #0 0000000000000000 penguin.opencore.tester.MainActivity.nativeCrashJNI
124 | JavaKt: #1 0000007165277b30 penguin.opencore.tester.MainActivity$2.run
125 | JavaKt: #2 0000007179e13eb4 java.lang.Thread.run
126 | core-parser>
127 | ```
128 |
129 | ```
130 | $ gdb16 -c core.opencore.tester_28421_Thread-2_28470_1736612135
131 |
132 | (gdb) set sysroot symbols/
133 | Reading symbols from symbols/apex/com.android.art/lib64/libart.so...
134 | (No debugging symbols found in symbols/apex/com.android.art/lib64/libart.so)
135 | Reading symbols from symbols/data/app/~~t-3m0JHw8Ez4qv9bddEVKg==/penguin.opencore.tester-rYieubZRUEwwTqkECUNBYQ==/lib/arm64/libnative-lib.so...
136 |
137 | (gdb) bt
138 | #0 0x000000714eee9608 in Java_penguin_opencore_tester_MainActivity_nativeCrashJNI (env=0xb4000070fb110380, thiz=0x70e1f43f68)
139 | at /home/penguin/opensource/OpenCoreSDK/app/src/main/cpp/native-lib.cpp:25
140 | #1 0x000000717a422248 in art_quick_generic_jni_trampoline () from symbols/apex/com.android.art/lib64/libart.so
141 | #2 0x000000717a418968 in art_quick_invoke_stub () from symbols/apex/com.android.art/lib64/libart.so
142 | #3 0x000000717a484064 in art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) () from symbols/apex/com.android.art/lib64/libart.so
143 | #4 0x000000717a5e1734 in art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*) ()
144 | from symbols/apex/com.android.art/lib64/libart.so
145 | #5 0x000000717a5dc028 in bool art::interpreter::DoCall(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) ()
146 | from symbols/apex/com.android.art/lib64/libart.so
147 | #6 0x000000717a943a68 in MterpInvokeVirtual () from symbols/apex/com.android.art/lib64/libart.so
148 | #7 0x000000717a403818 in mterp_op_invoke_virtual () from symbols/apex/com.android.art/lib64/libart.so
149 | #8 0x000000717a5d3fd4 in art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) ()
150 | from symbols/apex/com.android.art/lib64/libart.so
151 | #9 0x000000717a5db5a8 in art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) ()
152 | from symbols/apex/com.android.art/lib64/libart.so
153 | #10 0x000000717a5dc004 in bool art::interpreter::DoCall(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) ()
154 | from symbols/apex/com.android.art/lib64/libart.so
155 | #11 0x000000717a949c00 in MterpInvokeInterface () from symbols/apex/com.android.art/lib64/libart.so
156 | #12 0x000000717a403a18 in mterp_op_invoke_interface () from symbols/apex/com.android.art/lib64/libart.so
157 | #13 0x000000717a5d3fd4 in art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) ()
158 | from symbols/apex/com.android.art/lib64/libart.so
159 | #14 0x000000717a932568 in artQuickToInterpreterBridge () from symbols/apex/com.android.art/lib64/libart.so
160 | #15 0x000000717a42237c in art_quick_to_interpreter_bridge () from symbols/apex/com.android.art/lib64/libart.so
161 | #16 0x000000717a418968 in art_quick_invoke_stub () from symbols/apex/com.android.art/lib64/libart.so
162 | #17 0x000000717a484064 in art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) () from symbols/apex/com.android.art/lib64/libart.so
163 | #18 0x000000717a818618 in art::JValue art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*) () from symbols/apex/com.android.art/lib64/libart.so
164 | #19 0x000000717a866b24 in art::Thread::CreateCallback(void*) () from symbols/apex/com.android.art/lib64/libart.so
165 | ...
166 | ```
167 | ## Build Only
168 | ```
169 | Optional:
170 | export BUILD_TYPE="Debug"
171 | export BUILD_ANDROID_ABIS="arm64-v8a armeabi-v7a x86_64 x86"
172 | export BUILD_ANDROID_PLATFORM="android-30"
173 |
174 | Required:
175 | export ANDROID_NDK_HOME=
176 | ./script/build_opencore.sh
177 | ```
178 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/arm64/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "arm64-opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/arm64/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #define DEF_VA_BITS 39
30 | #ifndef NT_FPREGSET
31 | #define NT_FPREGSET 0x2
32 | #endif
33 | #ifndef NT_ARM_PAC_MASK
34 | #define NT_ARM_PAC_MASK 0x406
35 | #endif
36 | #ifndef NT_ARM_TAGGED_ADDR_CTRL
37 | #define NT_ARM_TAGGED_ADDR_CTRL 0x409
38 | #endif
39 | #ifndef NT_ARM_PAC_ENABLED_KEYS
40 | #define NT_ARM_PAC_ENABLED_KEYS 0x40A
41 | #endif
42 |
43 | namespace arm64 {
44 |
45 | struct user_pac_mask {
46 | uint64_t data_mask;
47 | uint64_t insn_mask;
48 | };
49 |
50 | void Opencore::CreateCorePrStatus(int pid) {
51 | if (!threads.size()) return;
52 |
53 | prnum = threads.size();
54 | prstatus = (Elf64_prstatus *)malloc(prnum * sizeof(Elf64_prstatus));
55 | memset(prstatus, 0, prnum * sizeof(Elf64_prstatus));
56 |
57 | int cur = 1;
58 | for (int index = 0; index < prnum; index++) {
59 | pid_t tid = threads[index].pid;
60 | int idx;
61 | if (tid == getTid()) {
62 | idx = 0;
63 | prstatus[idx].pr_pid = tid;
64 | // top thread maybe use ucontext prs
65 | if (getContext()) {
66 | struct ucontext *context = (struct ucontext *) getContext();
67 | memcpy(&prstatus[idx].pr_reg, &context->uc_mcontext.regs, sizeof(arm64::pt_regs));
68 | continue;
69 | }
70 | } else {
71 | // 0 top thread was truncated
72 | idx = (cur >= prnum) ? 0 : cur;
73 | ++cur;
74 | prstatus[idx].pr_pid = tid;
75 | }
76 |
77 | struct iovec ioVec = {
78 | &prstatus[idx].pr_reg,
79 | sizeof(arm64::pt_regs),
80 | };
81 |
82 | if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &ioVec) < 0)
83 | continue;
84 | }
85 |
86 | extra_note_filesz += (sizeof(Elf64_prstatus) + sizeof(Elf64_Nhdr) + 8) * prnum; // NT_PRSTATUS
87 | extra_note_filesz += sizeof(siginfo_t) + sizeof(Elf64_Nhdr) + 8; // NT_SIGINFO
88 | extra_note_filesz += (sizeof(Elf64_fpregset) + sizeof(Elf64_Nhdr) + 8) * prnum; // NT_FPREGSET
89 | extra_note_filesz += (sizeof(Elf64_tls) + sizeof(Elf64_Nhdr) + 8) * prnum; // NT_ARM_TLS
90 | extra_note_filesz += ((sizeof(struct user_pac_mask) + sizeof(Elf64_Nhdr) + 8) // NT_ARM_PAC_MASK
91 | + (sizeof(uint64_t) + sizeof(Elf64_Nhdr) + 8) // NT_ARM_PAC_ENABLED_KEYS
92 | ) * prnum;
93 | extra_note_filesz += (sizeof(uint64_t) + sizeof(Elf64_Nhdr) + 8) * prnum; // NT_ARM_TAGGED_ADDR_CTRL
94 | }
95 |
96 | void Opencore::WriteCorePrStatus(FILE* fp) {
97 | Elf64_Nhdr elf_nhdr;
98 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
99 | elf_nhdr.n_descsz = sizeof(Elf64_prstatus);
100 | elf_nhdr.n_type = NT_PRSTATUS;
101 |
102 | char magic[8];
103 | memset(magic, 0, sizeof(magic));
104 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
105 |
106 | for (int index = 0; index < prnum; index++) {
107 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
108 | fwrite(magic, sizeof(magic), 1, fp);
109 | fwrite(&prstatus[index], sizeof(Elf64_prstatus), 1, fp);
110 | if (!index) WriteCoreSignalInfo(fp);
111 | WriteCoreFpRegs(prstatus[index].pr_pid ,fp);
112 | WriteCoreTLS(prstatus[index].pr_pid, fp);
113 | WriteCorePAC(prstatus[index].pr_pid ,fp);
114 | WriteCoreMTE(prstatus[index].pr_pid ,fp);
115 | }
116 | }
117 |
118 | int Opencore::IsSpecialFilterSegment(Opencore::VirtualMemoryArea& vma) {
119 | int filter = getFilter();
120 | if (filter & FILTER_MINIDUMP) {
121 | if (!prnum)
122 | return VMA_NULL;
123 |
124 | arm64::pt_regs *regs = &prstatus[0].pr_reg;
125 | if (regs->pc >= vma.begin && regs->pc < vma.end
126 | || regs->regs[0] >= vma.begin && regs->regs[0] < vma.end
127 | || regs->regs[1] >= vma.begin && regs->regs[1] < vma.end
128 | || regs->regs[2] >= vma.begin && regs->regs[2] < vma.end
129 | || regs->regs[3] >= vma.begin && regs->regs[3] < vma.end
130 | || regs->regs[4] >= vma.begin && regs->regs[4] < vma.end
131 | || regs->regs[5] >= vma.begin && regs->regs[5] < vma.end
132 | || regs->regs[6] >= vma.begin && regs->regs[6] < vma.end
133 | || regs->regs[7] >= vma.begin && regs->regs[7] < vma.end
134 | || regs->regs[8] >= vma.begin && regs->regs[8] < vma.end
135 | || regs->regs[9] >= vma.begin && regs->regs[9] < vma.end
136 | || regs->regs[10] >= vma.begin && regs->regs[10] < vma.end
137 | || regs->regs[11] >= vma.begin && regs->regs[11] < vma.end
138 | || regs->regs[12] >= vma.begin && regs->regs[12] < vma.end
139 | || regs->regs[13] >= vma.begin && regs->regs[13] < vma.end
140 | || regs->regs[14] >= vma.begin && regs->regs[14] < vma.end
141 | || regs->regs[15] >= vma.begin && regs->regs[15] < vma.end
142 | || regs->regs[16] >= vma.begin && regs->regs[16] < vma.end
143 | || regs->regs[17] >= vma.begin && regs->regs[17] < vma.end
144 | || regs->regs[18] >= vma.begin && regs->regs[18] < vma.end
145 | || regs->regs[19] >= vma.begin && regs->regs[19] < vma.end
146 | || regs->regs[20] >= vma.begin && regs->regs[20] < vma.end
147 | || regs->regs[21] >= vma.begin && regs->regs[21] < vma.end
148 | || regs->regs[22] >= vma.begin && regs->regs[22] < vma.end
149 | || regs->regs[23] >= vma.begin && regs->regs[23] < vma.end
150 | || regs->regs[24] >= vma.begin && regs->regs[24] < vma.end
151 | || regs->regs[25] >= vma.begin && regs->regs[25] < vma.end
152 | || regs->regs[26] >= vma.begin && regs->regs[26] < vma.end
153 | || regs->regs[27] >= vma.begin && regs->regs[27] < vma.end
154 | || regs->regs[28] >= vma.begin && regs->regs[28] < vma.end
155 | || regs->regs[29] >= vma.begin && regs->regs[29] < vma.end
156 | || regs->regs[30] >= vma.begin && regs->regs[30] < vma.end
157 | || regs->sp >= vma.begin && regs->sp < vma.end) {
158 | return VMA_INCLUDE;
159 | }
160 |
161 | return VMA_NULL;
162 | }
163 | return VMA_NORMAL;
164 | }
165 |
166 | void Opencore::WriteCoreFpRegs(int tid, FILE* fp) {
167 | // NT_FPREGSET
168 | Elf64_Nhdr elf_nhdr;
169 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
170 | elf_nhdr.n_descsz = sizeof(Elf64_fpregset);
171 | elf_nhdr.n_type = NT_FPREGSET;
172 |
173 | char magic[8];
174 | memset(magic, 0, sizeof(magic));
175 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
176 |
177 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
178 | fwrite(magic, sizeof(magic), 1, fp);
179 |
180 | Elf64_fpregset fpregset;
181 | memset(&fpregset, 0x0, sizeof(fpregset));
182 | struct iovec fpregset_iov = {
183 | &fpregset,
184 | sizeof(fpregset),
185 | };
186 |
187 | if (ptrace(PTRACE_GETREGSET, tid, NT_FPREGSET,
188 | reinterpret_cast(&fpregset_iov)) == -1) {
189 | memset(&fpregset, 0x0, sizeof(fpregset));
190 | }
191 |
192 | fwrite(&fpregset, sizeof(Elf64_fpregset), 1, fp);
193 | }
194 |
195 | void Opencore::WriteCoreTLS(int tid, FILE* fp) {
196 | // NT_ARM_TLS
197 | Elf64_Nhdr elf_nhdr;
198 | elf_nhdr.n_namesz = NOTE_LINUX_NAME_SZ;
199 | elf_nhdr.n_descsz = sizeof(user_pac_mask);
200 | elf_nhdr.n_type = NT_ARM_TLS;
201 |
202 | char magic[8];
203 | memset(magic, 0, sizeof(magic));
204 | snprintf(magic, NOTE_LINUX_NAME_SZ, ELFLINUXMAGIC);
205 |
206 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
207 | fwrite(magic, sizeof(magic), 1, fp);
208 |
209 | Elf64_tls tls;
210 | struct iovec tls_iov = {
211 | &tls.regs,
212 | sizeof(tls.regs),
213 | };
214 | if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS,
215 | reinterpret_cast(&tls_iov)) == -1) {
216 | memset(&tls.regs, 0x0, sizeof(tls.regs));
217 | }
218 | fwrite(&tls, sizeof(tls), 1, fp);
219 | }
220 |
221 | void Opencore::WriteCorePAC(int tid, FILE* fp) {
222 | // NT_ARM_PAC_MASK
223 | Elf64_Nhdr elf_nhdr;
224 | elf_nhdr.n_namesz = NOTE_LINUX_NAME_SZ;
225 | elf_nhdr.n_descsz = sizeof(user_pac_mask);
226 | elf_nhdr.n_type = NT_ARM_PAC_MASK;
227 |
228 | char magic[8];
229 | memset(magic, 0, sizeof(magic));
230 | snprintf(magic, NOTE_LINUX_NAME_SZ, ELFLINUXMAGIC);
231 |
232 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
233 | fwrite(magic, sizeof(magic), 1, fp);
234 |
235 | user_pac_mask uregs;
236 | struct iovec pac_mask_iov = {
237 | &uregs,
238 | sizeof(user_pac_mask),
239 | };
240 | if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_PAC_MASK,
241 | reinterpret_cast(&pac_mask_iov)) == -1) {
242 | uint64_t mask = GENMASK_UL(54, DEF_VA_BITS);
243 | uregs.data_mask = mask;
244 | uregs.insn_mask = mask;
245 | }
246 | fwrite(&uregs, sizeof(user_pac_mask), 1, fp);
247 |
248 | // NT_ARM_PAC_ENABLED_KEYS
249 | elf_nhdr.n_descsz = sizeof(uint64_t);
250 | elf_nhdr.n_type = NT_ARM_PAC_ENABLED_KEYS;
251 |
252 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
253 | fwrite(magic, sizeof(magic), 1, fp);
254 |
255 | uint64_t pac_enabled_keys;
256 | struct iovec pac_enabled_keys_iov = {
257 | &pac_enabled_keys,
258 | sizeof(pac_enabled_keys),
259 | };
260 | if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_PAC_ENABLED_KEYS,
261 | reinterpret_cast(&pac_enabled_keys_iov)) == -1) {
262 | pac_enabled_keys = -1;
263 | }
264 | fwrite(&pac_enabled_keys, sizeof(uint64_t), 1, fp);
265 | }
266 |
267 | void Opencore::WriteCoreMTE(int tid, FILE* fp) {
268 | // NT_ARM_TAGGED_ADDR_CTRL
269 | Elf64_Nhdr elf_nhdr;
270 | elf_nhdr.n_namesz = NOTE_LINUX_NAME_SZ;
271 | elf_nhdr.n_descsz = sizeof(uint64_t);
272 | elf_nhdr.n_type = NT_ARM_TAGGED_ADDR_CTRL;
273 |
274 | char magic[8];
275 | memset(magic, 0, sizeof(magic));
276 | snprintf(magic, NOTE_LINUX_NAME_SZ, ELFLINUXMAGIC);
277 |
278 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
279 | fwrite(magic, sizeof(magic), 1, fp);
280 |
281 | uint64_t tagged_addr_ctrl;
282 | struct iovec tagged_addr_ctrl_iov = {
283 | &tagged_addr_ctrl,
284 | sizeof(tagged_addr_ctrl),
285 | };
286 | if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL,
287 | reinterpret_cast(&tagged_addr_ctrl_iov)) == -1) {
288 | tagged_addr_ctrl = -1;
289 | }
290 | fwrite(&tagged_addr_ctrl, sizeof(uint64_t), 1, fp);
291 | }
292 |
293 | void Opencore::Finish() {
294 | if (prstatus) free(prstatus);
295 | lp64::OpencoreImpl::Finish();
296 | }
297 |
298 | } // namespace arm64
299 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/lp32/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/lp32/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | namespace lp32 {
32 |
33 | void OpencoreImpl::ParserPhdr(int index, Opencore::VirtualMemoryArea& vma) {
34 | phdr[index].p_type = PT_LOAD;
35 |
36 | phdr[index].p_vaddr = (Elf32_Addr)vma.begin;
37 | phdr[index].p_paddr = 0x0;
38 | phdr[index].p_memsz = (Elf32_Addr)vma.end-(Elf32_Addr)vma.begin;
39 |
40 | if (vma.flags[0] == 'r' || vma.flags[0] == 'R')
41 | phdr[index].p_flags = phdr[index].p_flags | PF_R;
42 |
43 | if (vma.flags[1] == 'w' || vma.flags[1] == 'W')
44 | phdr[index].p_flags = phdr[index].p_flags | PF_W;
45 |
46 | if (vma.flags[2] == 'x' || vma.flags[2] == 'X')
47 | phdr[index].p_flags = phdr[index].p_flags | PF_X;
48 |
49 | phdr[index].p_filesz = phdr[index].p_memsz;
50 | phdr[index].p_align = align_size;
51 | }
52 |
53 | void OpencoreImpl::ParserNtFile(int index, Opencore::VirtualMemoryArea& vma) {
54 | file[index].begin = (Elf32_Addr)vma.begin;
55 | file[index].end = (Elf32_Addr)vma.end;
56 | file[index].offset = vma.offset >> 12;
57 | fileslen += vma.file.length() + 1;
58 | }
59 |
60 | void OpencoreImpl::ParseProcessMapsVma(int pid) {
61 | ParseMaps(pid, maps);
62 | if (!maps.size())
63 | return;
64 |
65 | phnum = maps.size();
66 | phdr = (Elf32_Phdr *)malloc(phnum * sizeof(Elf32_Phdr));
67 | memset(phdr, 0, phnum * sizeof(Elf32_Phdr));
68 | file = (lp32::File *)malloc(phnum * sizeof(lp32::File));
69 | memset(file, 0, phnum * sizeof(lp32::File));
70 |
71 | for (int index = 0; index < maps.size(); ++index) {
72 | Opencore::VirtualMemoryArea& vma = maps[index];
73 | ParserPhdr(index, vma);
74 | ParserNtFile(index, vma);
75 | }
76 | }
77 |
78 | void OpencoreImpl::CreateCoreHeader() {
79 | snprintf((char *)ehdr.e_ident, 5, ELFMAG);
80 | ehdr.e_ident[EI_CLASS] = ELFCLASS32;
81 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
82 | ehdr.e_ident[EI_VERSION] = EV_CURRENT;
83 |
84 | ehdr.e_type = ET_CORE;
85 | ehdr.e_machine = getMachine();
86 | ehdr.e_version = EV_CURRENT;
87 | ehdr.e_entry = 0x0;
88 | ehdr.e_phoff = sizeof(Elf32_Ehdr);
89 | ehdr.e_shoff = 0x0;
90 | ehdr.e_flags = 0x0;
91 | ehdr.e_ehsize = sizeof(Elf32_Ehdr);
92 | ehdr.e_phentsize = sizeof(Elf32_Phdr);
93 | ehdr.e_phnum = phnum + 1;
94 | ehdr.e_shentsize = 0x0;
95 | ehdr.e_shnum = 0x0;
96 | ehdr.e_shstrndx = 0x0;
97 | }
98 |
99 | void OpencoreImpl::CreateCoreNoteHeader() {
100 | note.p_type = PT_NOTE;
101 | note.p_offset = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
102 | }
103 |
104 | void OpencoreImpl::CreateCoreAUXV(int pid) {
105 | char filename[32];
106 | lp32::Auxv vec;
107 | snprintf(filename, sizeof(filename), "/proc/%d/auxv", pid);
108 |
109 | FILE *fp = fopen(filename, "rb");
110 | if (fp != nullptr) {
111 | while (fread(&vec, sizeof(vec), 1, fp)) {
112 | auxvnum++;
113 | }
114 | fseek(fp, 0, SEEK_SET);
115 |
116 | auxv = (lp32::Auxv *)malloc(auxvnum * sizeof(lp32::Auxv));
117 | memset(auxv, 0, auxvnum * sizeof(lp32::Auxv));
118 |
119 | int index =0;
120 | while (fread(&vec, sizeof(vec), 1, fp)) {
121 | auxv[index].type = vec.type;
122 | auxv[index].value = vec.value;
123 | index++;
124 | }
125 |
126 | fclose(fp);
127 | }
128 | }
129 |
130 | void OpencoreImpl::SpecialCoreFilter() {
131 | for (int index = 0; index < maps.size(); ++index) {
132 | Opencore::VirtualMemoryArea& vma = maps[index];
133 | int vma_flag = IsFilterSegment(vma) | IsSpecialFilterSegment(vma);
134 | if (vma_flag & VMA_NULL)
135 | phdr[index].p_filesz = 0x0;
136 |
137 | if (vma_flag & VMA_INCLUDE)
138 | phdr[index].p_filesz = phdr[index].p_memsz;
139 | }
140 | }
141 |
142 | void OpencoreImpl::WriteCoreHeader(FILE* fp) {
143 | fwrite((void *)&ehdr, sizeof(Elf32_Ehdr), 1, fp);
144 | }
145 |
146 | void OpencoreImpl::WriteCoreNoteHeader(FILE* fp) {
147 | note.p_filesz += sizeof(lp32::Auxv) * auxvnum + sizeof(Elf32_Nhdr) + 8;
148 | note.p_filesz += extra_note_filesz;
149 | note.p_filesz += sizeof(lp32::File) * phnum + sizeof(Elf32_Nhdr) + 8 + 2 * 4 + RoundUp(fileslen, 4);
150 | fwrite((void *)¬e, sizeof(Elf32_Phdr), 1, fp);
151 | }
152 |
153 | void OpencoreImpl::WriteCoreProgramHeaders(FILE* fp) {
154 | if (!phnum)
155 | return;
156 |
157 | uint32_t offset = RoundUp(note.p_offset + note.p_filesz, align_size);
158 | phdr[0].p_offset = offset;
159 | fwrite(&phdr[0], sizeof(Elf32_Phdr), 1, fp);
160 |
161 | int index = 1;
162 | while (index < phnum) {
163 | phdr[index].p_offset = phdr[index - 1].p_offset + phdr[index-1].p_filesz;
164 | fwrite(&phdr[index], sizeof(Elf32_Phdr), 1, fp);
165 | index++;
166 | }
167 | }
168 |
169 | void OpencoreImpl::WriteCoreSignalInfo(FILE* fp) {
170 | Elf32_Nhdr elf_nhdr;
171 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
172 | elf_nhdr.n_descsz = sizeof(siginfo_t);
173 | elf_nhdr.n_type = NT_SIGINFO;
174 |
175 | char magic[8];
176 | memset(magic, 0, sizeof(magic));
177 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
178 |
179 | fwrite(&elf_nhdr, sizeof(Elf32_Nhdr), 1, fp);
180 | fwrite(magic, sizeof(magic), 1, fp);
181 |
182 | siginfo_t info;
183 | memset(&info, 0x0, sizeof(siginfo_t));
184 | if (getSignalInfo())
185 | memcpy(&info, getSignalInfo(), sizeof(siginfo_t));
186 | fwrite(&info, sizeof(siginfo_t), 1, fp);
187 | }
188 |
189 | void OpencoreImpl::WriteCoreAUXV(FILE* fp) {
190 | Elf32_Nhdr elf_nhdr;
191 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
192 | elf_nhdr.n_descsz = sizeof(lp32::Auxv) * auxvnum;
193 | elf_nhdr.n_type = NT_AUXV;
194 |
195 | char magic[8];
196 | memset(magic, 0, sizeof(magic));
197 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
198 |
199 | fwrite(&elf_nhdr, sizeof(Elf32_Nhdr), 1, fp);
200 | fwrite(magic, sizeof(magic), 1, fp);
201 |
202 | int index = 0;
203 | while (index < auxvnum) {
204 | fwrite(&auxv[index], sizeof(lp32::Auxv), 1, fp);
205 | index++;
206 | }
207 | }
208 |
209 | void OpencoreImpl::WriteNtFile(FILE* fp) {
210 | Elf32_Nhdr elf_nhdr;
211 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
212 | elf_nhdr.n_descsz = sizeof(lp32::File) * phnum + 2 * 4 + RoundUp(fileslen, 4);
213 | elf_nhdr.n_type = NT_FILE;
214 |
215 | char magic[8];
216 | memset(magic, 0, sizeof(magic));
217 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
218 |
219 | fwrite(&elf_nhdr, sizeof(Elf32_Nhdr), 1, fp);
220 | fwrite(magic, sizeof(magic), 1, fp);
221 |
222 | uint32_t number = phnum;
223 | fwrite(&number, 4, 1, fp);
224 | fwrite(&page_size, 4, 1, fp);
225 |
226 | for (int index = 0; index < phnum; ++index)
227 | fwrite(&file[index], sizeof(lp32::File), 1, fp);
228 |
229 | for (int index = 0; index < phnum; ++index)
230 | fwrite(maps[index].file.data(), maps[index].file.length() + 1, 1, fp);
231 | }
232 |
233 | void OpencoreImpl::AlignNoteSegment(FILE* fp) {
234 | memset(zero, 0x0, align_size);
235 | uint32_t align_filesz = note.p_filesz - RoundUp(fileslen, 4) + fileslen;
236 | uint32_t offset = RoundUp(note.p_offset + align_filesz, align_size);
237 | uint32_t size = offset - (note.p_offset + align_filesz);
238 | fwrite(zero, size, 1, fp);
239 | }
240 |
241 | void OpencoreImpl::WriteCoreLoadSegment(int pid, FILE* fp) {
242 | char filename[32];
243 | int fd;
244 | int index = 0;
245 | memset(zero, 0x0, align_size);
246 |
247 | snprintf(filename, sizeof(filename), "/proc/%d/mem", pid);
248 | fd = open(filename, O_RDONLY);
249 | if (fd < 0) {
250 | JNI_LOGE("open %s fail.", filename);
251 | return;
252 | }
253 |
254 | while(index < phnum) {
255 | if (phdr[index].p_filesz > 0) {
256 | long current_pos = ftell(fp);
257 | bool need_padd_zero = false;
258 | int count = phdr[index].p_memsz / align_size;
259 | for (int i = 0; i < count; i++) {
260 | memset(zero, 0x0, align_size);
261 | pread64(fd, zero, phdr[index].p_align, phdr[index].p_vaddr + (i * align_size));
262 | uint32_t ret = fwrite(zero, align_size, 1, fp);
263 | if (ret != 1) {
264 | JNI_LOGE("[%x] write load segment fail. %s %s",
265 | (uint32_t)phdr[index].p_vaddr, strerror(errno), maps[index].file.c_str());
266 | if (errno == ENOSPC)
267 | return;
268 |
269 | need_padd_zero = true;
270 | break;
271 | }
272 | }
273 | if (need_padd_zero && current_pos > 0) {
274 | memset(zero, 0x0, align_size);
275 | fseek(fp, current_pos, SEEK_SET);
276 | int count = phdr[index].p_memsz / align_size;
277 | for (int i = 0; i < count; i++)
278 | fwrite(zero, align_size, 1, fp);
279 | }
280 | }
281 | index++;
282 | }
283 | close(fd);
284 | }
285 |
286 | bool OpencoreImpl::DoCoredump(const char* filename) {
287 | Prepare(filename);
288 |
289 | FILE* fp = fopen(filename, "wb");
290 | if (!fp) {
291 | JNI_LOGE("%s %s: %s", __func__, filename, strerror(errno));
292 | return false;
293 | }
294 |
295 | StopTheWorld(getPid());
296 |
297 | ParseProcessMapsVma(getPid());
298 | CreateCoreHeader();
299 | CreateCoreNoteHeader();
300 | CreateCorePrStatus(getPid());
301 | CreateCoreAUXV(getPid());
302 | SpecialCoreFilter();
303 |
304 | // ELF Header
305 | WriteCoreHeader(fp);
306 |
307 | // Program Headers
308 | WriteCoreNoteHeader(fp);
309 | WriteCoreProgramHeaders(fp);
310 |
311 | // Segments
312 | WriteCorePrStatus(fp);
313 | WriteCoreAUXV(fp);
314 | WriteNtFile(fp);
315 | AlignNoteSegment(fp);
316 | WriteCoreLoadSegment(getPid(), fp);
317 |
318 | fflush(fp);
319 | fsync(fileno(fp));
320 | fclose(fp);
321 | return true;
322 | }
323 |
324 | int OpencoreImpl::NeedFilterFile(Opencore::VirtualMemoryArea& vma) {
325 | struct stat sb;
326 | int fd = open(vma.file.c_str(), O_RDONLY);
327 | if (fd < 0)
328 | return VMA_NULL;
329 |
330 | if (fstat(fd, &sb) < 0) {
331 | close(fd);
332 | return VMA_NULL;
333 | }
334 |
335 | char* mem = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0x0);
336 | close(fd);
337 | if (mem == MAP_FAILED)
338 | return VMA_NULL;
339 |
340 | Elf32_Ehdr* ehdr = (Elf32_Ehdr*)mem;
341 | if (strncmp(mem, ELFMAG, 4) || ehdr->e_machine != getMachine()) {
342 | munmap(mem, sb.st_size);
343 | return VMA_NULL;
344 | }
345 |
346 | int ret = VMA_NULL;
347 | Elf32_Phdr* phdr = (Elf32_Phdr *)(mem + sizeof(Elf32_Ehdr));
348 | for (int index = 0; index < ehdr->e_phnum; index++) {
349 | if (phdr[index].p_type != PT_LOAD)
350 | continue;
351 |
352 | int pos = RoundDown(phdr[index].p_offset, page_size);
353 | int end = pos + phdr[index].p_memsz;
354 | if (pos <= vma.offset && vma.offset < end) {
355 | if ((phdr[index].p_flags & PF_W))
356 | ret = VMA_NORMAL;
357 | }
358 | }
359 |
360 | munmap(mem, sb.st_size);
361 | return ret;
362 | }
363 |
364 | uint32_t OpencoreImpl::FindAuxv(uint32_t type) {
365 | for (int idx = 0; idx < auxvnum; ++idx) {
366 | if (auxv[idx].type == type)
367 | return auxv[idx].value;
368 | }
369 | return 0;
370 | }
371 |
372 | void OpencoreImpl::Prepare(const char* filename) {
373 | JNI_LOGI("Coredump %s ...", filename);
374 | zero = (uint8_t*)malloc(align_size);
375 | memset(&ehdr, 0, sizeof(Elf32_Ehdr));
376 | memset(¬e, 0, sizeof(Elf32_Phdr));
377 | }
378 |
379 | void OpencoreImpl::Finish() {
380 | if (auxv) free(auxv);
381 | if (phdr) free(phdr);
382 | if (file) free(file);
383 | if (zero) free(zero);
384 | Opencore::Finish();
385 | JNI_LOGI("Finish done.");
386 | }
387 |
388 | } // namespace lp32
389 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/lp64/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/lp64/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | namespace lp64 {
32 |
33 | void OpencoreImpl::ParserPhdr(int index, Opencore::VirtualMemoryArea& vma) {
34 | phdr[index].p_type = PT_LOAD;
35 |
36 | phdr[index].p_vaddr = (Elf64_Addr)vma.begin;
37 | phdr[index].p_paddr = 0x0;
38 | phdr[index].p_memsz = (Elf64_Addr)vma.end-(Elf64_Addr)vma.begin;
39 |
40 | if (vma.flags[0] == 'r' || vma.flags[0] == 'R')
41 | phdr[index].p_flags = phdr[index].p_flags | PF_R;
42 |
43 | if (vma.flags[1] == 'w' || vma.flags[1] == 'W')
44 | phdr[index].p_flags = phdr[index].p_flags | PF_W;
45 |
46 | if (vma.flags[2] == 'x' || vma.flags[2] == 'X')
47 | phdr[index].p_flags = phdr[index].p_flags | PF_X;
48 |
49 | phdr[index].p_filesz = phdr[index].p_memsz;
50 | phdr[index].p_align = align_size;
51 | }
52 |
53 | void OpencoreImpl::ParserNtFile(int index, Opencore::VirtualMemoryArea& vma) {
54 | file[index].begin = (Elf64_Addr)vma.begin;
55 | file[index].end = (Elf64_Addr)vma.end;
56 | file[index].offset = vma.offset >> 12;
57 | fileslen += vma.file.length() + 1;
58 | }
59 |
60 | void OpencoreImpl::ParseProcessMapsVma(int pid) {
61 | ParseMaps(pid, maps);
62 | if (!maps.size())
63 | return;
64 |
65 | phnum = maps.size();
66 | phdr = (Elf64_Phdr *)malloc(phnum * sizeof(Elf64_Phdr));
67 | memset(phdr, 0, phnum * sizeof(Elf64_Phdr));
68 | file = (lp64::File *)malloc(phnum * sizeof(lp64::File));
69 | memset(file, 0, phnum * sizeof(lp64::File));
70 |
71 | for (int index = 0; index < maps.size(); ++index) {
72 | Opencore::VirtualMemoryArea& vma = maps[index];
73 | ParserPhdr(index, vma);
74 | ParserNtFile(index, vma);
75 | }
76 | }
77 |
78 | void OpencoreImpl::CreateCoreHeader() {
79 | snprintf((char *)ehdr.e_ident, 5, ELFMAG);
80 | ehdr.e_ident[EI_CLASS] = ELFCLASS64;
81 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
82 | ehdr.e_ident[EI_VERSION] = EV_CURRENT;
83 |
84 | ehdr.e_type = ET_CORE;
85 | ehdr.e_machine = getMachine();
86 | ehdr.e_version = EV_CURRENT;
87 | ehdr.e_entry = 0x0;
88 | ehdr.e_phoff = sizeof(Elf64_Ehdr);
89 | ehdr.e_shoff = 0x0;
90 | ehdr.e_flags = 0x0;
91 | ehdr.e_ehsize = sizeof(Elf64_Ehdr);
92 | ehdr.e_phentsize = sizeof(Elf64_Phdr);
93 | ehdr.e_phnum = phnum + 1;
94 | ehdr.e_shentsize = 0x0;
95 | ehdr.e_shnum = 0x0;
96 | ehdr.e_shstrndx = 0x0;
97 | }
98 |
99 | void OpencoreImpl::CreateCoreNoteHeader() {
100 | note.p_type = PT_NOTE;
101 | note.p_offset = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr);
102 | }
103 |
104 | void OpencoreImpl::CreateCoreAUXV(int pid) {
105 | char filename[32];
106 | lp64::Auxv vec;
107 | snprintf(filename, sizeof(filename), "/proc/%d/auxv", pid);
108 |
109 | FILE *fp = fopen(filename, "rb");
110 | if (fp != nullptr) {
111 | while (fread(&vec, sizeof(vec), 1, fp)) {
112 | auxvnum++;
113 | }
114 | fseek(fp, 0, SEEK_SET);
115 |
116 | auxv = (lp64::Auxv *)malloc(auxvnum * sizeof(lp64::Auxv));
117 | memset(auxv, 0, auxvnum * sizeof(lp64::Auxv));
118 |
119 | int index =0;
120 | while (fread(&vec, sizeof(vec), 1, fp)) {
121 | auxv[index].type = vec.type;
122 | auxv[index].value = vec.value;
123 | index++;
124 | }
125 |
126 | fclose(fp);
127 | }
128 | }
129 |
130 | void OpencoreImpl::SpecialCoreFilter() {
131 | for (int index = 0; index < maps.size(); ++index) {
132 | Opencore::VirtualMemoryArea& vma = maps[index];
133 | int vma_flag = IsFilterSegment(vma) | IsSpecialFilterSegment(vma);
134 | if (vma_flag & VMA_NULL)
135 | phdr[index].p_filesz = 0x0;
136 |
137 | if (vma_flag & VMA_INCLUDE)
138 | phdr[index].p_filesz = phdr[index].p_memsz;
139 | }
140 | }
141 |
142 | void OpencoreImpl::WriteCoreHeader(FILE* fp) {
143 | fwrite((void *)&ehdr, sizeof(Elf64_Ehdr), 1, fp);
144 | }
145 |
146 | void OpencoreImpl::WriteCoreNoteHeader(FILE* fp) {
147 | note.p_filesz += sizeof(lp64::Auxv) * auxvnum + sizeof(Elf64_Nhdr) + 8;
148 | note.p_filesz += extra_note_filesz;
149 | note.p_filesz += sizeof(lp64::File) * phnum + sizeof(Elf64_Nhdr) + 8 + 2 * 8 + RoundUp(fileslen, 4);
150 | fwrite((void *)¬e, sizeof(Elf64_Phdr), 1, fp);
151 | }
152 |
153 | void OpencoreImpl::WriteCoreProgramHeaders(FILE* fp) {
154 | if (!phnum)
155 | return;
156 |
157 | uint64_t offset = RoundUp(note.p_offset + note.p_filesz, align_size);
158 | phdr[0].p_offset = offset;
159 | fwrite(&phdr[0], sizeof(Elf64_Phdr), 1, fp);
160 |
161 | int index = 1;
162 | while (index < phnum) {
163 | phdr[index].p_offset = phdr[index - 1].p_offset + phdr[index-1].p_filesz;
164 | fwrite(&phdr[index], sizeof(Elf64_Phdr), 1, fp);
165 | index++;
166 | }
167 | }
168 |
169 | void OpencoreImpl::WriteCoreSignalInfo(FILE* fp) {
170 | Elf64_Nhdr elf_nhdr;
171 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
172 | elf_nhdr.n_descsz = sizeof(siginfo_t);
173 | elf_nhdr.n_type = NT_SIGINFO;
174 |
175 | char magic[8];
176 | memset(magic, 0, sizeof(magic));
177 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
178 |
179 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
180 | fwrite(magic, sizeof(magic), 1, fp);
181 |
182 | siginfo_t info;
183 | memset(&info, 0x0, sizeof(siginfo_t));
184 | if (getSignalInfo())
185 | memcpy(&info, getSignalInfo(), sizeof(siginfo_t));
186 | fwrite(&info, sizeof(siginfo_t), 1, fp);
187 | }
188 |
189 | void OpencoreImpl::WriteCoreAUXV(FILE* fp) {
190 | Elf64_Nhdr elf_nhdr;
191 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
192 | elf_nhdr.n_descsz = sizeof(lp64::Auxv) * auxvnum;
193 | elf_nhdr.n_type = NT_AUXV;
194 |
195 | char magic[8];
196 | memset(magic, 0, sizeof(magic));
197 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
198 |
199 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
200 | fwrite(magic, sizeof(magic), 1, fp);
201 |
202 | int index = 0;
203 | while (index < auxvnum) {
204 | fwrite(&auxv[index], sizeof(lp64::Auxv), 1, fp);
205 | index++;
206 | }
207 | }
208 |
209 | void OpencoreImpl::WriteNtFile(FILE* fp) {
210 | Elf64_Nhdr elf_nhdr;
211 | elf_nhdr.n_namesz = NOTE_CORE_NAME_SZ;
212 | elf_nhdr.n_descsz = sizeof(lp64::File) * phnum + 2 * 8 + RoundUp(fileslen, 4);
213 | elf_nhdr.n_type = NT_FILE;
214 |
215 | char magic[8];
216 | memset(magic, 0, sizeof(magic));
217 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC);
218 |
219 | fwrite(&elf_nhdr, sizeof(Elf64_Nhdr), 1, fp);
220 | fwrite(magic, sizeof(magic), 1, fp);
221 |
222 | uint64_t number = phnum;
223 | fwrite(&number, 8, 1, fp);
224 | fwrite(&page_size, 8, 1, fp);
225 |
226 | for (int index = 0; index < phnum; ++index)
227 | fwrite(&file[index], sizeof(lp64::File), 1, fp);
228 |
229 | for (int index = 0; index < phnum; ++index)
230 | fwrite(maps[index].file.data(), maps[index].file.length() + 1, 1, fp);
231 | }
232 |
233 | void OpencoreImpl::AlignNoteSegment(FILE* fp) {
234 | memset(zero, 0x0, align_size);
235 | uint64_t align_filesz = note.p_filesz - RoundUp(fileslen, 4) + fileslen;
236 | uint64_t offset = RoundUp(note.p_offset + align_filesz, align_size);
237 | uint64_t size = offset - (note.p_offset + align_filesz);
238 | fwrite(zero, size, 1, fp);
239 | }
240 |
241 | void OpencoreImpl::WriteCoreLoadSegment(int pid, FILE* fp) {
242 | char filename[32];
243 | int fd;
244 | int index = 0;
245 | memset(zero, 0x0, align_size);
246 |
247 | snprintf(filename, sizeof(filename), "/proc/%d/mem", pid);
248 | fd = open(filename, O_RDONLY);
249 | if (fd < 0) {
250 | JNI_LOGE("open %s fail.", filename);
251 | return;
252 | }
253 |
254 | while(index < phnum) {
255 | if (phdr[index].p_filesz > 0) {
256 | long current_pos = ftell(fp);
257 | bool need_padd_zero = false;
258 | int count = phdr[index].p_memsz / align_size;
259 | for (int i = 0; i < count; i++) {
260 | memset(zero, 0x0, align_size);
261 | pread64(fd, zero, phdr[index].p_align, phdr[index].p_vaddr + (i * align_size));
262 | uint64_t ret = fwrite(zero, align_size, 1, fp);
263 | if (ret != 1) {
264 | JNI_LOGE("[%" PRIx64 "] write load segment fail. %s %s",
265 | (uint64_t)phdr[index].p_vaddr, strerror(errno), maps[index].file.c_str());
266 | if (errno == ENOSPC)
267 | return;
268 |
269 | need_padd_zero = true;
270 | break;
271 | }
272 | }
273 | if (need_padd_zero && current_pos > 0) {
274 | memset(zero, 0x0, align_size);
275 | fseek(fp, current_pos, SEEK_SET);
276 | int count = phdr[index].p_memsz / align_size;
277 | for (int i = 0; i < count; i++)
278 | fwrite(zero, align_size, 1, fp);
279 | }
280 | }
281 | index++;
282 | }
283 | close(fd);
284 | }
285 |
286 | bool OpencoreImpl::DoCoredump(const char* filename) {
287 | Prepare(filename);
288 |
289 | FILE* fp = fopen(filename, "wb");
290 | if (!fp) {
291 | JNI_LOGE("%s %s: %s", __func__, filename, strerror(errno));
292 | return false;
293 | }
294 |
295 | StopTheWorld(getPid());
296 |
297 | ParseProcessMapsVma(getPid());
298 | CreateCoreHeader();
299 | CreateCoreNoteHeader();
300 | CreateCorePrStatus(getPid());
301 | CreateCoreAUXV(getPid());
302 | SpecialCoreFilter();
303 |
304 | // ELF Header
305 | WriteCoreHeader(fp);
306 |
307 | // Program Headers
308 | WriteCoreNoteHeader(fp);
309 | WriteCoreProgramHeaders(fp);
310 |
311 | // Segments
312 | WriteCorePrStatus(fp);
313 | WriteCoreAUXV(fp);
314 | WriteNtFile(fp);
315 | AlignNoteSegment(fp);
316 | WriteCoreLoadSegment(getPid(), fp);
317 |
318 | fflush(fp);
319 | fsync(fileno(fp));
320 | fclose(fp);
321 | return true;
322 | }
323 |
324 | int OpencoreImpl::NeedFilterFile(Opencore::VirtualMemoryArea& vma) {
325 | struct stat sb;
326 | int fd = open(vma.file.c_str(), O_RDONLY);
327 | if (fd < 0)
328 | return VMA_NULL;
329 |
330 | if (fstat(fd, &sb) < 0) {
331 | close(fd);
332 | return VMA_NULL;
333 | }
334 |
335 | char* mem = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0x0);
336 | close(fd);
337 | if (mem == MAP_FAILED)
338 | return VMA_NULL;
339 |
340 | Elf64_Ehdr* ehdr = (Elf64_Ehdr*)mem;
341 | if (strncmp(mem, ELFMAG, 4) || ehdr->e_machine != getMachine()) {
342 | munmap(mem, sb.st_size);
343 | return VMA_NULL;
344 | }
345 |
346 | int ret = VMA_NULL;
347 | Elf64_Phdr* phdr = (Elf64_Phdr *)(mem + sizeof(Elf64_Ehdr));
348 | for (int index = 0; index < ehdr->e_phnum; index++) {
349 | if (phdr[index].p_type != PT_LOAD)
350 | continue;
351 |
352 | int pos = RoundDown(phdr[index].p_offset, page_size);
353 | int end = pos + phdr[index].p_memsz;
354 | if (pos <= vma.offset && vma.offset < end) {
355 | if ((phdr[index].p_flags & PF_W))
356 | ret = VMA_NORMAL;
357 | }
358 | }
359 |
360 | munmap(mem, sb.st_size);
361 | return ret;
362 | }
363 |
364 | uint64_t OpencoreImpl::FindAuxv(uint64_t type) {
365 | for (int idx = 0; idx < auxvnum; ++idx) {
366 | if (auxv[idx].type == type)
367 | return auxv[idx].value;
368 | }
369 | return 0;
370 | }
371 |
372 | void OpencoreImpl::Prepare(const char* filename) {
373 | JNI_LOGI("Coredump %s ...", filename);
374 | zero = (uint8_t*)malloc(align_size);
375 | memset(&ehdr, 0, sizeof(Elf64_Ehdr));
376 | memset(¬e, 0, sizeof(Elf64_Phdr));
377 | }
378 |
379 | void OpencoreImpl::Finish() {
380 | if (auxv) free(auxv);
381 | if (phdr) free(phdr);
382 | if (file) free(file);
383 | if (zero) free(zero);
384 | Opencore::Finish();
385 | JNI_LOGI("Finish done.");
386 | }
387 |
388 | } // namespace lp64
389 |
--------------------------------------------------------------------------------
/opencore/src/main/java/penguin/opencore/sdk/Coredump.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package penguin.opencore.sdk;
18 |
19 | import android.os.Handler;
20 | import android.os.HandlerThread;
21 | import android.os.Looper;
22 | import android.os.Message;
23 | import android.os.Process;
24 | import android.util.Log;
25 |
26 | public class Coredump {
27 |
28 | public static final String TAG = "Coredump";
29 | private static final Coredump sInstance = new Coredump();
30 |
31 | private static volatile boolean sReady = false;
32 |
33 | private static final int STANDBY = 0;
34 | private static final int COREDUMPED = 1 << 0;
35 | private static final int COREDUMP_COMPLETED = 1 << 1;
36 | private int mCondition = STANDBY;
37 | private final Object mLock = new Object();
38 |
39 | private OpencoreHandler mCoredumpWork;
40 | private OpencorePostHandler mCoredumpPostWork;
41 | private Listener mListener;
42 | private JavaCrashHandler mJavaCrashHandler = new JavaCrashHandler();
43 |
44 | public static final int JAVA = 1;
45 | public static final int NATIVE = 2;
46 |
47 | public static final int FLAG_CORE = 1 << 0;
48 | public static final int FLAG_PROCESS_COMM = 1 << 1;
49 | public static final int FLAG_PID = 1 << 2;
50 | public static final int FLAG_THREAD_COMM = 1 << 3;
51 | public static final int FLAG_TID = 1 << 4;
52 | public static final int FLAG_TIMESTAMP = 1 << 5;
53 |
54 | public static final int DEF_TIMEOUT = 120;
55 |
56 | public static final int FILTER_NONE = 0;
57 | public static final int FILTER_SPECIAL_VMA = 1 << 0;
58 | public static final int FILTER_FILE_VMA = 1 << 1;
59 | public static final int FILTER_SHARED_VMA = 1 << 2;
60 | public static final int FILTER_SANITIZER_SHADOW_VMA = 1 << 3;
61 | public static final int FILTER_NON_READ_VMA = 1 << 4;
62 | public static final int FILTER_SIGNAL_CONTEXT = 1 << 5;
63 | public static final int FILTER_MINIDUMP = 1 << 6;
64 | public static final int FILTER_JAVAHEAP_VMA = 1 << 7;
65 | public static final int FILTER_JIT_CACHE_VMA = 1 << 8;
66 |
67 | static {
68 | try {
69 | System.loadLibrary("opencore");
70 | } catch(UnsatisfiedLinkError e) {
71 | Log.e(TAG, "Cannot load opencore library", e);
72 | }
73 | }
74 |
75 | private Coredump() {}
76 |
77 | public static Coredump getInstance() {
78 | return sInstance;
79 | }
80 |
81 | public static boolean isReady() {
82 | return sReady;
83 | }
84 |
85 | public synchronized boolean init() {
86 | if (mCoredumpWork != null && mCoredumpPostWork != null)
87 | return sReady;
88 |
89 | try {
90 | if (!nativeInit())
91 | return false;
92 |
93 | if (mCoredumpWork == null) {
94 | HandlerThread core = new HandlerThread("opencore-bg");
95 | core.start();
96 | mCoredumpWork = new OpencoreHandler(core.getLooper());
97 | }
98 |
99 | if (mCoredumpPostWork == null) {
100 | HandlerThread post = new HandlerThread("opencore-post");
101 | post.start();
102 | mCoredumpPostWork = new OpencorePostHandler(post.getLooper());
103 | }
104 |
105 | sReady = true;
106 | } catch(UnsatisfiedLinkError e) {
107 | Log.e(TAG, "opencore init work fail", e);
108 | }
109 | return sReady;
110 | }
111 |
112 | public synchronized boolean enable(int type) {
113 | if (isReady()) {
114 | switch (type) {
115 | case JAVA:
116 | return mJavaCrashHandler.enable();
117 | case NATIVE:
118 | return nativeEnable();
119 | }
120 | }
121 | return false;
122 | }
123 |
124 | public synchronized boolean disable(int type) {
125 | if (isReady()) {
126 | switch (type) {
127 | case JAVA:
128 | return mJavaCrashHandler.disable();
129 | case NATIVE:
130 | return nativeDisable();
131 | }
132 | }
133 | return false;
134 | }
135 |
136 | public synchronized boolean isEnabled(int type) {
137 | if (isReady()) {
138 | switch (type) {
139 | case JAVA:
140 | return mJavaCrashHandler.isEnabled();
141 | case NATIVE:
142 | return nativeIsEnabled();
143 | }
144 | }
145 | return false;
146 | }
147 |
148 | public synchronized boolean doCoredump() {
149 | return doCoredump(null);
150 | }
151 |
152 | public synchronized boolean doCoredump(String filename) {
153 | if (!isReady())
154 | return false;
155 |
156 | mCondition &= ~COREDUMPED;
157 | sendEvent(CODE_COREDUMP, filename, mCoredumpWork);
158 | return waitCore();
159 | }
160 |
161 | private boolean waitCore() {
162 | try {
163 | synchronized (mLock) {
164 | while ((mCondition & COREDUMPED) != COREDUMPED)
165 | mLock.wait();
166 | }
167 | } catch (InterruptedException e) {
168 | return false;
169 | }
170 | return true;
171 | }
172 |
173 | private void notifyCore() {
174 | synchronized (mLock) {
175 | mCondition |= COREDUMPED;
176 | mLock.notifyAll();
177 | }
178 | }
179 |
180 | private boolean doCompleted(String filename) {
181 | if (mListener == null)
182 | return true;
183 |
184 | mCondition &= ~COREDUMP_COMPLETED;
185 | sendEvent(CODE_COREDUMP_COMPLETED, filename, mCoredumpPostWork);
186 | return waitCompleted();
187 | }
188 |
189 | private boolean waitCompleted() {
190 | try {
191 | synchronized (mLock) {
192 | while ((mCondition & COREDUMP_COMPLETED) != COREDUMP_COMPLETED)
193 | mLock.wait();
194 | }
195 | } catch (InterruptedException e) {
196 | return false;
197 | }
198 | return true;
199 | }
200 |
201 | private void notifyCompleted() {
202 | synchronized (mLock) {
203 | mCondition |= COREDUMP_COMPLETED;
204 | mLock.notifyAll();
205 | }
206 | }
207 |
208 | private void onCompleted(String filepath) {
209 | if (mListener != null) {
210 | mListener.onCompleted(filepath);
211 | }
212 | }
213 |
214 | public void setCoreDir(String dir) {
215 | if (isReady() && dir != null) {
216 | nativeSetDir(dir);
217 | }
218 | }
219 |
220 | public void setCoreFlag(int flag) {
221 | if (isReady()) {
222 | nativeSetFlag(flag);
223 | }
224 | }
225 |
226 | public void setCoreTimeout(int sec) {
227 | if (isReady()) {
228 | nativeSetTimeout(sec);
229 | }
230 | }
231 |
232 | public void setCoreFilter(int filter) {
233 | if (isReady()) {
234 | nativeSetFilter(filter);
235 | }
236 | }
237 |
238 | public String getCoreDir() {
239 | if (isReady()) {
240 | return nativeGetDir();
241 | }
242 | return "";
243 | }
244 |
245 | public int getCoreFlag() {
246 | if (isReady()) {
247 | return nativeGetFlag();
248 | }
249 | return 0;
250 | }
251 |
252 | public int getCoreTimeout() {
253 | if (isReady()) {
254 | return nativeGetTimeout();
255 | }
256 | return DEF_TIMEOUT;
257 | }
258 |
259 | public int getCoreFilter() {
260 | if (isReady()) {
261 | return nativeGetFilter();
262 | }
263 | return FILTER_NONE;
264 | }
265 |
266 | public String getVersion() {
267 | if (isReady())
268 | return nativeVersion();
269 | return "unknown";
270 | }
271 |
272 | private static native boolean nativeInit();
273 | private static native String nativeVersion();
274 | private static native boolean nativeEnable();
275 | private static native boolean nativeDisable();
276 | private static native boolean nativeCoredump(int tid, String filename);
277 | private static native void nativeSetDir(String dir);
278 | private static native void nativeSetFlag(int flag);
279 | private static native void nativeSetTimeout(int sec);
280 | private static native void nativeSetFilter(int filter);
281 | private static native boolean nativeIsEnabled();
282 | private static native String nativeGetDir();
283 | private static native int nativeGetFlag();
284 | private static native int nativeGetTimeout();
285 | private static native int nativeGetFilter();
286 |
287 | private static final int CODE_COREDUMP = 1;
288 | private static final int CODE_COREDUMP_COMPLETED = 2;
289 |
290 | private static class OpencoreHandler extends Handler {
291 | public OpencoreHandler(Looper looper) {
292 | super(looper);
293 | }
294 |
295 | @Override
296 | public void handleMessage(Message msg) {
297 | switch (msg.what) {
298 | case CODE_COREDUMP: {
299 | if (isReady()) {
300 | if (msg.obj instanceof String) {
301 | Coredump.getInstance().nativeCoredump(msg.arg1, (String)msg.obj);
302 | } else {
303 | Coredump.getInstance().nativeCoredump(msg.arg1, null);
304 | }
305 | }
306 | // waitCore
307 | Coredump.getInstance().notifyCore();
308 | } break;
309 | }
310 | }
311 | }
312 |
313 | private static class OpencorePostHandler extends Handler {
314 | public OpencorePostHandler(Looper looper) {
315 | super(looper);
316 | }
317 |
318 | @Override
319 | public void handleMessage(Message msg) {
320 | switch (msg.what) {
321 | case CODE_COREDUMP_COMPLETED: {
322 | if (msg.obj instanceof String) {
323 | Coredump.getInstance().onCompleted((String)msg.obj);
324 | } else {
325 | Coredump.getInstance().onCompleted(null);
326 | }
327 | // waitCompleted
328 | Coredump.getInstance().notifyCompleted();
329 | } break;
330 | }
331 | }
332 | }
333 |
334 | private void sendEvent(int code, String filename, Handler handler) {
335 | Message msg = Message.obtain(handler, code, Process.myTid(), 0, filename);
336 | msg.sendToTarget();
337 | }
338 |
339 | private static void callbackEvent(String filepath) {
340 | Coredump.getInstance().doCompleted(filepath);
341 | }
342 |
343 | public static interface Listener {
344 | void onCompleted(String path);
345 | }
346 |
347 | public void setListener(Listener listener) {
348 | mListener = listener;
349 | }
350 |
351 | private static class JavaCrashHandler implements Thread.UncaughtExceptionHandler {
352 | private Thread.UncaughtExceptionHandler defaultHandler;
353 |
354 | public boolean enable() {
355 | if (defaultHandler == null) {
356 | defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
357 | }
358 | Thread.setDefaultUncaughtExceptionHandler(this);
359 | return true;
360 | }
361 |
362 | public boolean disable() {
363 | if (defaultHandler != null) {
364 | Thread.setDefaultUncaughtExceptionHandler(defaultHandler);
365 | }
366 | return true;
367 | }
368 |
369 | public boolean isEnabled() {
370 | return this == Thread.getDefaultUncaughtExceptionHandler();
371 | }
372 |
373 | @Override
374 | public void uncaughtException(Thread thread, Throwable throwable) {
375 | try {
376 | disable();
377 | Coredump.getInstance().doCoredump();
378 | } finally {
379 | Process.killProcess(Process.myPid());
380 | System.exit(10);
381 | }
382 | }
383 | }
384 |
385 | public static String coreFlagToString(int flag) {
386 | StringBuilder sb = new StringBuilder();
387 | if (flag == 0) {
388 | sb.append("FLAG_NONE");
389 | return sb.toString();
390 | }
391 |
392 | boolean need_seq = false;
393 | if ((flag & FLAG_CORE) != 0) {
394 | if (need_seq) sb.append('|');
395 | sb.append("FLAG_CORE");
396 | need_seq = true;
397 | }
398 |
399 | if ((flag & FLAG_PROCESS_COMM) != 0) {
400 | if (need_seq) sb.append('|');
401 | sb.append("FLAG_PROCESS_COMM");
402 | need_seq = true;
403 | }
404 |
405 | if ((flag & FLAG_PID) != 0) {
406 | if (need_seq) sb.append('|');
407 | sb.append("FLAG_PID");
408 | need_seq = true;
409 | }
410 |
411 | if ((flag & FLAG_THREAD_COMM) != 0) {
412 | if (need_seq) sb.append('|');
413 | sb.append("FLAG_THREAD_COMM");
414 | need_seq = true;
415 | }
416 |
417 | if ((flag & FLAG_TID) != 0) {
418 | if (need_seq) sb.append('|');
419 | sb.append("FLAG_TID");
420 | need_seq = true;
421 | }
422 |
423 | if ((flag & FLAG_TIMESTAMP) != 0) {
424 | if (need_seq) sb.append('|');
425 | sb.append("FLAG_TIMESTAMP");
426 | need_seq = true;
427 | }
428 | return sb.toString();
429 | }
430 |
431 | public static String coreFilterToString(int filter) {
432 | StringBuilder sb = new StringBuilder();
433 | if (filter == 0) {
434 | sb.append("FILTER_NONE");
435 | return sb.toString();
436 | }
437 |
438 | boolean need_seq = false;
439 | if ((filter & FILTER_SPECIAL_VMA) != 0) {
440 | if (need_seq) sb.append('|');
441 | sb.append("FILTER_SPECIAL_VMA");
442 | need_seq = true;
443 | }
444 |
445 | if ((filter & FILTER_FILE_VMA) != 0) {
446 | if (need_seq) sb.append('|');
447 | sb.append("FILTER_FILE_VMA");
448 | need_seq = true;
449 | }
450 |
451 | if ((filter & FILTER_SHARED_VMA) != 0) {
452 | if (need_seq) sb.append('|');
453 | sb.append("FILTER_SHARED_VMA");
454 | need_seq = true;
455 | }
456 |
457 | if ((filter & FILTER_SANITIZER_SHADOW_VMA) != 0) {
458 | if (need_seq) sb.append('|');
459 | sb.append("FILTER_SANITIZER_SHADOW_VMA");
460 | need_seq = true;
461 | }
462 |
463 | if ((filter & FILTER_NON_READ_VMA) != 0) {
464 | if (need_seq) sb.append('|');
465 | sb.append("FLAG_TID");
466 | need_seq = true;
467 | }
468 |
469 | if ((filter & FILTER_SIGNAL_CONTEXT) != 0) {
470 | if (need_seq) sb.append('|');
471 | sb.append("FILTER_SIGNAL_CONTEXT");
472 | need_seq = true;
473 | }
474 |
475 | if ((filter & FILTER_MINIDUMP) != 0) {
476 | if (need_seq) sb.append('|');
477 | sb.append("FILTER_MINIDUMP");
478 | need_seq = true;
479 | }
480 |
481 | if ((filter & FILTER_JAVAHEAP_VMA) != 0) {
482 | if (need_seq) sb.append('|');
483 | sb.append("FILTER_JAVAHEAP_VMA");
484 | need_seq = true;
485 | }
486 |
487 | if ((filter & FILTER_JIT_CACHE_VMA) != 0) {
488 | if (need_seq) sb.append('|');
489 | sb.append("FILTER_JIT_CACHE_VMA");
490 | need_seq = true;
491 | }
492 |
493 | return sb.toString();
494 | }
495 |
496 | @Override
497 | public String toString() {
498 | StringBuilder sb = new StringBuilder();
499 | sb.append("Coredump[");
500 | if (!isReady()) {
501 | sb.append("NOT READY!!]");
502 | return sb.toString();
503 | }
504 |
505 | sb.append(nativeVersion());
506 |
507 | sb.append(",");
508 | sb.append(nativeGetDir());
509 |
510 | sb.append(",");
511 | sb.append(coreFlagToString(nativeGetFlag()));
512 |
513 | sb.append(",");
514 | sb.append(coreFilterToString(nativeGetFilter()));
515 |
516 | sb.append(",");
517 | sb.append(mJavaCrashHandler.isEnabled());
518 |
519 | sb.append(",");
520 | sb.append(nativeIsEnabled());
521 |
522 | sb.append(",");
523 | sb.append(nativeGetTimeout());
524 |
525 | sb.append("]");
526 | return sb.toString();
527 | }
528 | }
529 |
--------------------------------------------------------------------------------
/opencore/src/main/cpp/opencore/opencore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024-present, Guanyou.Chen. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef LOG_TAG
18 | #define LOG_TAG "opencore"
19 | #endif
20 |
21 | #include "eajnis/Log.h"
22 | #include "opencore/opencore.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #if defined(__aarch64__) || defined(__arm64__)
33 | #include "opencore/arm64/opencore.h"
34 | Opencore* opencore = new arm64::Opencore();
35 | #elif defined(__arm__)
36 | #include "opencore/arm/opencore.h"
37 | Opencore* opencore = new arm::Opencore();
38 | #elif defined(__x86_64__)
39 | #include "opencore/x86_64/opencore.h"
40 | Opencore* opencore = new x86_64::Opencore();
41 | #elif defined(__i386__) || defined(__x86__)
42 | #include "opencore/x86/opencore.h"
43 | Opencore* opencore = new x86::Opencore();
44 | #elif defined(__riscv64__)
45 | #include "opencore/riscv64/opencore.h"
46 | Opencore* opencore = new riscv64::Opencore();
47 | #else
48 | Opencore* opencore = new Opencore();
49 | #endif
50 |
51 | Opencore* Opencore::GetInstance() {
52 | return opencore;
53 | }
54 |
55 | static pthread_mutex_t g_handle_lock = PTHREAD_MUTEX_INITIALIZER;
56 | static pthread_mutex_t g_switch_lock = PTHREAD_MUTEX_INITIALIZER;
57 | static constexpr int kExceptionSignals[] = {
58 | SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGTRAP
59 | };
60 | static constexpr int kNumHandledSignals = sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]);
61 | static struct sigaction g_restore_action[kNumHandledSignals] = {0};
62 | static bool handlers_installed = false;
63 |
64 | void Opencore::HandleSignal(int signal, siginfo_t* siginfo, void* ucontext_raw) {
65 | pthread_mutex_lock(&g_handle_lock);
66 | Disable();
67 | Dump(siginfo, ucontext_raw);
68 | raise(signal);
69 | pthread_mutex_unlock(&g_handle_lock);
70 | }
71 |
72 | bool Opencore::Enable() {
73 | pthread_mutex_lock(&g_switch_lock);
74 | if (handlers_installed) {
75 | JNI_LOGW("opencore native handlers already installed.");
76 | pthread_mutex_unlock(&g_switch_lock);
77 | return false;
78 | }
79 |
80 | for (int i = 0; i < kNumHandledSignals; ++i) {
81 | if (sigaction(kExceptionSignals[i], NULL, &g_restore_action[i]) == -1) {
82 | JNI_LOGE("signal %d unable to store old handler", kExceptionSignals[i]);
83 | pthread_mutex_unlock(&g_switch_lock);
84 | return false;
85 | }
86 | }
87 |
88 | struct sigaction stact;
89 | memset(&stact, 0, sizeof(stact));
90 | sigemptyset(&stact.sa_mask);
91 |
92 | for (int i = 0; i < kNumHandledSignals; ++i)
93 | sigaddset(&stact.sa_mask, kExceptionSignals[i]);
94 |
95 | stact.sa_sigaction = Opencore::HandleSignal;
96 | stact.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
97 |
98 | for (int i = 0; i < kNumHandledSignals; i++)
99 | sigaction(kExceptionSignals[i], &stact, NULL);
100 |
101 | handlers_installed = true;
102 | pthread_mutex_unlock(&g_switch_lock);
103 | return true;
104 | }
105 |
106 | bool Opencore::Disable() {
107 | pthread_mutex_lock(&g_switch_lock);
108 | if (!handlers_installed) {
109 | JNI_LOGW("opencore native handlers already uninstalled.");
110 | pthread_mutex_unlock(&g_switch_lock);
111 | return false;
112 | }
113 |
114 | for (int i = 0; i < kNumHandledSignals; i++)
115 | sigaction(kExceptionSignals[i], &g_restore_action[i], NULL);
116 |
117 | memset(&g_restore_action, 0, sizeof(g_restore_action));
118 | handlers_installed = false;
119 | pthread_mutex_unlock(&g_switch_lock);
120 | return true;
121 | }
122 |
123 | bool Opencore::IsEnabled() {
124 | bool installed = false;
125 | pthread_mutex_lock(&g_switch_lock);
126 | installed = handlers_installed;
127 | pthread_mutex_unlock(&g_switch_lock);
128 | return installed;
129 | }
130 |
131 | void Opencore::IgnoreHandler() {
132 | // only child process use
133 | struct sigaction stact;
134 | memset(&stact, 0, sizeof(stact));
135 | stact.sa_handler = SIG_IGN;
136 | stact.sa_flags = SA_RESTART;
137 | sigaction(SIGCHLD, &stact, NULL);
138 |
139 | // ignore opencore signal handler
140 | for (int i = 0; i < kNumHandledSignals; i++)
141 | sigaction(kExceptionSignals[i], &stact, NULL);
142 | }
143 |
144 | void Opencore::SetDir(const char *dir) {
145 | Opencore* impl = GetInstance();
146 | if (impl) impl->setDir(dir);
147 | }
148 |
149 | void Opencore::SetCallback(DumpCallback cb) {
150 | Opencore* impl = GetInstance();
151 | if (impl) impl->setCallback(cb);
152 | }
153 |
154 | void Opencore::SetFlag(int flag) {
155 | Opencore* impl = GetInstance();
156 | if (impl) impl->setFlag(flag);
157 | }
158 |
159 | void Opencore::SetTimeout(int sec) {
160 | Opencore* impl = GetInstance();
161 | if (impl && sec > 0)
162 | impl->setTimeout(sec);
163 | }
164 |
165 | void Opencore::SetFilter(int filter) {
166 | Opencore* impl = GetInstance();
167 | if (impl) impl->setFilter(filter);
168 | }
169 |
170 | void Opencore::TimeoutHandle(int) {
171 | JNI_LOGI("Coredump timeout.");
172 | Opencore* impl = GetInstance();
173 | if (impl) impl->Finish();
174 | _exit(0);
175 | }
176 |
177 | const char* Opencore::GetDir() {
178 | Opencore* impl = GetInstance();
179 | if (impl) {
180 | std::string& dir = impl->getDir();
181 | return dir.c_str();
182 | }
183 | return "";
184 | }
185 |
186 | int Opencore::GetFlag() {
187 | Opencore* impl = GetInstance();
188 | if (impl)
189 | return impl->getFlag();
190 | return 0;
191 | }
192 |
193 | int Opencore::GetTimeout() {
194 | Opencore* impl = GetInstance();
195 | if (impl)
196 | return impl->getTimeout();
197 | return DEF_TIMEOUT;
198 | }
199 |
200 | int Opencore::GetFilter() {
201 | Opencore* impl = GetInstance();
202 | if (impl)
203 | return impl->getFilter();
204 | return FILTER_NONE;
205 | }
206 |
207 | void Opencore::Dump() {
208 | Opencore::DumpOption option;
209 | option.pid = getpid();
210 | option.tid = gettid();
211 | Opencore::Dump(&option);
212 | }
213 |
214 | void Opencore::Dump(const char* filename) {
215 | Opencore::DumpOption option;
216 | option.filename = const_cast(filename);
217 | option.pid = getpid();
218 | option.tid = gettid();
219 | Opencore::Dump(&option);
220 | }
221 |
222 | void Opencore::Dump(const char* filename, int tid) {
223 | Opencore::DumpOption option;
224 | option.filename = const_cast(filename);
225 | option.pid = getpid();
226 | option.tid = tid;
227 | Opencore::Dump(&option);
228 | }
229 |
230 | void Opencore::Dump(siginfo_t* siginfo, void* ucontext_raw) {
231 | Opencore::DumpOption option;
232 | option.pid = getpid();
233 | option.tid = gettid();
234 | option.siginfo = siginfo;
235 | option.context = ucontext_raw;
236 | Opencore::Dump(&option);
237 | }
238 |
239 | void Opencore::Dump(Opencore::DumpOption* option) {
240 | if (!option || !option->pid) {
241 | JNI_LOGE("No any dump!");
242 | return;
243 | }
244 |
245 | int ori_dumpable;
246 | int flag, pid, tid;
247 | char comm[16];
248 | bool need_split = false;
249 | bool need_restore_dumpable = false;
250 | bool need_restore_ptrace = false;
251 | std::string output;
252 |
253 | Opencore* impl = GetInstance();
254 | if (impl) {
255 | impl->setPid(option->pid);
256 | impl->setTid(option->tid);
257 | impl->setSignalInfo(option->siginfo);
258 |
259 | if (impl->getFilter() & FILTER_SIGNAL_CONTEXT)
260 | impl->setContext(option->context);
261 |
262 | pid = impl->getPid();
263 | tid = impl->getTid();
264 | flag = impl->getFlag();
265 |
266 | if (impl->getDir().length() > 0) {
267 | output.append(impl->getDir()).append("/");
268 | }
269 | if (!option->filename) {
270 | if (!(flag & FLAG_ALL)) {
271 | flag |= FLAG_CORE;
272 | flag |= FLAG_TID;
273 | }
274 |
275 | if (flag & FLAG_CORE)
276 | output.append("core.");
277 |
278 | if (flag & FLAG_PROCESS_COMM) {
279 | char comm_path[32];
280 | snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", pid);
281 | int fd = open(comm_path, O_RDONLY);
282 | if (fd > 0) {
283 | memset(&comm, 0x0, sizeof(comm));
284 | int rc = read(fd, &comm, sizeof(comm) - 1);
285 | if (rc > 0) {
286 | for (int i = 0; i < rc; i++) {
287 | if (comm[i] == '\n') {
288 | comm[i] = 0;
289 | break;
290 | }
291 | }
292 | comm[rc] = 0;
293 | output.append(comm);
294 | } else {
295 | output.append("unknown");
296 | }
297 | close(fd);
298 | }
299 | need_split = true;
300 | }
301 |
302 | if (flag & FLAG_PID) {
303 | if (need_split)
304 | output.append("_");
305 | output.append(std::to_string(pid));
306 | need_split = true;
307 | }
308 |
309 | if (flag & FLAG_THREAD_COMM) {
310 | if (need_split)
311 | output.append("_");
312 |
313 | char thread_comm_path[64];
314 | snprintf(thread_comm_path, sizeof(thread_comm_path), "/proc/%d/task/%d/comm", pid, tid);
315 | int fd = open(thread_comm_path, O_RDONLY);
316 | if (fd > 0) {
317 | memset(&comm, 0x0, sizeof(comm));
318 | int rc = read(fd, &comm, sizeof(comm) - 1);
319 | if (rc > 0) {
320 | for (int i = 0; i < rc; i++) {
321 | if (comm[i] == '\n') {
322 | comm[i] = 0;
323 | break;
324 | }
325 | }
326 | comm[rc] = 0;
327 | output.append(comm);
328 | } else {
329 | output.append("unknown");
330 | }
331 | close(fd);
332 | }
333 | need_split = true;
334 | }
335 |
336 | if (flag & FLAG_TID) {
337 | if (need_split)
338 | output.append("_");
339 | output.append(std::to_string(tid));
340 | need_split = true;
341 | }
342 |
343 | if (flag & FLAG_TIMESTAMP) {
344 | struct timeval tv;
345 | gettimeofday(&tv, NULL);
346 | if (need_split)
347 | output.append("_");
348 | output.append(std::to_string(tv.tv_sec));
349 | }
350 | } else {
351 | output.append(option->filename);
352 | }
353 |
354 | ori_dumpable = prctl(PR_GET_DUMPABLE);
355 | if (!prctl(PR_SET_DUMPABLE, 1))
356 | need_restore_dumpable = true;
357 |
358 | if (!prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY))
359 | need_restore_ptrace = true;
360 |
361 | impl->Coredump(output.c_str());
362 |
363 | if (need_restore_dumpable) prctl(PR_SET_DUMPABLE, ori_dumpable);
364 | if (need_restore_ptrace) prctl(PR_SET_PTRACER, 0);
365 |
366 | DumpCallback callback = impl->getCallback();
367 | if (callback) callback(output.c_str());
368 | } else {
369 | JNI_LOGI("Not support coredump!!");
370 | }
371 | }
372 |
373 | bool Opencore::Coredump(const char* filename) {
374 | pid_t child = fork();
375 | if (child == 0) {
376 | IgnoreHandler();
377 | signal(SIGALRM, Opencore::TimeoutHandle);
378 | alarm(getTimeout());
379 | DoCoredump(filename);
380 | Finish();
381 | _exit(0);
382 | } else {
383 | JNI_LOGI("Wait (%d) coredump", child);
384 | int status = 0;
385 | wait(&status);
386 | }
387 | return true;
388 | }
389 |
390 | void Opencore::Finish() {
391 | Continue();
392 | maps.clear();
393 | setContext(nullptr);
394 | setSignalInfo(nullptr);
395 | }
396 |
397 | int Opencore::IsFilterSegment(Opencore::VirtualMemoryArea& vma) {
398 | int filter = getFilter();
399 | if (filter & FILTER_SPECIAL_VMA) {
400 | if (vma.file == "/dev/binderfs/hwbinder"
401 | || vma.file == "/dev/binderfs/binder"
402 | || vma.file == "[vvar]"
403 | || vma.file == "/dev/mali0"
404 | ) {
405 | return VMA_NULL;
406 | }
407 | }
408 |
409 | if (filter & FILTER_FILE_VMA) {
410 | if (vma.inode > 0 && vma.flags[1] == '-')
411 | return NeedFilterFile(vma);
412 | }
413 |
414 | if (filter & FILTER_SHARED_VMA) {
415 | if (vma.flags[3] == 's' || vma.flags[3] == 'S')
416 | return VMA_NULL;
417 | }
418 |
419 | if (filter & FILTER_SANITIZER_SHADOW_VMA) {
420 | if (vma.file == "[anon:low shadow]"
421 | || vma.file == "[anon:high shadow]"
422 | || (vma.file.compare(0, 12, "[anon:hwasan") == 0))
423 | return VMA_NULL;
424 | }
425 |
426 | if (filter & FILTER_NON_READ_VMA) {
427 | if (vma.flags[0] == '-' && vma.flags[1] == '-' && vma.flags[2] == '-')
428 | return VMA_NULL;
429 | }
430 |
431 | if (filter & FILTER_JAVAHEAP_VMA) {
432 | if (vma.file.compare(0, 12, "[anon:dalvik") == 0)
433 | return VMA_NULL;
434 | }
435 |
436 | if (filter & FILTER_JIT_CACHE_VMA) {
437 | if (vma.file.compare(0, 10, "/memfd:jit") == 0)
438 | return VMA_NULL;
439 | }
440 | return VMA_NORMAL;
441 | }
442 |
443 | void Opencore::StopTheWorld(int pid) {
444 | char task_dir[32];
445 | struct dirent *entry;
446 | snprintf(task_dir, sizeof(task_dir), "/proc/%d/task", pid);
447 | DIR *dp = opendir(task_dir);
448 | if (dp) {
449 | while ((entry=readdir(dp)) != NULL) {
450 | if (!strncmp(entry->d_name, ".", 1)) {
451 | continue;
452 | }
453 |
454 | pid_t tid = std::atoi(entry->d_name);
455 | Opencore::StopTheThread(tid);
456 | }
457 | closedir(dp);
458 | }
459 | }
460 |
461 | bool Opencore::StopTheThread(int tid) {
462 | ThreadRecord ts = {
463 | .pid = tid,
464 | .attached = false,
465 | };
466 | if (ptrace(PTRACE_ATTACH, tid, NULL, 0) < 0) {
467 | threads.push_back(ts);
468 | return false;
469 | }
470 |
471 | ts.attached = true;
472 | threads.push_back(ts);
473 |
474 | int status = 0;
475 | int result = waitpid(tid, &status, WUNTRACED | __WALL);
476 | if (result != tid) {
477 | JNI_LOGW("waitpid failed on %d while detaching", tid);
478 | return false;
479 | }
480 | if (WIFSTOPPED(status)) {
481 | int received_signal = 0;
482 | if (status >> 16 == PTRACE_EVENT_STOP) {
483 | received_signal = 0;
484 | } else {
485 | received_signal = WSTOPSIG(status);
486 | }
487 | return true;
488 | }
489 | JNI_LOGW("waitpid failed on %d while non-stop, status 0x%x", tid, status);
490 | return false;
491 | }
492 |
493 | void Opencore::Continue() {
494 | for (int index = 0; index < threads.size(); index++) {
495 | ThreadRecord& ts = threads[index];
496 | if (!ts.attached)
497 | continue;
498 |
499 | pid_t tid = ts.pid;
500 | if (ptrace(PTRACE_DETACH, tid, NULL, 0) < 0)
501 | continue;
502 | }
503 | threads.clear();
504 | }
505 |
506 | void Opencore::ParseMaps(int pid, std::vector& maps) {
507 | char filename[32];
508 | char line[1024];
509 |
510 | snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
511 | FILE *fp = fopen(filename, "r");
512 | if (fp) {
513 | while (fgets(line, sizeof(line), fp)) {
514 | int m;
515 | VirtualMemoryArea vma;
516 | char filename[256] = {'\0'};
517 |
518 |
519 | sscanf(line, "%" PRIx64 "-%" PRIx64 " %c%c%c%c %x %x:%x %" PRIu64 " %[^\n] %n",
520 | &vma.begin, &vma.end,
521 | &vma.flags[0], &vma.flags[1], &vma.flags[2], &vma.flags[3],
522 | &vma.offset, &vma.major, &vma.minor, &vma.inode, filename, &m);
523 |
524 | vma.file = filename;
525 |
526 | #if defined(__i386__) || defined(__x86__) || defined(__arm__)
527 | // avoid compat32 bit application dump64
528 | if (vma.begin > 0xFFFFFFFF)
529 | break;
530 | #endif
531 | maps.push_back(vma);
532 | }
533 | fclose(fp);
534 | }
535 | }
536 |
--------------------------------------------------------------------------------