mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-25 02:55:33 +00:00
Add inode plt hook APIs
This commit is contained in:
parent
e38f35eab2
commit
aa0a2f77cf
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -40,6 +40,9 @@
|
||||
[submodule "cxx-rs"]
|
||||
path = native/src/external/cxx-rs
|
||||
url = https://github.com/topjohnwu/cxx.git
|
||||
[submodule "lsplt"]
|
||||
path = native/src/external/lsplt
|
||||
url = https://github.com/LSPosed/LSPlt.git
|
||||
[submodule "termux-elf-cleaner"]
|
||||
path = tools/termux-elf-cleaner
|
||||
url = https://github.com/termux/termux-elf-cleaner.git
|
||||
|
@ -13,7 +13,7 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libnanopb \
|
||||
libsystemproperties \
|
||||
libphmap \
|
||||
libxhook \
|
||||
liblsplt \
|
||||
libmincrypt \
|
||||
libmagisk-rs
|
||||
|
||||
|
18
native/src/external/Android.mk
vendored
18
native/src/external/Android.mk
vendored
@ -361,21 +361,17 @@ LOCAL_SRC_FILES := \
|
||||
pcre2_workaround.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libxhook.a
|
||||
# liblsplt.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libxhook
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libxhook
|
||||
LOCAL_MODULE:= liblsplt
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/lsplt/lsplt/src/main/jni/include
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_CFLAGS := -Wall -Wextra -Werror -fvisibility=hidden -D__android_log_print=magisk_log_print
|
||||
LOCAL_CONLYFLAGS := -std=c11
|
||||
LOCAL_CPPFLAGS := -std=c++20
|
||||
LOCAL_STATIC_LIBRARIES := libcxx
|
||||
LOCAL_SRC_FILES := \
|
||||
libxhook/xh_log.c \
|
||||
libxhook/xh_version.c \
|
||||
libxhook/xh_jni.c \
|
||||
libxhook/xhook.c \
|
||||
libxhook/xh_core.c \
|
||||
libxhook/xh_util.c \
|
||||
libxhook/xh_elf.c
|
||||
lsplt/lsplt/src/main/jni/elf_util.cc \
|
||||
lsplt/lsplt/src/main/jni/lsplt.cc
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libz.a
|
||||
|
18
native/src/external/libxhook/.gitignore
vendored
18
native/src/external/libxhook/.gitignore
vendored
@ -1,18 +0,0 @@
|
||||
.DS_Store
|
||||
|
||||
libxhook/libs/
|
||||
libxhook/obj/
|
||||
libbiz/libs/
|
||||
libbiz/obj/
|
||||
libtest/libs/
|
||||
libtest/obj/
|
||||
|
||||
#for xhookwrapper
|
||||
build/
|
||||
.gradle/
|
||||
.idea/
|
||||
local.properties
|
||||
*.iml
|
||||
*.log
|
||||
*.so
|
||||
xhookwrapper/xhook/libs/
|
90
native/src/external/libxhook/LICENSE
vendored
90
native/src/external/libxhook/LICENSE
vendored
@ -1,90 +0,0 @@
|
||||
Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
|
||||
Most source code in xhook are MIT licensed. Some other source code
|
||||
have BSD-style licenses.
|
||||
|
||||
A copy of the MIT License is included in this file.
|
||||
|
||||
|
||||
Source code Licensed under the BSD 2-Clause License
|
||||
===================================================
|
||||
|
||||
tree.h
|
||||
|
||||
Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Source code Licensed under the BSD 3-Clause License
|
||||
===================================================
|
||||
|
||||
queue.h
|
||||
|
||||
Copyright (c) 1991, 1993 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
|
||||
Terms of the MIT License
|
||||
========================
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
393
native/src/external/libxhook/LICENSE-docs
vendored
393
native/src/external/libxhook/LICENSE-docs
vendored
@ -1,393 +0,0 @@
|
||||
Attribution 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More_considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution 4.0 International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution 4.0 International Public License ("Public License"). To the
|
||||
extent this Public License may be interpreted as a contract, You are
|
||||
granted the Licensed Rights in consideration of Your acceptance of
|
||||
these terms and conditions, and the Licensor grants You such rights in
|
||||
consideration of benefits the Licensor receives from making the
|
||||
Licensed Material available under these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
d. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
f. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
g. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
h. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
i. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
j. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
k. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
4. If You Share Adapted Material You produce, the Adapter's
|
||||
License You apply must not prevent recipients of the Adapted
|
||||
Material from complying with this Public License.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material; and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public licenses.
|
||||
Notwithstanding, Creative Commons may elect to apply one of its public
|
||||
licenses to material it publishes and in those instances will be
|
||||
considered the "Licensor." Except for the limited purpose of indicating
|
||||
that material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the public
|
||||
licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
200
native/src/external/libxhook/README.md
vendored
200
native/src/external/libxhook/README.md
vendored
@ -1,200 +0,0 @@
|
||||
<p align="center"><img src="https://github.com/iqiyi/xHook/blob/master/docs/xhooklogo.png?raw=true" alt="xhook" width="50%"></p>
|
||||
|
||||
# xHook
|
||||
|
||||
![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)
|
||||
![](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)
|
||||
![](https://img.shields.io/badge/release-1.2.0-red.svg?style=flat)
|
||||
![](https://img.shields.io/badge/Android-4.0%20--%2010-blue.svg?style=flat)
|
||||
![](https://img.shields.io/badge/arch-armeabi%20%7C%20armeabi--v7a%20%7C%20arm64--v8a%20%7C%20x86%20%7C%20x86__64-blue.svg?style=flat)
|
||||
|
||||
[README 中文版](README.zh-CN.md)
|
||||
|
||||
[Android PLT hook 概述 中文版](docs/overview/android_plt_hook_overview.zh-CN.md)
|
||||
|
||||
xHook is a PLT (Procedure Linkage Table) hook library for Android native ELF (executable and shared libraries).
|
||||
|
||||
xHook has been keeping optimized for stability and compatibility.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* Support Android 4.0 - 10 (API level 14 - 29).
|
||||
* Support armeabi, armeabi-v7a, arm64-v8a, x86 and x86_64.
|
||||
* Support **ELF HASH** and **GNU HASH** indexed symbols.
|
||||
* Support **SLEB128** encoded relocation info.
|
||||
* Support setting hook info via regular expressions.
|
||||
* Do not require root permission or any system permissions.
|
||||
* Do not depends on any third-party shared libraries.
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
* Download [Android NDK r16b](https://developer.android.com/ndk/downloads/revision_history.html), set environment PATH. (support for armeabi has been removed since r17)
|
||||
|
||||
* Build and install the native libraries.
|
||||
|
||||
```
|
||||
./build_libs.sh
|
||||
./install_libs.sh
|
||||
```
|
||||
|
||||
|
||||
## Demo
|
||||
|
||||
```
|
||||
cd ./xhookwrapper/
|
||||
./gradlew assembleDebug
|
||||
adb install ./app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
External API header file: `libxhook/jni/xhook.h`
|
||||
|
||||
### 1. Register hook info
|
||||
|
||||
```c
|
||||
int xhook_register(const char *pathname_regex_str,
|
||||
const char *symbol,
|
||||
void *new_func,
|
||||
void **old_func);
|
||||
```
|
||||
|
||||
In current process's memory space, in every loaded ELF which pathname matches regular expression `pathname_regex_str`, every PLT entries to `symbol` will be **replaced with** `new_func`. The original one will be saved in `old_func`.
|
||||
|
||||
The `new_func` **must** have the same function declaration as the original one.
|
||||
|
||||
Return zero if successful, non-zero otherwise.
|
||||
|
||||
The regular expression for `pathname_regex_str` only support **POSIX BRE (Basic Regular Expression)**.
|
||||
|
||||
### 2. Ignore some hook info
|
||||
|
||||
```c
|
||||
int xhook_ignore(const char *pathname_regex_str,
|
||||
const char *symbol);
|
||||
```
|
||||
|
||||
Ignore some hook info according to `pathname_regex_str` and `symbol`, from registered hooks by `xhook_register`. If `symbol` is `NULL`, xhook will ignore all symbols from ELF which pathname matches `pathname_regex_str`.
|
||||
|
||||
Return zero if successful, non-zero otherwise.
|
||||
|
||||
The regular expression for `pathname_regex_str` only support **POSIX BRE**.
|
||||
|
||||
### 3. Do hook
|
||||
|
||||
```c
|
||||
int xhook_refresh(int async);
|
||||
```
|
||||
|
||||
Do the real hook operations according to the registered hook info.
|
||||
|
||||
Pass `1` to `async` for asynchronous hook. Pass `0` to `async` for synchronous hook.
|
||||
|
||||
Return zero if successful, non-zero otherwise.
|
||||
|
||||
xhook will keep a global cache for saving the last ELF loading info from `/proc/self/maps`. This cache will also be updated in `xhook_refresh`. With this cache, `xhook_refresh` can determine which ELF is newly loaded. We only need to do hook in these newly loaded ELF.
|
||||
|
||||
### 4. Clear cache
|
||||
|
||||
```c
|
||||
void xhook_clear();
|
||||
```
|
||||
|
||||
Clear all cache owned by xhook, reset all global flags to default value.
|
||||
|
||||
If you confirm that all PLT entries you want have been hooked, you could call this function to save some memory.
|
||||
|
||||
### 5. Enable/Disable debug info
|
||||
|
||||
```c
|
||||
void xhook_enable_debug(int flag);
|
||||
```
|
||||
|
||||
Pass `1` to `flag` for enable debug info. Pass `0` to `flag` for disable. (**disabled** by default)
|
||||
|
||||
Debug info will be sent to logcat with tag `xhook`.
|
||||
|
||||
### 6. Enable/Disable SFP (segmentation fault protection)
|
||||
|
||||
```c
|
||||
void xhook_enable_sigsegv_protection(int flag);
|
||||
```
|
||||
|
||||
Pass `1` to `flag` for enable SFP. Pass `0` to `flag` for disable. (**enabled** by default)
|
||||
|
||||
xhook is NOT a compliant business layer library. We have to calculate the value of some pointers directly. Reading or writing the memory pointed to by these pointers will cause a segmentation fault in some unusual situations and environment. The APP crash rate increased which caused by xhook is about one ten-millionth (0.0000001) according to our test. (The increased crash rate is also related to the ELFs and symbols you need to hook). Finally, we have to use some trick to prevent this harmless crashing. We called it SFP (segmentation fault protection) which consists of: `sigaction()`, `SIGSEGV`, `siglongjmp()` and `sigsetjmp()`.
|
||||
|
||||
**You should always enable SFP for release-APP, this will prevent your app from crashing. On the other hand, you should always disable SFP for debug-APP, so you can't miss any common coding mistakes that should be fixed.**
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
```c
|
||||
//detect memory leaks
|
||||
xhook_register(".*\\.so$", "malloc", my_malloc, NULL);
|
||||
xhook_register(".*\\.so$", "calloc", my_calloc, NULL);
|
||||
xhook_register(".*\\.so$", "realloc", my_realloc, NULL);
|
||||
xhook_register(".*\\.so$", "free", my_free, NULL);
|
||||
|
||||
//inspect sockets lifecycle
|
||||
xhook_register(".*\\.so$", "getaddrinfo", my_getaddrinfo, NULL);
|
||||
xhook_register(".*\\.so$", "socket", my_socket, NULL);
|
||||
xhook_register(".*\\.so$", "setsockopt" my_setsockopt, NULL);
|
||||
xhook_register(".*\\.so$", "bind", my_bind, NULL);
|
||||
xhook_register(".*\\.so$", "listen", my_listen, NULL);
|
||||
xhook_register(".*\\.so$", "connect", my_connect, NULL);
|
||||
xhook_register(".*\\.so$", "shutdown", my_shutdown, NULL);
|
||||
xhook_register(".*\\.so$", "close", my_close, NULL);
|
||||
|
||||
//filter off and save some android log to local file
|
||||
xhook_register(".*\\.so$", "__android_log_write", my_log_write, NULL);
|
||||
xhook_register(".*\\.so$", "__android_log_print", my_log_print, NULL);
|
||||
xhook_register(".*\\.so$", "__android_log_vprint", my_log_vprint, NULL);
|
||||
xhook_register(".*\\.so$", "__android_log_assert", my_log_assert, NULL);
|
||||
|
||||
//tracking (ignore linker and linker64)
|
||||
xhook_register("^/system/.*$", "mmap", my_mmap, NULL);
|
||||
xhook_register("^/vendor/.*$", "munmap", my_munmap, NULL);
|
||||
xhook_ignore (".*/linker$", "mmap");
|
||||
xhook_ignore (".*/linker$", "munmap");
|
||||
xhook_ignore (".*/linker64$", "mmap");
|
||||
xhook_ignore (".*/linker64$", "munmap");
|
||||
|
||||
//defense to some injection attacks
|
||||
xhook_register(".*com\\.hacker.*\\.so$", "malloc", my_malloc_always_return_NULL, NULL);
|
||||
xhook_register(".*/libhacker\\.so$", "connect", my_connect_with_recorder, NULL);
|
||||
|
||||
//fix some system bug
|
||||
xhook_register(".*some_vendor.*/libvictim\\.so$", "bad_func", my_nice_func, NULL);
|
||||
|
||||
//ignore all hooks in libwebviewchromium.so
|
||||
xhook_ignore(".*/libwebviewchromium.so$", NULL);
|
||||
|
||||
//hook now!
|
||||
xhook_refresh(1);
|
||||
```
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
1. Check the [xhook-sample](libbiz/jni).
|
||||
2. Communicate on [GitHub issues](https://github.com/iqiyi/xHook/issues).
|
||||
3. Mail: <a href="mailto:caikelun@gmail.com">caikelun@gmail.com</a>
|
||||
4. QQ group: 603635869. QR code:
|
||||
|
||||
<p align="left"><img src="docs/qq_group.jpg" alt="qq group" width="300px"></p>
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
See [xHook Contributing Guide](CONTRIBUTING.md).
|
||||
|
||||
|
||||
## License
|
||||
|
||||
xHook is MIT licensed, as found in the [LICENSE](LICENSE) file.
|
||||
|
||||
xHook documentation is Creative Commons licensed, as found in the [LICENSE-docs](LICENSE-docs) file.
|
200
native/src/external/libxhook/README.zh-CN.md
vendored
200
native/src/external/libxhook/README.zh-CN.md
vendored
@ -1,200 +0,0 @@
|
||||
<p align="center"><img src="https://github.com/iqiyi/xHook/blob/master/docs/xhooklogo.png?raw=true" alt="xhook" width="50%"></p>
|
||||
|
||||
# xHook
|
||||
|
||||
![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)
|
||||
![](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)
|
||||
![](https://img.shields.io/badge/release-1.2.0-red.svg?style=flat)
|
||||
![](https://img.shields.io/badge/Android-4.0%20--%2010-blue.svg?style=flat)
|
||||
![](https://img.shields.io/badge/arch-armeabi%20%7C%20armeabi--v7a%20%7C%20arm64--v8a%20%7C%20x86%20%7C%20x86__64-blue.svg?style=flat)
|
||||
|
||||
[README English Version](README.md)
|
||||
|
||||
[Android PLT hook 概述 中文版](docs/overview/android_plt_hook_overview.zh-CN.md)
|
||||
|
||||
xHook 是一个针对 Android 平台 ELF (可执行文件和动态库) 的 PLT (Procedure Linkage Table) hook 库。
|
||||
|
||||
xHook 一直在稳定性和兼容性方面做着持续的优化。
|
||||
|
||||
|
||||
## 特征
|
||||
|
||||
* 支持 Android 4.0 - 10(API level 14 - 29)。
|
||||
* 支持 armeabi,armeabi-v7a,arm64-v8a,x86 和 x86_64。
|
||||
* 支持 **ELF HASH** 和 **GNU HASH** 索引的符号。
|
||||
* 支持 **SLEB128** 编码的重定位信息。
|
||||
* 支持通过正则表达式批量设置 hook 信息。
|
||||
* 不需要 root 权限或任何系统权限。
|
||||
* 不依赖于任何的第三方动态库。
|
||||
|
||||
|
||||
## 编译
|
||||
|
||||
* 下载 [Android NDK r16b](https://developer.android.com/ndk/downloads/revision_history.html),设置 PATH 环境变量。(对 armeabi 的支持,从 r17 版本开始被移除了)
|
||||
|
||||
* 编译和安装 native 库。
|
||||
|
||||
```
|
||||
./build_libs.sh
|
||||
./install_libs.sh
|
||||
```
|
||||
|
||||
|
||||
## Demo
|
||||
|
||||
```
|
||||
cd ./xhookwrapper/
|
||||
./gradlew assembleDebug
|
||||
adb install ./app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
外部 API 头文件: `libxhook/jni/xhook.h`
|
||||
|
||||
### 1. 注册 hook 信息
|
||||
|
||||
```c
|
||||
int xhook_register(const char *pathname_regex_str,
|
||||
const char *symbol,
|
||||
void *new_func,
|
||||
void **old_func);
|
||||
```
|
||||
|
||||
在当前进程的内存空间中,在每一个符合正则表达式 `pathname_regex_str` 的已加载ELF中,每一个调用 `symbol` 的 PLT 入口点的地址值都将给替换成 `new_func`。之前的 PLT 入口点的地址值将被保存在 `old_func` 中。
|
||||
|
||||
`new_func` 必须具有和原函数同样的函数声明。
|
||||
|
||||
成功返回 0,失败返回 非0。
|
||||
|
||||
`pathname_regex_str` 只支持 **POSIX BRE (Basic Regular Expression)** 定义的正则表达式语法。
|
||||
|
||||
### 2. 忽略部分 hook 信息
|
||||
|
||||
```c
|
||||
int xhook_ignore(const char *pathname_regex_str,
|
||||
const char *symbol);
|
||||
```
|
||||
|
||||
根据 `pathname_regex_str` 和 `symbol`,从已经通过 `xhook_register` 注册的 hook 信息中,忽略一部分 hook 信息。如果 `symbol` 为 `NULL`,xhook 将忽略所有路径名符合正则表达式 `pathname_regex_str` 的 ELF。
|
||||
|
||||
成功返回 0,失败返回 非0。
|
||||
|
||||
`pathname_regex_str` 只支持 **POSIX BRE** 定义的正则表达式语法。
|
||||
|
||||
### 3. 执行 hook
|
||||
|
||||
```c
|
||||
int xhook_refresh(int async);
|
||||
```
|
||||
|
||||
根据前面注册的 hook 信息,执行真正的 hook 操作。
|
||||
|
||||
给 `async` 参数传 `1` 表示执行异步的 hook 操作,传 `0` 表示执行同步的 hook 操作。
|
||||
|
||||
成功返回 0,失败返回 非0。
|
||||
|
||||
xhook 在内部维护了一个全局的缓存,用于保存最后一次从 `/proc/self/maps` 读取到的 ELF 加载信息。每次一调用 `xhook_refresh` 函数,这个缓存都将被更新。xhook 使用这个缓存来判断哪些 ELF 是这次新被加载到内存中的。我们每次只需要针对这些新加载的 ELF 做 hook 就可以了。
|
||||
|
||||
### 4. 清除缓存
|
||||
|
||||
```c
|
||||
void xhook_clear();
|
||||
```
|
||||
|
||||
清除 xhook 的缓存,重置所有的全局标示。
|
||||
|
||||
如果你确定你需要的所有 PLT 入口点都已经被替换了,你可以调用这个函数来释放和节省一些内存空间。
|
||||
|
||||
### 5. 启用/禁用 调试信息
|
||||
|
||||
```c
|
||||
void xhook_enable_debug(int flag);
|
||||
```
|
||||
|
||||
给 `flag` 参数传 `1` 表示启用调试信息,传 `0` 表示禁用调试信息。 (默认为:**禁用**)
|
||||
|
||||
调试信息将被输出到 logcat,对应的 TAG 为:`xhook`。
|
||||
|
||||
### 6. 启用/禁用 SFP (段错误保护)
|
||||
|
||||
```c
|
||||
void xhook_enable_sigsegv_protection(int flag);
|
||||
```
|
||||
|
||||
给 `flag` 参数传 `1` 表示启用 SFP,传 `0` 表示禁用 SFP。 (默认为:**启用**)
|
||||
|
||||
xhook 并不是一个常规的业务层的动态库。在 xhook 中,我们不得不直接计算一些内存指针的值。在一些极端的情况和环境下,读或者写这些指针指向的内存会发生段错误。根据我们的测试,xhook 的行为将导致 APP 崩溃率增加 “一千万分之一” (0.0000001)。(具体崩溃率可能会增加多少,也和你想要 hook 的库和符号有关)。最终,我们不得不使用某些方法来防止这些无害的崩溃。我们叫它SFP (段错误保护),它是由这些调用和值组成的:`sigaction()`, `SIGSEGV`, `siglongjmp()` 和 `sigsetjmp()`。
|
||||
|
||||
**在 release 版本的 APP 中,你应该始终启用 SFP,这能防止你的 APP 因为 xhook 而崩溃。在 debug 版本的 APP 中,你应该始终禁用 SFP,这样你就不会丢失那些一般性的编码失误导致的段错误,这些段错误是应该被修复的。**
|
||||
|
||||
|
||||
## 例子
|
||||
|
||||
```c
|
||||
//监测内存泄露
|
||||
xhook_register(".*\\.so$", "malloc", my_malloc, NULL);
|
||||
xhook_register(".*\\.so$", "calloc", my_calloc, NULL);
|
||||
xhook_register(".*\\.so$", "realloc", my_realloc, NULL);
|
||||
xhook_register(".*\\.so$", "free", my_free, NULL);
|
||||
|
||||
//监控 sockets 生命周期
|
||||
xhook_register(".*\\.so$", "getaddrinfo", my_getaddrinfo, NULL);
|
||||
xhook_register(".*\\.so$", "socket", my_socket, NULL);
|
||||
xhook_register(".*\\.so$", "setsockopt" my_setsockopt, NULL);
|
||||
xhook_register(".*\\.so$", "bind", my_bind, NULL);
|
||||
xhook_register(".*\\.so$", "listen", my_listen, NULL);
|
||||
xhook_register(".*\\.so$", "connect", my_connect, NULL);
|
||||
xhook_register(".*\\.so$", "shutdown", my_shutdown, NULL);
|
||||
xhook_register(".*\\.so$", "close", my_close, NULL);
|
||||
|
||||
//过滤出和保存部分安卓 log 到本地文件
|
||||
xhook_register(".*\\.so$", "__android_log_write", my_log_write, NULL);
|
||||
xhook_register(".*\\.so$", "__android_log_print", my_log_print, NULL);
|
||||
xhook_register(".*\\.so$", "__android_log_vprint", my_log_vprint, NULL);
|
||||
xhook_register(".*\\.so$", "__android_log_assert", my_log_assert, NULL);
|
||||
|
||||
//追踪某些调用 (忽略 linker 和 linker64)
|
||||
xhook_register("^/system/.*$", "mmap", my_mmap, NULL);
|
||||
xhook_register("^/vendor/.*$", "munmap", my_munmap, NULL);
|
||||
xhook_ignore (".*/linker$", "mmap");
|
||||
xhook_ignore (".*/linker$", "munmap");
|
||||
xhook_ignore (".*/linker64$", "mmap");
|
||||
xhook_ignore (".*/linker64$", "munmap");
|
||||
|
||||
//防御某些注入攻击
|
||||
xhook_register(".*com\\.hacker.*\\.so$", "malloc", my_malloc_always_return_NULL, NULL);
|
||||
xhook_register(".*/libhacker\\.so$", "connect", my_connect_with_recorder, NULL);
|
||||
|
||||
//修复某些系统 bug
|
||||
xhook_register(".*some_vendor.*/libvictim\\.so$", "bad_func", my_nice_func, NULL);
|
||||
|
||||
//忽略 libwebviewchromium.so 的所有 hook 信息
|
||||
xhook_ignore(".*/libwebviewchromium.so$", NULL);
|
||||
|
||||
//现在执行 hook!
|
||||
xhook_refresh(1);
|
||||
```
|
||||
|
||||
|
||||
## 技术支持
|
||||
|
||||
1. 查看 [xhook-sample](libbiz/jni)。
|
||||
2. 在 [GitHub issues](https://github.com/iqiyi/xHook/issues) 交流。
|
||||
3. 邮件: <a href="mailto:caikelun@gmail.com">caikelun@gmail.com</a>
|
||||
5. QQ 群: 603635869。二维码:
|
||||
|
||||
<p align="left"><img src="docs/qq_group.jpg" alt="qq group" width="320px"></p>
|
||||
|
||||
|
||||
## 贡献
|
||||
|
||||
请阅读 [xHook Contributing Guide](CONTRIBUTING.md)。
|
||||
|
||||
|
||||
## 许可证
|
||||
|
||||
xHook 使用 [MIT 许可证](LICENSE)。
|
||||
|
||||
xHook 的文档使用 [Creative Commons 许可证](LICENSE-docs)。
|
554
native/src/external/libxhook/queue.h
vendored
554
native/src/external/libxhook/queue.h
vendored
@ -1,554 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
* $FreeBSD: stable/9/sys/sys/queue.h 252365 2013-06-29 04:25:40Z lstewart $
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
/* #include <sys/cdefs.h> */
|
||||
#define __containerof(ptr, type, field) ((type *)((char *)(ptr) - ((char *)&((type *)0)->field)))
|
||||
|
||||
/*
|
||||
* This file defines four types of data structures: singly-linked lists,
|
||||
* singly-linked tail queues, lists and tail queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A singly-linked tail queue is headed by a pair of pointers, one to the
|
||||
* head of the list and the other to the tail of the list. The elements are
|
||||
* singly linked for minimum space and pointer manipulation overhead at the
|
||||
* expense of O(n) removal for arbitrary elements. New elements can be added
|
||||
* to the list after an existing element, at the head of the list, or at the
|
||||
* end of the list. Elements being removed from the head of the tail queue
|
||||
* should use the explicit macro for this purpose for optimum efficiency.
|
||||
* A singly-linked tail queue may only be traversed in the forward direction.
|
||||
* Singly-linked tail queues are ideal for applications with large datasets
|
||||
* and few or no removals or for implementing a FIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may be traversed in either direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*
|
||||
* SLIST LIST STAILQ TAILQ
|
||||
* _HEAD + + + +
|
||||
* _HEAD_INITIALIZER + + + +
|
||||
* _ENTRY + + + +
|
||||
* _INIT + + + +
|
||||
* _EMPTY + + + +
|
||||
* _FIRST + + + +
|
||||
* _NEXT + + + +
|
||||
* _PREV - + - +
|
||||
* _LAST - - + +
|
||||
* _FOREACH + + + +
|
||||
* _FOREACH_FROM + + + +
|
||||
* _FOREACH_SAFE + + + +
|
||||
* _FOREACH_FROM_SAFE + + + +
|
||||
* _FOREACH_REVERSE - - - +
|
||||
* _FOREACH_REVERSE_FROM - - - +
|
||||
* _FOREACH_REVERSE_SAFE - - - +
|
||||
* _FOREACH_REVERSE_FROM_SAFE - - - +
|
||||
* _INSERT_HEAD + + + +
|
||||
* _INSERT_BEFORE - + - +
|
||||
* _INSERT_AFTER + + + +
|
||||
* _INSERT_TAIL - - + +
|
||||
* _CONCAT - - + +
|
||||
* _REMOVE_AFTER + - + -
|
||||
* _REMOVE_HEAD + - + -
|
||||
* _REMOVE + + + +
|
||||
* _SWAP + + + +
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Singly-linked List declarations.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
struct type *qual slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type, qual) \
|
||||
struct { \
|
||||
struct type *qual sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) do { \
|
||||
SLIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
|
||||
SLIST_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
|
||||
SLIST_NEXT((slistelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_AFTER(elm, field) do { \
|
||||
SLIST_NEXT(elm, field) = \
|
||||
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if (SLIST_FIRST((head)) == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = SLIST_FIRST((head)); \
|
||||
while (SLIST_NEXT(curelm, field) != (elm)) \
|
||||
curelm = SLIST_NEXT(curelm, field); \
|
||||
SLIST_REMOVE_AFTER(curelm, field); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_SWAP(head1, head2, type) do { \
|
||||
struct type *swap_first = SLIST_FIRST(head1); \
|
||||
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
|
||||
SLIST_FIRST(head2) = swap_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* List declarations.
|
||||
*/
|
||||
#define LIST_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
struct type *qual lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type, qual) \
|
||||
struct { \
|
||||
struct type *qual le_next; /* next element */ \
|
||||
struct type *qual *le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_PREV(elm, head, type, field) \
|
||||
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
|
||||
__containerof((elm)->field.le_prev, struct type, field.le_next))
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = LIST_NEXT((var), field))
|
||||
|
||||
#define LIST_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = LIST_NEXT((var), field))
|
||||
|
||||
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
|
||||
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
|
||||
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \
|
||||
LIST_FIRST((head)) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
LIST_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \
|
||||
LIST_NEXT((listelm), field)->field.le_prev = \
|
||||
&LIST_NEXT((elm), field); \
|
||||
LIST_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if (LIST_NEXT((elm), field) != NULL) \
|
||||
LIST_NEXT((elm), field)->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_SWAP(head1, head2, type, field) do { \
|
||||
struct type *swap_tmp = LIST_FIRST((head1)); \
|
||||
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
|
||||
LIST_FIRST((head2)) = swap_tmp; \
|
||||
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
|
||||
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue declarations.
|
||||
*/
|
||||
#define STAILQ_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
struct type *qual stqh_first;/* first element */ \
|
||||
struct type *qual *stqh_last;/* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
|
||||
#define STAILQ_ENTRY(type, qual) \
|
||||
struct { \
|
||||
struct type *qual stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue functions.
|
||||
*/
|
||||
#define STAILQ_INIT(head) do { \
|
||||
STAILQ_FIRST((head)) = NULL; \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
#define STAILQ_LAST(head, type, field) \
|
||||
(STAILQ_EMPTY((head)) ? NULL : \
|
||||
__containerof((head)->stqh_last, struct type, field.stqe_next))
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for((var) = STAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
#define STAILQ_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = STAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_NEXT((tqelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
STAILQ_NEXT((elm), field) = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_CONCAT(head1, head2) do { \
|
||||
if (!STAILQ_EMPTY((head2))) { \
|
||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT(elm, field) = \
|
||||
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if ((STAILQ_FIRST((head)) = \
|
||||
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
if (STAILQ_FIRST((head)) == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = STAILQ_FIRST((head)); \
|
||||
while (STAILQ_NEXT(curelm, field) != (elm)) \
|
||||
curelm = STAILQ_NEXT(curelm, field); \
|
||||
STAILQ_REMOVE_AFTER(head, curelm, field); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_SWAP(head1, head2, type) do { \
|
||||
struct type *swap_first = STAILQ_FIRST(head1); \
|
||||
struct type **swap_last = (head1)->stqh_last; \
|
||||
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_FIRST(head2) = swap_first; \
|
||||
(head2)->stqh_last = swap_last; \
|
||||
if (STAILQ_EMPTY(head1)) \
|
||||
(head1)->stqh_last = &STAILQ_FIRST(head1); \
|
||||
if (STAILQ_EMPTY(head2)) \
|
||||
(head2)->stqh_last = &STAILQ_FIRST(head2); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue declarations.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
struct type *qual tqh_first; /* first element */ \
|
||||
struct type *qual *tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type, qual) \
|
||||
struct { \
|
||||
struct type *qual tqe_next; /* next element */ \
|
||||
struct type *qual *tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
TAILQ_FIRST((head)) = NULL; \
|
||||
(head)->tqh_last = &TAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var); \
|
||||
(var) = TAILQ_PREV((var), headname, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
|
||||
(var); \
|
||||
(var) = TAILQ_PREV((var), headname, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
|
||||
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
|
||||
TAILQ_FIRST((head))->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
TAILQ_FIRST((head)) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
TAILQ_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
TAILQ_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
TAILQ_NEXT((elm), field) = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if ((TAILQ_NEXT((elm), field)) != NULL) \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_SWAP(head1, head2, type, field) do { \
|
||||
struct type *swap_first = (head1)->tqh_first; \
|
||||
struct type **swap_last = (head1)->tqh_last; \
|
||||
(head1)->tqh_first = (head2)->tqh_first; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
(head2)->tqh_first = swap_first; \
|
||||
(head2)->tqh_last = swap_last; \
|
||||
if ((swap_first = (head1)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head1)->tqh_first; \
|
||||
else \
|
||||
(head1)->tqh_last = &(head1)->tqh_first; \
|
||||
if ((swap_first = (head2)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head2)->tqh_first; \
|
||||
else \
|
||||
(head2)->tqh_last = &(head2)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
768
native/src/external/libxhook/tree.h
vendored
768
native/src/external/libxhook/tree.h
vendored
@ -1,768 +0,0 @@
|
||||
/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
|
||||
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
|
||||
/* $FreeBSD: stable/9/sys/sys/tree.h 189204 2009-03-01 04:57:23Z bms $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TREE_H
|
||||
#define TREE_H
|
||||
|
||||
/* #include <sys/cdefs.h> */
|
||||
#ifndef __unused
|
||||
#define __unused __attribute__((__unused__))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file defines data structures for different types of trees:
|
||||
* splay trees and red-black trees.
|
||||
*
|
||||
* A splay tree is a self-organizing data structure. Every operation
|
||||
* on the tree causes a splay to happen. The splay moves the requested
|
||||
* node to the root of the tree and partly rebalances it.
|
||||
*
|
||||
* This has the benefit that request locality causes faster lookups as
|
||||
* the requested nodes move to the top of the tree. On the other hand,
|
||||
* every lookup causes memory writes.
|
||||
*
|
||||
* The Balance Theorem bounds the total access time for m operations
|
||||
* and n inserts on an initially empty tree as O((m + n)lg n). The
|
||||
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
|
||||
*
|
||||
* A red-black tree is a binary search tree with the node color as an
|
||||
* extra attribute. It fulfills a set of conditions:
|
||||
* - every search path from the root to a leaf consists of the
|
||||
* same number of black nodes,
|
||||
* - each red node (except for the root) has a black parent,
|
||||
* - each leaf node is black.
|
||||
*
|
||||
* Every operation on a red-black tree is bounded as O(lg n).
|
||||
* The maximum height of a red-black tree is 2lg (n+1).
|
||||
*/
|
||||
|
||||
#define SPLAY_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sph_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define SPLAY_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define SPLAY_INIT(root) do { \
|
||||
(root)->sph_root = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *spe_left; /* left element */ \
|
||||
struct type *spe_right; /* right element */ \
|
||||
}
|
||||
|
||||
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
|
||||
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
|
||||
#define SPLAY_ROOT(head) (head)->sph_root
|
||||
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
||||
|
||||
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
||||
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKLEFT(head, tmp, field) do { \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
|
||||
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
/* Generates prototypes and inline functions */
|
||||
|
||||
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
|
||||
void name##_SPLAY(struct name *, struct type *); \
|
||||
void name##_SPLAY_MINMAX(struct name *, int); \
|
||||
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
|
||||
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_FIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return(NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) \
|
||||
return (head->sph_root); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
name##_SPLAY(head, elm); \
|
||||
if (SPLAY_RIGHT(elm, field) != NULL) { \
|
||||
elm = SPLAY_RIGHT(elm, field); \
|
||||
while (SPLAY_LEFT(elm, field) != NULL) { \
|
||||
elm = SPLAY_LEFT(elm, field); \
|
||||
} \
|
||||
} else \
|
||||
elm = NULL; \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_MIN_MAX(struct name *head, int val) \
|
||||
{ \
|
||||
name##_SPLAY_MINMAX(head, val); \
|
||||
return (SPLAY_ROOT(head)); \
|
||||
}
|
||||
|
||||
/* Main splay operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define SPLAY_GENERATE(name, type, field, cmp) \
|
||||
struct type * \
|
||||
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
||||
} else { \
|
||||
int __comp; \
|
||||
name##_SPLAY(head, elm); \
|
||||
__comp = (cmp)(elm, (head)->sph_root); \
|
||||
if(__comp < 0) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
|
||||
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
||||
} else if (__comp > 0) { \
|
||||
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
|
||||
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
||||
} else \
|
||||
return ((head)->sph_root); \
|
||||
} \
|
||||
(head)->sph_root = (elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
struct type * \
|
||||
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *__tmp; \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return (NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) { \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
|
||||
} else { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
|
||||
name##_SPLAY(head, elm); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
name##_SPLAY(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
int __comp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) > 0){ \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
} \
|
||||
\
|
||||
/* Splay with either the minimum or the maximum element \
|
||||
* Used to find minimum or maximum element in tree. \
|
||||
*/ \
|
||||
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while (1) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp > 0) { \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
}
|
||||
|
||||
#define SPLAY_NEGINF -1
|
||||
#define SPLAY_INF 1
|
||||
|
||||
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
|
||||
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
|
||||
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
|
||||
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
|
||||
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
|
||||
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
|
||||
|
||||
#define SPLAY_FOREACH(x, name, head) \
|
||||
for ((x) = SPLAY_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = SPLAY_NEXT(name, head, x))
|
||||
|
||||
/* Macros that define a red-black tree */
|
||||
#define RB_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *rbh_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define RB_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define RB_INIT(root) do { \
|
||||
(root)->rbh_root = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define RB_BLACK 0
|
||||
#define RB_RED 1
|
||||
#define RB_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *rbe_left; /* left element */ \
|
||||
struct type *rbe_right; /* right element */ \
|
||||
struct type *rbe_parent; /* parent element */ \
|
||||
int rbe_color; /* node color */ \
|
||||
}
|
||||
|
||||
#define RB_LEFT(elm, field) (elm)->field.rbe_left
|
||||
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
|
||||
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
|
||||
#define RB_COLOR(elm, field) (elm)->field.rbe_color
|
||||
#define RB_ROOT(head) (head)->rbh_root
|
||||
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
|
||||
|
||||
#define RB_SET(elm, parent, field) do { \
|
||||
RB_PARENT(elm, field) = parent; \
|
||||
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
|
||||
RB_COLOR(elm, field) = RB_RED; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define RB_SET_BLACKRED(black, red, field) do { \
|
||||
RB_COLOR(black, field) = RB_BLACK; \
|
||||
RB_COLOR(red, field) = RB_RED; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#ifndef RB_AUGMENT
|
||||
#define RB_AUGMENT(x) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
|
||||
(tmp) = RB_RIGHT(elm, field); \
|
||||
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
|
||||
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
|
||||
} \
|
||||
RB_AUGMENT(elm); \
|
||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
} else \
|
||||
(head)->rbh_root = (tmp); \
|
||||
RB_LEFT(tmp, field) = (elm); \
|
||||
RB_PARENT(elm, field) = (tmp); \
|
||||
RB_AUGMENT(tmp); \
|
||||
if ((RB_PARENT(tmp, field))) \
|
||||
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
|
||||
(tmp) = RB_LEFT(elm, field); \
|
||||
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
|
||||
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
|
||||
} \
|
||||
RB_AUGMENT(elm); \
|
||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
} else \
|
||||
(head)->rbh_root = (tmp); \
|
||||
RB_RIGHT(tmp, field) = (elm); \
|
||||
RB_PARENT(elm, field) = (tmp); \
|
||||
RB_AUGMENT(tmp); \
|
||||
if ((RB_PARENT(tmp, field))) \
|
||||
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
/* Generates prototypes and inline functions */
|
||||
#define RB_PROTOTYPE(name, type, field, cmp) \
|
||||
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
|
||||
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
|
||||
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
|
||||
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
|
||||
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
|
||||
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
|
||||
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_FIND(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_NEXT(struct type *); \
|
||||
attr struct type *name##_RB_PREV(struct type *); \
|
||||
attr struct type *name##_RB_MINMAX(struct name *, int); \
|
||||
\
|
||||
|
||||
/* Main rb operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define RB_GENERATE(name, type, field, cmp) \
|
||||
RB_GENERATE_INTERNAL(name, type, field, cmp,)
|
||||
#define RB_GENERATE_STATIC(name, type, field, cmp) \
|
||||
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
|
||||
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
|
||||
attr void \
|
||||
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *parent, *gparent, *tmp; \
|
||||
while ((parent = RB_PARENT(elm, field)) != NULL && \
|
||||
RB_COLOR(parent, field) == RB_RED) { \
|
||||
gparent = RB_PARENT(parent, field); \
|
||||
if (parent == RB_LEFT(gparent, field)) { \
|
||||
tmp = RB_RIGHT(gparent, field); \
|
||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||
RB_SET_BLACKRED(parent, gparent, field);\
|
||||
elm = gparent; \
|
||||
continue; \
|
||||
} \
|
||||
if (RB_RIGHT(parent, field) == elm) { \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field);\
|
||||
tmp = parent; \
|
||||
parent = elm; \
|
||||
elm = tmp; \
|
||||
} \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
|
||||
} else { \
|
||||
tmp = RB_LEFT(gparent, field); \
|
||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||
RB_SET_BLACKRED(parent, gparent, field);\
|
||||
elm = gparent; \
|
||||
continue; \
|
||||
} \
|
||||
if (RB_LEFT(parent, field) == elm) { \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field);\
|
||||
tmp = parent; \
|
||||
parent = elm; \
|
||||
elm = tmp; \
|
||||
} \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
RB_ROTATE_LEFT(head, gparent, tmp, field); \
|
||||
} \
|
||||
} \
|
||||
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
|
||||
} \
|
||||
\
|
||||
attr void \
|
||||
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp; \
|
||||
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
|
||||
elm != RB_ROOT(head)) { \
|
||||
if (RB_LEFT(parent, field) == elm) { \
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_SET_BLACKRED(tmp, parent, field); \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field);\
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
} \
|
||||
if ((RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
|
||||
(RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
elm = parent; \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
} else { \
|
||||
if (RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
|
||||
struct type *oleft; \
|
||||
if ((oleft = RB_LEFT(tmp, field)) \
|
||||
!= NULL) \
|
||||
RB_COLOR(oleft, field) = RB_BLACK;\
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
} \
|
||||
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
|
||||
RB_COLOR(parent, field) = RB_BLACK; \
|
||||
if (RB_RIGHT(tmp, field)) \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field);\
|
||||
elm = RB_ROOT(head); \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_SET_BLACKRED(tmp, parent, field); \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field);\
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
} \
|
||||
if ((RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
|
||||
(RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
elm = parent; \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
} else { \
|
||||
if (RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
|
||||
struct type *oright; \
|
||||
if ((oright = RB_RIGHT(tmp, field)) \
|
||||
!= NULL) \
|
||||
RB_COLOR(oright, field) = RB_BLACK;\
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
RB_ROTATE_LEFT(head, tmp, oright, field);\
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
} \
|
||||
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
|
||||
RB_COLOR(parent, field) = RB_BLACK; \
|
||||
if (RB_LEFT(tmp, field)) \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field);\
|
||||
elm = RB_ROOT(head); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (elm) \
|
||||
RB_COLOR(elm, field) = RB_BLACK; \
|
||||
} \
|
||||
\
|
||||
attr struct type * \
|
||||
name##_RB_REMOVE(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *child, *parent, *old = elm; \
|
||||
int color; \
|
||||
if (RB_LEFT(elm, field) == NULL) \
|
||||
child = RB_RIGHT(elm, field); \
|
||||
else if (RB_RIGHT(elm, field) == NULL) \
|
||||
child = RB_LEFT(elm, field); \
|
||||
else { \
|
||||
struct type *left; \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
while ((left = RB_LEFT(elm, field)) != NULL) \
|
||||
elm = left; \
|
||||
child = RB_RIGHT(elm, field); \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
color = RB_COLOR(elm, field); \
|
||||
if (child) \
|
||||
RB_PARENT(child, field) = parent; \
|
||||
if (parent) { \
|
||||
if (RB_LEFT(parent, field) == elm) \
|
||||
RB_LEFT(parent, field) = child; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = child; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = child; \
|
||||
if (RB_PARENT(elm, field) == old) \
|
||||
parent = elm; \
|
||||
(elm)->field = (old)->field; \
|
||||
if (RB_PARENT(old, field)) { \
|
||||
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
|
||||
RB_LEFT(RB_PARENT(old, field), field) = elm;\
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
|
||||
RB_AUGMENT(RB_PARENT(old, field)); \
|
||||
} else \
|
||||
RB_ROOT(head) = elm; \
|
||||
RB_PARENT(RB_LEFT(old, field), field) = elm; \
|
||||
if (RB_RIGHT(old, field)) \
|
||||
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
|
||||
if (parent) { \
|
||||
left = parent; \
|
||||
do { \
|
||||
RB_AUGMENT(left); \
|
||||
} while ((left = RB_PARENT(left, field)) != NULL); \
|
||||
} \
|
||||
goto color; \
|
||||
} \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
color = RB_COLOR(elm, field); \
|
||||
if (child) \
|
||||
RB_PARENT(child, field) = parent; \
|
||||
if (parent) { \
|
||||
if (RB_LEFT(parent, field) == elm) \
|
||||
RB_LEFT(parent, field) = child; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = child; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = child; \
|
||||
color: \
|
||||
if (color == RB_BLACK) \
|
||||
name##_RB_REMOVE_COLOR(head, parent, child); \
|
||||
return (old); \
|
||||
} \
|
||||
\
|
||||
/* Inserts a node into the RB tree */ \
|
||||
attr struct type * \
|
||||
name##_RB_INSERT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp; \
|
||||
struct type *parent = NULL; \
|
||||
int comp = 0; \
|
||||
tmp = RB_ROOT(head); \
|
||||
while (tmp) { \
|
||||
parent = tmp; \
|
||||
comp = (cmp)(elm, parent); \
|
||||
if (comp < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
RB_SET(elm, parent, field); \
|
||||
if (parent != NULL) { \
|
||||
if (comp < 0) \
|
||||
RB_LEFT(parent, field) = elm; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = elm; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = elm; \
|
||||
name##_RB_INSERT_COLOR(head, elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
attr struct type * \
|
||||
name##_RB_FIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
int comp; \
|
||||
while (tmp) { \
|
||||
comp = cmp(elm, tmp); \
|
||||
if (comp < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
/* Finds the first node greater than or equal to the search key */ \
|
||||
attr struct type * \
|
||||
name##_RB_NFIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
struct type *res = NULL; \
|
||||
int comp; \
|
||||
while (tmp) { \
|
||||
comp = cmp(elm, tmp); \
|
||||
if (comp < 0) { \
|
||||
res = tmp; \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
} \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
return (res); \
|
||||
} \
|
||||
\
|
||||
/* ARGSUSED */ \
|
||||
attr struct type * \
|
||||
name##_RB_NEXT(struct type *elm) \
|
||||
{ \
|
||||
if (RB_RIGHT(elm, field)) { \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
while (RB_LEFT(elm, field)) \
|
||||
elm = RB_LEFT(elm, field); \
|
||||
} else { \
|
||||
if (RB_PARENT(elm, field) && \
|
||||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
else { \
|
||||
while (RB_PARENT(elm, field) && \
|
||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
|
||||
elm = RB_PARENT(elm, field); \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
} \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
/* ARGSUSED */ \
|
||||
attr struct type * \
|
||||
name##_RB_PREV(struct type *elm) \
|
||||
{ \
|
||||
if (RB_LEFT(elm, field)) { \
|
||||
elm = RB_LEFT(elm, field); \
|
||||
while (RB_RIGHT(elm, field)) \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
} else { \
|
||||
if (RB_PARENT(elm, field) && \
|
||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
else { \
|
||||
while (RB_PARENT(elm, field) && \
|
||||
(elm == RB_LEFT(RB_PARENT(elm, field), field)))\
|
||||
elm = RB_PARENT(elm, field); \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
} \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
attr struct type * \
|
||||
name##_RB_MINMAX(struct name *head, int val) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
struct type *parent = NULL; \
|
||||
while (tmp) { \
|
||||
parent = tmp; \
|
||||
if (val < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
} \
|
||||
return (parent); \
|
||||
}
|
||||
|
||||
#define RB_NEGINF -1
|
||||
#define RB_INF 1
|
||||
|
||||
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
|
||||
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
|
||||
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
|
||||
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
|
||||
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
|
||||
#define RB_PREV(name, x, y) name##_RB_PREV(y)
|
||||
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
|
||||
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
|
||||
|
||||
#define RB_FOREACH(x, name, head) \
|
||||
for ((x) = RB_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = name##_RB_NEXT(x))
|
||||
|
||||
#define RB_FOREACH_FROM(x, name, y) \
|
||||
for ((x) = (y); \
|
||||
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_SAFE(x, name, head, y) \
|
||||
for ((x) = RB_MIN(name, head); \
|
||||
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_REVERSE(x, name, head) \
|
||||
for ((x) = RB_MAX(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = name##_RB_PREV(x))
|
||||
|
||||
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
|
||||
for ((x) = (y); \
|
||||
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
|
||||
for ((x) = RB_MAX(name, head); \
|
||||
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#endif
|
663
native/src/external/libxhook/xh_core.c
vendored
663
native/src/external/libxhook/xh_core.c
vendored
@ -1,663 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <regex.h>
|
||||
#include <setjmp.h>
|
||||
#include <errno.h>
|
||||
#include "queue.h"
|
||||
#include "tree.h"
|
||||
#include "xh_errno.h"
|
||||
#include "xh_log.h"
|
||||
#include "xh_elf.h"
|
||||
#include "xh_version.h"
|
||||
#include "xh_core.h"
|
||||
|
||||
#define XH_CORE_DEBUG 0
|
||||
|
||||
//registered hook info collection
|
||||
typedef struct xh_core_hook_info
|
||||
{
|
||||
#if XH_CORE_DEBUG
|
||||
char *pathname_regex_str;
|
||||
#endif
|
||||
regex_t pathname_regex;
|
||||
char *symbol;
|
||||
void *new_func;
|
||||
void **old_func;
|
||||
TAILQ_ENTRY(xh_core_hook_info,) link;
|
||||
} xh_core_hook_info_t;
|
||||
typedef TAILQ_HEAD(xh_core_hook_info_queue, xh_core_hook_info,) xh_core_hook_info_queue_t;
|
||||
|
||||
//ignored hook info collection
|
||||
typedef struct xh_core_ignore_info
|
||||
{
|
||||
#if XH_CORE_DEBUG
|
||||
char *pathname_regex_str;
|
||||
#endif
|
||||
regex_t pathname_regex;
|
||||
char *symbol; //NULL meaning for all symbols
|
||||
TAILQ_ENTRY(xh_core_ignore_info,) link;
|
||||
} xh_core_ignore_info_t;
|
||||
typedef TAILQ_HEAD(xh_core_ignore_info_queue, xh_core_ignore_info,) xh_core_ignore_info_queue_t;
|
||||
|
||||
//required info from /proc/self/maps
|
||||
typedef struct xh_core_map_info
|
||||
{
|
||||
char *pathname;
|
||||
unsigned long inode;
|
||||
uintptr_t base_addr;
|
||||
xh_elf_t elf;
|
||||
RB_ENTRY(xh_core_map_info) link;
|
||||
} xh_core_map_info_t;
|
||||
static __inline__ int xh_core_map_info_cmp(xh_core_map_info_t *a, xh_core_map_info_t *b)
|
||||
{
|
||||
int path_cmp = strcmp(a->pathname, b->pathname);
|
||||
if (path_cmp == 0) {
|
||||
return a->inode - b->inode;
|
||||
} else {
|
||||
return path_cmp;
|
||||
}
|
||||
}
|
||||
typedef RB_HEAD(xh_core_map_info_tree, xh_core_map_info) xh_core_map_info_tree_t;
|
||||
RB_GENERATE_STATIC(xh_core_map_info_tree, xh_core_map_info, link, xh_core_map_info_cmp)
|
||||
|
||||
//signal handler for SIGSEGV
|
||||
//for xh_elf_init(), xh_elf_hook(), xh_elf_check_elfheader()
|
||||
static int xh_core_sigsegv_enable = 1; //enable by default
|
||||
static struct sigaction xh_core_sigsegv_act_old;
|
||||
static volatile int xh_core_sigsegv_flag = 0;
|
||||
static sigjmp_buf xh_core_sigsegv_env;
|
||||
static void xh_core_sigsegv_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
|
||||
if(xh_core_sigsegv_flag)
|
||||
siglongjmp(xh_core_sigsegv_env, 1);
|
||||
else
|
||||
sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL);
|
||||
}
|
||||
static int xh_core_add_sigsegv_handler()
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
if(!xh_core_sigsegv_enable) return 0;
|
||||
|
||||
if(0 != sigemptyset(&act.sa_mask)) return (0 == errno ? XH_ERRNO_UNKNOWN : errno);
|
||||
act.sa_handler = xh_core_sigsegv_handler;
|
||||
|
||||
if(0 != sigaction(SIGSEGV, &act, &xh_core_sigsegv_act_old))
|
||||
return (0 == errno ? XH_ERRNO_UNKNOWN : errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void xh_core_del_sigsegv_handler()
|
||||
{
|
||||
if(!xh_core_sigsegv_enable) return;
|
||||
|
||||
sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL);
|
||||
}
|
||||
|
||||
|
||||
static xh_core_hook_info_queue_t xh_core_hook_info = TAILQ_HEAD_INITIALIZER(xh_core_hook_info);
|
||||
static xh_core_ignore_info_queue_t xh_core_ignore_info = TAILQ_HEAD_INITIALIZER(xh_core_ignore_info);
|
||||
static xh_core_map_info_tree_t xh_core_map_info = RB_INITIALIZER(&xh_core_map_info);
|
||||
static pthread_mutex_t xh_core_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t xh_core_cond = PTHREAD_COND_INITIALIZER;
|
||||
static volatile int xh_core_inited = 0;
|
||||
static volatile int xh_core_init_ok = 0;
|
||||
static volatile int xh_core_async_inited = 0;
|
||||
static volatile int xh_core_async_init_ok = 0;
|
||||
static pthread_mutex_t xh_core_refresh_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_t xh_core_refresh_thread_tid;
|
||||
static volatile int xh_core_refresh_thread_running = 0;
|
||||
static volatile int xh_core_refresh_thread_do = 0;
|
||||
|
||||
|
||||
int xh_core_register(const char *pathname_regex_str, const char *symbol,
|
||||
void *new_func, void **old_func)
|
||||
{
|
||||
xh_core_hook_info_t *hi;
|
||||
regex_t regex;
|
||||
|
||||
if(NULL == pathname_regex_str || NULL == symbol || NULL == new_func) return XH_ERRNO_INVAL;
|
||||
|
||||
if(xh_core_inited)
|
||||
{
|
||||
XH_LOG_ERROR("do not register hook after refresh(): %s, %s", pathname_regex_str, symbol);
|
||||
return XH_ERRNO_INVAL;
|
||||
}
|
||||
|
||||
if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL;
|
||||
|
||||
if(NULL == (hi = malloc(sizeof(xh_core_hook_info_t)))) return XH_ERRNO_NOMEM;
|
||||
if(NULL == (hi->symbol = strdup(symbol)))
|
||||
{
|
||||
free(hi);
|
||||
return XH_ERRNO_NOMEM;
|
||||
}
|
||||
#if XH_CORE_DEBUG
|
||||
if(NULL == (hi->pathname_regex_str = strdup(pathname_regex_str)))
|
||||
{
|
||||
free(hi->symbol);
|
||||
free(hi);
|
||||
return XH_ERRNO_NOMEM;
|
||||
}
|
||||
#endif
|
||||
hi->pathname_regex = regex;
|
||||
hi->new_func = new_func;
|
||||
hi->old_func = old_func;
|
||||
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
TAILQ_INSERT_TAIL(&xh_core_hook_info, hi, link);
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xh_core_ignore(const char *pathname_regex_str, const char *symbol)
|
||||
{
|
||||
xh_core_ignore_info_t *ii;
|
||||
regex_t regex;
|
||||
|
||||
if(NULL == pathname_regex_str) return XH_ERRNO_INVAL;
|
||||
|
||||
if(xh_core_inited)
|
||||
{
|
||||
XH_LOG_ERROR("do not ignore hook after refresh(): %s, %s", pathname_regex_str, symbol ? symbol : "ALL");
|
||||
return XH_ERRNO_INVAL;
|
||||
}
|
||||
|
||||
if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL;
|
||||
|
||||
if(NULL == (ii = malloc(sizeof(xh_core_ignore_info_t)))) return XH_ERRNO_NOMEM;
|
||||
if(NULL != symbol)
|
||||
{
|
||||
if(NULL == (ii->symbol = strdup(symbol)))
|
||||
{
|
||||
free(ii);
|
||||
return XH_ERRNO_NOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ii->symbol = NULL; //ignore all symbols
|
||||
}
|
||||
#if XH_CORE_DEBUG
|
||||
if(NULL == (ii->pathname_regex_str = strdup(pathname_regex_str)))
|
||||
{
|
||||
free(ii->symbol);
|
||||
free(ii);
|
||||
return XH_ERRNO_NOMEM;
|
||||
}
|
||||
#endif
|
||||
ii->pathname_regex = regex;
|
||||
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
TAILQ_INSERT_TAIL(&xh_core_ignore_info, ii, link);
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xh_core_check_elf_header(uintptr_t base_addr, const char *pathname)
|
||||
{
|
||||
if(!xh_core_sigsegv_enable)
|
||||
{
|
||||
return xh_elf_check_elfheader(base_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret = XH_ERRNO_UNKNOWN;
|
||||
|
||||
xh_core_sigsegv_flag = 1;
|
||||
if(0 == sigsetjmp(xh_core_sigsegv_env, 1))
|
||||
{
|
||||
ret = xh_elf_check_elfheader(base_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = XH_ERRNO_SEGVERR;
|
||||
XH_LOG_WARN("catch SIGSEGV when check_elfheader: %s", pathname);
|
||||
}
|
||||
xh_core_sigsegv_flag = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static void xh_core_hook_impl(xh_core_map_info_t *mi)
|
||||
{
|
||||
//init
|
||||
if(0 != xh_elf_init(&(mi->elf), mi->base_addr, mi->pathname)) return;
|
||||
|
||||
//hook
|
||||
xh_core_hook_info_t *hi;
|
||||
xh_core_ignore_info_t *ii;
|
||||
int ignore;
|
||||
TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info
|
||||
{
|
||||
if(0 == regexec(&(hi->pathname_regex), mi->pathname, 0, NULL, 0))
|
||||
{
|
||||
ignore = 0;
|
||||
TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info
|
||||
{
|
||||
if(0 == regexec(&(ii->pathname_regex), mi->pathname, 0, NULL, 0))
|
||||
{
|
||||
if(NULL == ii->symbol) //ignore all symbols
|
||||
return;
|
||||
|
||||
if(0 == strcmp(ii->symbol, hi->symbol)) //ignore the current symbol
|
||||
{
|
||||
ignore = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(0 == ignore)
|
||||
xh_elf_hook(&(mi->elf), hi->symbol, hi->new_func, hi->old_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xh_core_hook(xh_core_map_info_t *mi)
|
||||
{
|
||||
if(!xh_core_sigsegv_enable)
|
||||
{
|
||||
xh_core_hook_impl(mi);
|
||||
}
|
||||
else
|
||||
{
|
||||
xh_core_sigsegv_flag = 1;
|
||||
if(0 == sigsetjmp(xh_core_sigsegv_env, 1))
|
||||
{
|
||||
xh_core_hook_impl(mi);
|
||||
}
|
||||
else
|
||||
{
|
||||
XH_LOG_WARN("catch SIGSEGV when init or hook: %s %lu", mi->pathname, mi->inode);
|
||||
}
|
||||
xh_core_sigsegv_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void xh_core_refresh_impl()
|
||||
{
|
||||
char line[512];
|
||||
FILE *fp;
|
||||
uintptr_t base_addr;
|
||||
char perm[5];
|
||||
unsigned long offset;
|
||||
unsigned long inode;
|
||||
int pathname_pos;
|
||||
char *pathname;
|
||||
size_t pathname_len;
|
||||
xh_core_map_info_t *mi, *mi_tmp;
|
||||
xh_core_map_info_t mi_key;
|
||||
xh_core_hook_info_t *hi;
|
||||
xh_core_ignore_info_t *ii;
|
||||
int match;
|
||||
xh_core_map_info_tree_t map_info_refreshed = RB_INITIALIZER(&map_info_refreshed);
|
||||
|
||||
if(NULL == (fp = fopen("/proc/self/maps", "r")))
|
||||
{
|
||||
XH_LOG_ERROR("fopen /proc/self/maps failed");
|
||||
return;
|
||||
}
|
||||
|
||||
while(fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if(sscanf(line, "%"PRIxPTR"-%*lx %4s %lx %*x:%*x %lu %n", &base_addr, perm, &offset, &inode, &pathname_pos) != 4) continue;
|
||||
|
||||
//check permission
|
||||
if(perm[0] != 'r') continue;
|
||||
if(perm[3] != 'p') continue; //do not touch the shared memory
|
||||
|
||||
//check offset
|
||||
//
|
||||
//We are trying to find ELF header in memory.
|
||||
//It can only be found at the beginning of a mapped memory regions
|
||||
//whose offset is 0.
|
||||
if(0 != offset) continue;
|
||||
|
||||
//get pathname
|
||||
while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
|
||||
pathname_pos += 1;
|
||||
if(pathname_pos >= (int)(sizeof(line) - 1)) continue;
|
||||
pathname = line + pathname_pos;
|
||||
pathname_len = strlen(pathname);
|
||||
if(0 == pathname_len) continue;
|
||||
if(pathname[pathname_len - 1] == '\n')
|
||||
{
|
||||
pathname[pathname_len - 1] = '\0';
|
||||
pathname_len -= 1;
|
||||
}
|
||||
if(0 == pathname_len) continue;
|
||||
if('[' == pathname[0]) continue;
|
||||
|
||||
//check pathname
|
||||
//if we need to hook this elf?
|
||||
match = 0;
|
||||
TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info
|
||||
{
|
||||
if(0 == regexec(&(hi->pathname_regex), pathname, 0, NULL, 0))
|
||||
{
|
||||
TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info
|
||||
{
|
||||
if(0 == regexec(&(ii->pathname_regex), pathname, 0, NULL, 0))
|
||||
{
|
||||
if(NULL == ii->symbol)
|
||||
goto check_finished;
|
||||
|
||||
if(0 == strcmp(ii->symbol, hi->symbol))
|
||||
goto check_continue;
|
||||
}
|
||||
}
|
||||
|
||||
match = 1;
|
||||
check_continue:
|
||||
break;
|
||||
}
|
||||
}
|
||||
check_finished:
|
||||
if(0 == match) continue;
|
||||
|
||||
//check elf header format
|
||||
//We are trying to do ELF header checking as late as possible.
|
||||
if(0 != xh_core_check_elf_header(base_addr, pathname)) continue;
|
||||
|
||||
//check existed map item
|
||||
mi_key.pathname = pathname;
|
||||
mi_key.inode = inode;
|
||||
if(NULL != (mi = RB_FIND(xh_core_map_info_tree, &xh_core_map_info, &mi_key)))
|
||||
{
|
||||
//exist
|
||||
RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi);
|
||||
|
||||
//repeated?
|
||||
//We only keep the first one, that is the real base address
|
||||
if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi))
|
||||
{
|
||||
#if XH_CORE_DEBUG
|
||||
XH_LOG_DEBUG("repeated map info when update: %s", line);
|
||||
#endif
|
||||
free(mi->pathname);
|
||||
free(mi);
|
||||
continue;
|
||||
}
|
||||
|
||||
//re-hook if base_addr changed
|
||||
if(mi->base_addr != base_addr)
|
||||
{
|
||||
mi->base_addr = base_addr;
|
||||
xh_core_hook(mi);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//not exist, create a new map info
|
||||
if(NULL == (mi = (xh_core_map_info_t *)malloc(sizeof(xh_core_map_info_t)))) continue;
|
||||
if(NULL == (mi->pathname = strdup(pathname)))
|
||||
{
|
||||
free(mi);
|
||||
continue;
|
||||
}
|
||||
mi->inode = inode;
|
||||
mi->base_addr = base_addr;
|
||||
|
||||
//repeated?
|
||||
//We only keep the first one, that is the real base address
|
||||
if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi))
|
||||
{
|
||||
XH_LOG_WARN("repeated map info when create: %s", line);
|
||||
free(mi->pathname);
|
||||
free(mi);
|
||||
continue;
|
||||
}
|
||||
|
||||
//hook
|
||||
xh_core_hook(mi); //hook
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
//free all missing map item, maybe dlclosed?
|
||||
RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp)
|
||||
{
|
||||
#if XH_CORE_DEBUG
|
||||
XH_LOG_DEBUG("remove missing map info: %s", mi->pathname);
|
||||
#endif
|
||||
RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi);
|
||||
if(mi->pathname) free(mi->pathname);
|
||||
free(mi);
|
||||
}
|
||||
|
||||
//save the new refreshed map info tree
|
||||
xh_core_map_info = map_info_refreshed;
|
||||
|
||||
XH_LOG_INFO("map refreshed");
|
||||
|
||||
#if XH_CORE_DEBUG
|
||||
RB_FOREACH(mi, xh_core_map_info_tree, &xh_core_map_info)
|
||||
XH_LOG_DEBUG(" %"PRIxPTR" %s\n", mi->base_addr, mi->pathname);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *xh_core_refresh_thread_func(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
pthread_setname_np(pthread_self(), "xh_refresh_loop");
|
||||
|
||||
while(xh_core_refresh_thread_running)
|
||||
{
|
||||
//waiting for a refresh task or exit
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
while(!xh_core_refresh_thread_do && xh_core_refresh_thread_running)
|
||||
{
|
||||
pthread_cond_wait(&xh_core_cond, &xh_core_mutex);
|
||||
}
|
||||
if(!xh_core_refresh_thread_running)
|
||||
{
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
break;
|
||||
}
|
||||
xh_core_refresh_thread_do = 0;
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
|
||||
//refresh
|
||||
pthread_mutex_lock(&xh_core_refresh_mutex);
|
||||
xh_core_refresh_impl();
|
||||
pthread_mutex_unlock(&xh_core_refresh_mutex);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void xh_core_init_once()
|
||||
{
|
||||
if(xh_core_inited) return;
|
||||
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
|
||||
if(xh_core_inited) goto end;
|
||||
|
||||
xh_core_inited = 1;
|
||||
|
||||
//dump debug info
|
||||
XH_LOG_INFO("%s\n", xh_version_str_full());
|
||||
#if XH_CORE_DEBUG
|
||||
xh_core_hook_info_t *hi;
|
||||
TAILQ_FOREACH(hi, &xh_core_hook_info, link)
|
||||
XH_LOG_INFO(" hook: %s @ %s, (%p, %p)\n", hi->symbol, hi->pathname_regex_str,
|
||||
hi->new_func, hi->old_func);
|
||||
xh_core_ignore_info_t *ii;
|
||||
TAILQ_FOREACH(ii, &xh_core_ignore_info, link)
|
||||
XH_LOG_INFO(" ignore: %s @ %s\n", ii->symbol ? ii->symbol : "ALL ",
|
||||
ii->pathname_regex_str);
|
||||
#endif
|
||||
|
||||
//register signal handler
|
||||
if(0 != xh_core_add_sigsegv_handler()) goto end;
|
||||
|
||||
//OK
|
||||
xh_core_init_ok = 1;
|
||||
|
||||
end:
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
}
|
||||
|
||||
static void xh_core_init_async_once()
|
||||
{
|
||||
if(xh_core_async_inited) return;
|
||||
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
|
||||
if(xh_core_async_inited) goto end;
|
||||
|
||||
xh_core_async_inited = 1;
|
||||
|
||||
//create async refresh thread
|
||||
xh_core_refresh_thread_running = 1;
|
||||
if(0 != pthread_create(&xh_core_refresh_thread_tid, NULL, &xh_core_refresh_thread_func, NULL))
|
||||
{
|
||||
xh_core_refresh_thread_running = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
//OK
|
||||
xh_core_async_init_ok = 1;
|
||||
|
||||
end:
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
}
|
||||
|
||||
int xh_core_refresh(int async)
|
||||
{
|
||||
//init
|
||||
xh_core_init_once();
|
||||
if(!xh_core_init_ok) return XH_ERRNO_UNKNOWN;
|
||||
|
||||
if(async)
|
||||
{
|
||||
//init for async
|
||||
xh_core_init_async_once();
|
||||
if(!xh_core_async_init_ok) return XH_ERRNO_UNKNOWN;
|
||||
|
||||
//refresh async
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
xh_core_refresh_thread_do = 1;
|
||||
pthread_cond_signal(&xh_core_cond);
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
//refresh sync
|
||||
pthread_mutex_lock(&xh_core_refresh_mutex);
|
||||
xh_core_refresh_impl();
|
||||
pthread_mutex_unlock(&xh_core_refresh_mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xh_core_clear()
|
||||
{
|
||||
//stop the async refresh thread
|
||||
if(xh_core_async_init_ok)
|
||||
{
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
xh_core_refresh_thread_running = 0;
|
||||
pthread_cond_signal(&xh_core_cond);
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
|
||||
pthread_join(xh_core_refresh_thread_tid, NULL);
|
||||
xh_core_async_init_ok = 0;
|
||||
}
|
||||
xh_core_async_inited = 0;
|
||||
|
||||
//unregister the sig handler
|
||||
if(xh_core_init_ok)
|
||||
{
|
||||
xh_core_del_sigsegv_handler();
|
||||
xh_core_init_ok = 0;
|
||||
}
|
||||
xh_core_inited = 0;
|
||||
|
||||
pthread_mutex_lock(&xh_core_mutex);
|
||||
pthread_mutex_lock(&xh_core_refresh_mutex);
|
||||
|
||||
//free all map info
|
||||
xh_core_map_info_t *mi, *mi_tmp;
|
||||
RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp)
|
||||
{
|
||||
RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi);
|
||||
if(mi->pathname) free(mi->pathname);
|
||||
free(mi);
|
||||
}
|
||||
|
||||
//free all hook info
|
||||
xh_core_hook_info_t *hi, *hi_tmp;
|
||||
TAILQ_FOREACH_SAFE(hi, &xh_core_hook_info, link, hi_tmp)
|
||||
{
|
||||
TAILQ_REMOVE(&xh_core_hook_info, hi, link);
|
||||
#if XH_CORE_DEBUG
|
||||
free(hi->pathname_regex_str);
|
||||
#endif
|
||||
regfree(&(hi->pathname_regex));
|
||||
free(hi->symbol);
|
||||
free(hi);
|
||||
}
|
||||
|
||||
//free all ignore info
|
||||
xh_core_ignore_info_t *ii, *ii_tmp;
|
||||
TAILQ_FOREACH_SAFE(ii, &xh_core_ignore_info, link, ii_tmp)
|
||||
{
|
||||
TAILQ_REMOVE(&xh_core_ignore_info, ii, link);
|
||||
#if XH_CORE_DEBUG
|
||||
free(ii->pathname_regex_str);
|
||||
#endif
|
||||
regfree(&(ii->pathname_regex));
|
||||
free(ii->symbol);
|
||||
free(ii);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&xh_core_refresh_mutex);
|
||||
pthread_mutex_unlock(&xh_core_mutex);
|
||||
}
|
||||
|
||||
void xh_core_enable_debug(int flag)
|
||||
{
|
||||
xh_log_priority = (flag ? ANDROID_LOG_DEBUG : ANDROID_LOG_WARN);
|
||||
}
|
||||
|
||||
void xh_core_enable_sigsegv_protection(int flag)
|
||||
{
|
||||
xh_core_sigsegv_enable = (flag ? 1 : 0);
|
||||
}
|
48
native/src/external/libxhook/xh_core.h
vendored
48
native/src/external/libxhook/xh_core.h
vendored
@ -1,48 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#ifndef XH_CORE_H
|
||||
#define XH_CORE_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int xh_core_register(const char *pathname_regex_str, const char *symbol,
|
||||
void *new_func, void **old_func);
|
||||
|
||||
int xh_core_ignore(const char *pathname_regex_str, const char *symbol);
|
||||
|
||||
int xh_core_refresh(int async);
|
||||
|
||||
void xh_core_clear();
|
||||
|
||||
void xh_core_enable_debug(int flag);
|
||||
|
||||
void xh_core_enable_sigsegv_protection(int flag);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1046
native/src/external/libxhook/xh_elf.c
vendored
1046
native/src/external/libxhook/xh_elf.c
vendored
File diff suppressed because it is too large
Load Diff
85
native/src/external/libxhook/xh_elf.h
vendored
85
native/src/external/libxhook/xh_elf.h
vendored
@ -1,85 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#ifndef XH_ELF_H
|
||||
#define XH_ELF_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *pathname;
|
||||
|
||||
ElfW(Addr) base_addr;
|
||||
ElfW(Addr) bias_addr;
|
||||
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Phdr) *phdr;
|
||||
|
||||
ElfW(Dyn) *dyn; //.dynamic
|
||||
ElfW(Word) dyn_sz;
|
||||
|
||||
const char *strtab; //.dynstr (string-table)
|
||||
ElfW(Sym) *symtab; //.dynsym (symbol-index to string-table's offset)
|
||||
|
||||
ElfW(Addr) relplt; //.rel.plt or .rela.plt
|
||||
ElfW(Word) relplt_sz;
|
||||
|
||||
ElfW(Addr) reldyn; //.rel.dyn or .rela.dyn
|
||||
ElfW(Word) reldyn_sz;
|
||||
|
||||
ElfW(Addr) relandroid; //android compressed rel or rela
|
||||
ElfW(Word) relandroid_sz;
|
||||
|
||||
//for ELF hash
|
||||
uint32_t *bucket;
|
||||
uint32_t bucket_cnt;
|
||||
uint32_t *chain;
|
||||
uint32_t chain_cnt; //invalid for GNU hash
|
||||
|
||||
//append for GNU hash
|
||||
uint32_t symoffset;
|
||||
ElfW(Addr) *bloom;
|
||||
uint32_t bloom_sz;
|
||||
uint32_t bloom_shift;
|
||||
|
||||
int is_use_rela;
|
||||
int is_use_gnu_hash;
|
||||
} xh_elf_t;
|
||||
|
||||
int xh_elf_init(xh_elf_t *self, uintptr_t base_addr, const char *pathname);
|
||||
int xh_elf_hook(xh_elf_t *self, const char *symbol, void *new_func, void **old_func);
|
||||
|
||||
int xh_elf_check_elfheader(uintptr_t base_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
37
native/src/external/libxhook/xh_errno.h
vendored
37
native/src/external/libxhook/xh_errno.h
vendored
@ -1,37 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#ifndef XH_ERRNO_H
|
||||
#define XH_ERRNO_H 1
|
||||
|
||||
#define XH_ERRNO_UNKNOWN 1001
|
||||
#define XH_ERRNO_INVAL 1002
|
||||
#define XH_ERRNO_NOMEM 1003
|
||||
#define XH_ERRNO_REPEAT 1004
|
||||
#define XH_ERRNO_NOTFND 1005
|
||||
#define XH_ERRNO_BADMAPS 1006
|
||||
#define XH_ERRNO_FORMAT 1007
|
||||
#define XH_ERRNO_ELFINIT 1008
|
||||
#define XH_ERRNO_SEGVERR 1009
|
||||
|
||||
#endif
|
59
native/src/external/libxhook/xh_jni.c
vendored
59
native/src/external/libxhook/xh_jni.c
vendored
@ -1,59 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#include <jni.h>
|
||||
#include "xhook.h"
|
||||
|
||||
#define JNI_API_DEF(f) Java_com_qiyi_xhook_NativeHandler_##f
|
||||
|
||||
JNIEXPORT jint JNI_API_DEF(refresh)(JNIEnv *env, jobject obj, jboolean async)
|
||||
{
|
||||
(void)env;
|
||||
(void)obj;
|
||||
|
||||
return xhook_refresh(async ? 1 : 0);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNI_API_DEF(clear)(JNIEnv *env, jobject obj)
|
||||
{
|
||||
(void)env;
|
||||
(void)obj;
|
||||
|
||||
xhook_clear();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNI_API_DEF(enableDebug)(JNIEnv *env, jobject obj, jboolean flag)
|
||||
{
|
||||
(void)env;
|
||||
(void)obj;
|
||||
|
||||
xhook_enable_debug(flag ? 1 : 0);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNI_API_DEF(enableSigSegvProtection)(JNIEnv *env, jobject obj, jboolean flag)
|
||||
{
|
||||
(void)env;
|
||||
(void)obj;
|
||||
|
||||
xhook_enable_sigsegv_protection(flag ? 1 : 0);
|
||||
}
|
27
native/src/external/libxhook/xh_log.c
vendored
27
native/src/external/libxhook/xh_log.c
vendored
@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#include <android/log.h>
|
||||
#include "xh_log.h"
|
||||
|
||||
android_LogPriority xh_log_priority = ANDROID_LOG_WARN;
|
45
native/src/external/libxhook/xh_log.h
vendored
45
native/src/external/libxhook/xh_log.h
vendored
@ -1,45 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#ifndef XH_LOG_H
|
||||
#define XH_LOG_H 1
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern android_LogPriority xh_log_priority;
|
||||
|
||||
#define XH_LOG_TAG "xhook"
|
||||
#define XH_LOG_DEBUG(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_DEBUG) __android_log_print(ANDROID_LOG_DEBUG, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
|
||||
#define XH_LOG_INFO(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_INFO) __android_log_print(ANDROID_LOG_INFO, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
|
||||
#define XH_LOG_WARN(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_WARN) __android_log_print(ANDROID_LOG_WARN, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
|
||||
#define XH_LOG_ERROR(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_ERROR) __android_log_print(ANDROID_LOG_ERROR, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
121
native/src/external/libxhook/xh_util.c
vendored
121
native/src/external/libxhook/xh_util.c
vendored
@ -1,121 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
#include "xh_util.h"
|
||||
#include "xh_errno.h"
|
||||
#include "xh_log.h"
|
||||
|
||||
#define PAGE_START(addr) ((addr) & PAGE_MASK)
|
||||
#define PAGE_END(addr) (PAGE_START(addr + sizeof(uintptr_t) - 1) + PAGE_SIZE)
|
||||
#define PAGE_COVER(addr) (PAGE_END(addr) - PAGE_START(addr))
|
||||
|
||||
int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot)
|
||||
{
|
||||
uintptr_t start_addr = addr;
|
||||
uintptr_t end_addr = addr + len;
|
||||
FILE *fp;
|
||||
char line[512];
|
||||
uintptr_t start, end;
|
||||
char perm[5];
|
||||
int load0 = 1;
|
||||
int found_all = 0;
|
||||
|
||||
*prot = 0;
|
||||
|
||||
if(NULL == (fp = fopen("/proc/self/maps", "r"))) return XH_ERRNO_BADMAPS;
|
||||
|
||||
while(fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if(NULL != pathname)
|
||||
if(NULL == strstr(line, pathname)) continue;
|
||||
|
||||
if(sscanf(line, "%"PRIxPTR"-%"PRIxPTR" %4s ", &start, &end, perm) != 3) continue;
|
||||
|
||||
if(perm[3] != 'p') continue;
|
||||
|
||||
if(start_addr >= start && start_addr < end)
|
||||
{
|
||||
if(load0)
|
||||
{
|
||||
//first load segment
|
||||
if(perm[0] == 'r') *prot |= PROT_READ;
|
||||
if(perm[1] == 'w') *prot |= PROT_WRITE;
|
||||
if(perm[2] == 'x') *prot |= PROT_EXEC;
|
||||
load0 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//others
|
||||
if(perm[0] != 'r') *prot &= ~PROT_READ;
|
||||
if(perm[1] != 'w') *prot &= ~PROT_WRITE;
|
||||
if(perm[2] != 'x') *prot &= ~PROT_EXEC;
|
||||
}
|
||||
|
||||
if(end_addr <= end)
|
||||
{
|
||||
found_all = 1;
|
||||
break; //finished
|
||||
}
|
||||
else
|
||||
{
|
||||
start_addr = end; //try to find the next load segment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if(!found_all) return XH_ERRNO_SEGVERR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot)
|
||||
{
|
||||
return xh_util_get_mem_protect(addr, sizeof(addr), pathname, prot);
|
||||
}
|
||||
|
||||
int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot)
|
||||
{
|
||||
if(0 != mprotect((void *)PAGE_START(addr), PAGE_COVER(addr), (int)prot))
|
||||
return 0 == errno ? XH_ERRNO_UNKNOWN : errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xh_util_flush_instruction_cache(uintptr_t addr)
|
||||
{
|
||||
__builtin___clear_cache((void *)PAGE_START(addr), (void *)PAGE_END(addr));
|
||||
}
|
51
native/src/external/libxhook/xh_util.h
vendored
51
native/src/external/libxhook/xh_util.h
vendored
@ -1,51 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#ifndef XH_UTILS_H
|
||||
#define XH_UTILS_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__LP64__)
|
||||
#define XH_UTIL_FMT_LEN "16"
|
||||
#define XH_UTIL_FMT_X "llx"
|
||||
#else
|
||||
#define XH_UTIL_FMT_LEN "8"
|
||||
#define XH_UTIL_FMT_X "x"
|
||||
#endif
|
||||
|
||||
#define XH_UTIL_FMT_FIXED_X XH_UTIL_FMT_LEN XH_UTIL_FMT_X
|
||||
#define XH_UTIL_FMT_FIXED_S XH_UTIL_FMT_LEN "s"
|
||||
|
||||
int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot);
|
||||
int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot);
|
||||
int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot);
|
||||
void xh_util_flush_instruction_cache(uintptr_t addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
66
native/src/external/libxhook/xh_version.c
vendored
66
native/src/external/libxhook/xh_version.c
vendored
@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#include "xh_version.h"
|
||||
|
||||
#define XH_VERSION_MAJOR 1
|
||||
#define XH_VERSION_MINOR 2
|
||||
#define XH_VERSION_EXTRA 0
|
||||
|
||||
#define XH_VERSION ((XH_VERSION_MAJOR << 16) | (XH_VERSION_MINOR << 8) | (XH_VERSION_EXTRA))
|
||||
|
||||
#define XH_VERSION_TO_STR_HELPER(x) #x
|
||||
#define XH_VERSION_TO_STR(x) XH_VERSION_TO_STR_HELPER(x)
|
||||
|
||||
#define XH_VERSION_STR XH_VERSION_TO_STR(XH_VERSION_MAJOR) "." \
|
||||
XH_VERSION_TO_STR(XH_VERSION_MINOR) "." \
|
||||
XH_VERSION_TO_STR(XH_VERSION_EXTRA)
|
||||
|
||||
#if defined(__arm__)
|
||||
#define XH_VERSION_ARCH "arm"
|
||||
#elif defined(__aarch64__)
|
||||
#define XH_VERSION_ARCH "aarch64"
|
||||
#elif defined(__i386__)
|
||||
#define XH_VERSION_ARCH "x86"
|
||||
#elif defined(__x86_64__)
|
||||
#define XH_VERSION_ARCH "x86_64"
|
||||
#else
|
||||
#define XH_VERSION_ARCH "unknown"
|
||||
#endif
|
||||
|
||||
#define XH_VERSION_STR_FULL "libxhook "XH_VERSION_STR" ("XH_VERSION_ARCH")"
|
||||
|
||||
unsigned int xh_version()
|
||||
{
|
||||
return XH_VERSION;
|
||||
}
|
||||
|
||||
const char *xh_version_str()
|
||||
{
|
||||
return XH_VERSION_STR;
|
||||
}
|
||||
|
||||
const char *xh_version_str_full()
|
||||
{
|
||||
return XH_VERSION_STR_FULL;
|
||||
}
|
41
native/src/external/libxhook/xh_version.h
vendored
41
native/src/external/libxhook/xh_version.h
vendored
@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#ifndef XH_VERSION_H
|
||||
#define XH_VERSION_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned int xh_version();
|
||||
|
||||
const char *xh_version_str();
|
||||
|
||||
const char *xh_version_str_full();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
56
native/src/external/libxhook/xhook.c
vendored
56
native/src/external/libxhook/xhook.c
vendored
@ -1,56 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#include "xh_core.h"
|
||||
#include "xhook.h"
|
||||
|
||||
int xhook_register(const char *pathname_regex_str, const char *symbol,
|
||||
void *new_func, void **old_func)
|
||||
{
|
||||
return xh_core_register(pathname_regex_str, symbol, new_func, old_func);
|
||||
}
|
||||
|
||||
int xhook_ignore(const char *pathname_regex_str, const char *symbol)
|
||||
{
|
||||
return xh_core_ignore(pathname_regex_str, symbol);
|
||||
}
|
||||
|
||||
int xhook_refresh(int async)
|
||||
{
|
||||
return xh_core_refresh(async);
|
||||
}
|
||||
|
||||
void xhook_clear()
|
||||
{
|
||||
return xh_core_clear();
|
||||
}
|
||||
|
||||
void xhook_enable_debug(int flag)
|
||||
{
|
||||
return xh_core_enable_debug(flag);
|
||||
}
|
||||
|
||||
void xhook_enable_sigsegv_protection(int flag)
|
||||
{
|
||||
return xh_core_enable_sigsegv_protection(flag);
|
||||
}
|
50
native/src/external/libxhook/xhook.h
vendored
50
native/src/external/libxhook/xhook.h
vendored
@ -1,50 +0,0 @@
|
||||
// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Created by caikelun on 2018-04-11.
|
||||
|
||||
#ifndef XHOOK_H
|
||||
#define XHOOK_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XHOOK_EXPORT __attribute__((visibility("default")))
|
||||
|
||||
int xhook_register(const char *pathname_regex_str, const char *symbol,
|
||||
void *new_func, void **old_func) XHOOK_EXPORT;
|
||||
|
||||
int xhook_ignore(const char *pathname_regex_str, const char *symbol) XHOOK_EXPORT;
|
||||
|
||||
int xhook_refresh(int async) XHOOK_EXPORT;
|
||||
|
||||
void xhook_clear() XHOOK_EXPORT;
|
||||
|
||||
void xhook_enable_debug(int flag) XHOOK_EXPORT;
|
||||
|
||||
void xhook_enable_sigsegv_protection(int flag) XHOOK_EXPORT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1
native/src/external/lsplt
vendored
Submodule
1
native/src/external/lsplt
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d935c30d149f1d5cf934505c37bfdb5f5601572d
|
@ -236,6 +236,14 @@ struct Api {
|
||||
// If `symbol` is nullptr, then all symbols will be excluded.
|
||||
void pltHookExclude(const char *regex, const char *symbol);
|
||||
|
||||
// For ELFs loaded in memory matching `inode`, replace function `symbol` with `newFunc`.
|
||||
// If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`.
|
||||
void pltHookRegisterInode(ino_t inode, const char *symbol, void *newFunc, void **oldFunc);
|
||||
|
||||
// For ELFs loaded in memory matching `inode`, exclude hooks registered for `symbol`.
|
||||
// If `symbol` is nullptr, then all symbols will be excluded.
|
||||
void pltHookExcludeInode(ino_t inode, const char *symbol);
|
||||
|
||||
// Commit all the hooks that was previously registered.
|
||||
// Returns false if an error occurred.
|
||||
bool pltHookCommit();
|
||||
@ -303,6 +311,8 @@ struct api_table {
|
||||
int (*getModuleDir)(void * /* impl */);
|
||||
uint32_t (*getFlags)(void * /* impl */);
|
||||
bool (*exemptFd)(int);
|
||||
void (*pltHookRegisterInode)(ino_t, const char *, void *, void **);
|
||||
void (*pltHookExcludeInode)(ino_t, const char *);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@ -332,6 +342,12 @@ inline uint32_t Api::getFlags() {
|
||||
inline bool Api::exemptFd(int fd) {
|
||||
return tbl->exemptFd != nullptr && tbl->exemptFd(fd);
|
||||
}
|
||||
inline void Api::pltHookRegisterInode(ino_t inode, const char *symbol, void *newFunc, void **oldFunc) {
|
||||
if (tbl->pltHookExcludeInode) tbl->pltHookRegisterInode(inode, symbol, newFunc, oldFunc);
|
||||
}
|
||||
inline void Api::pltHookExcludeInode(ino_t inode, const char *symbol) {
|
||||
if (tbl->pltHookExcludeInode) tbl->pltHookExcludeInode(inode, symbol);
|
||||
}
|
||||
inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
|
||||
if (tbl->hookJniNativeMethods) tbl->hookJniNativeMethods(env, className, methods, numMethods);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <bitset>
|
||||
#include <list>
|
||||
|
||||
#include <xhook.h>
|
||||
#include <lsplt.hpp>
|
||||
|
||||
#include <base.hpp>
|
||||
#include <flags.h>
|
||||
@ -22,7 +22,7 @@ using xstring = jni_hook::string;
|
||||
|
||||
// Extreme verbose logging
|
||||
//#define ZLOGV(...) ZLOGD(__VA_ARGS__)
|
||||
#define ZLOGV(...)
|
||||
#define ZLOGV(...) (void*)0
|
||||
|
||||
static bool unhook_functions();
|
||||
|
||||
@ -81,7 +81,7 @@ struct HookContext {
|
||||
#undef DCL_PRE_POST
|
||||
|
||||
// Global variables
|
||||
vector<tuple<const char *, const char *, void **>> *xhook_list;
|
||||
vector<tuple<ino_t, const char *, void **>> *xhook_list;
|
||||
map<string, vector<JNINativeMethod>, StringCmp> *jni_hook_list;
|
||||
hash_map<xstring, tree_map<xstring, tree_map<xstring, void *>>> *jni_method_map;
|
||||
|
||||
@ -328,25 +328,19 @@ bool ZygiskModule::RegisterModuleImpl(ApiTable *api, long *module) {
|
||||
switch (api_version) {
|
||||
case 4:
|
||||
api->v4.exemptFd = [](int fd) { return g_ctx != nullptr && g_ctx->exempt_fd(fd); };
|
||||
// fallthrough
|
||||
api->v4.pltHookRegisterInode = PltHookRegister;
|
||||
api->v4.pltHookExcludeInode = PltHookExclude;
|
||||
[[fallthrough]];
|
||||
case 3:
|
||||
case 2:
|
||||
api->v2.getModuleDir = [](ZygiskModule *m) { return m->getModuleDir(); };
|
||||
api->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); };
|
||||
// fallthrough
|
||||
[[fallthrough]];
|
||||
case 1:
|
||||
api->v1.hookJniNativeMethods = &hookJniNativeMethods;
|
||||
api->v1.pltHookRegister = [](const char *p, const char *s, void *n, void **o) {
|
||||
xhook_register(p, s, n, o);
|
||||
};
|
||||
api->v1.pltHookExclude = [](const char *p, const char *s) {
|
||||
xhook_ignore(p, s);
|
||||
};
|
||||
api->v1.pltHookCommit = [] {
|
||||
bool r = xhook_refresh(0) == 0;
|
||||
xhook_clear();
|
||||
return r;
|
||||
};
|
||||
api->v1.hookJniNativeMethods = hookJniNativeMethods;
|
||||
api->v1.pltHookRegister = PltHookRegister;
|
||||
api->v1.pltHookExclude = PltHookExclude;
|
||||
api->v1.pltHookCommit = CommitPltHook;
|
||||
api->v1.connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); };
|
||||
api->v1.setOption = [](ZygiskModule *m, auto opt) { m->setOption(opt); };
|
||||
break;
|
||||
@ -358,16 +352,74 @@ bool ZygiskModule::RegisterModuleImpl(ApiTable *api, long *module) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZygiskModule::PltHookRegister(const char* regex, const char *symbol, void *callback, void **backup) {
|
||||
if (regex == nullptr || symbol == nullptr || callback == nullptr)
|
||||
return;
|
||||
regex_t re;
|
||||
if (regcomp(&re, regex, REG_NOSUB) != 0)
|
||||
return;
|
||||
mutex_guard lock(hook_lock);
|
||||
register_info.emplace_back(RegisterInfo{re, 0, symbol, callback, backup});
|
||||
}
|
||||
|
||||
void ZygiskModule::PltHookRegister(ino_t inode, const char *symbol, void *callback, void **backup) {
|
||||
if (inode == 0 || symbol == nullptr || callback == nullptr)
|
||||
return;
|
||||
mutex_guard lock(hook_lock);
|
||||
register_info.emplace_back(RegisterInfo{{}, inode, symbol, callback, backup});
|
||||
}
|
||||
|
||||
void ZygiskModule::PltHookExclude(const char* regex, const char *symbol) {
|
||||
if (!regex) return;
|
||||
regex_t re;
|
||||
if (regcomp(&re, regex, REG_NOSUB) != 0)
|
||||
return;
|
||||
mutex_guard lock(hook_lock);
|
||||
ignore_info.emplace_back(IgnoreInfo{re, 0, symbol ? symbol : ""});
|
||||
}
|
||||
|
||||
void ZygiskModule::PltHookExclude(ino_t inode, const char *symbol) {
|
||||
if (inode == 0) return;
|
||||
mutex_guard lock(hook_lock);
|
||||
ignore_info.emplace_back(IgnoreInfo{{}, inode, symbol ? symbol : ""});
|
||||
}
|
||||
|
||||
bool ZygiskModule::CommitPltHook() {
|
||||
mutex_guard lock(hook_lock);
|
||||
for (auto &map: lsplt::MapInfo::Scan()) {
|
||||
if (map.offset != 0 || !map.is_private || !(map.perms & PROT_READ)) continue;
|
||||
for (auto ®: register_info) {
|
||||
if ((reg.inode != 0 && reg.inode != map.inode)||
|
||||
(reg.inode == 0 && regexec(®.regex, map.path.c_str(), 0, nullptr, 0) != 0))
|
||||
continue;
|
||||
bool ignored = false;
|
||||
for (auto &ign: ignore_info) {
|
||||
if ((ign.inode != 0 && ign.inode != map.inode) ||
|
||||
(ign.inode == 0 && regexec(&ign.regex, map.path.c_str(), 0, nullptr, 0) != 0))
|
||||
continue;
|
||||
if (ign.symbol.empty() || ign.symbol == reg.symbol) {
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ignored) {
|
||||
lsplt::RegisterHook(map.inode, reg.symbol, reg.callback, reg.backup);
|
||||
}
|
||||
}
|
||||
}
|
||||
register_info.clear();
|
||||
ignore_info.clear();
|
||||
return lsplt::CommitHook();
|
||||
}
|
||||
|
||||
|
||||
bool ZygiskModule::valid() const {
|
||||
if (mod.api_version == nullptr)
|
||||
return false;
|
||||
switch (*mod.api_version) {
|
||||
case 4:
|
||||
// fallthrough
|
||||
case 3:
|
||||
// fallthrough
|
||||
case 2:
|
||||
// fallthrough
|
||||
case 1:
|
||||
return mod.v1->impl && mod.v1->preAppSpecialize && mod.v1->postAppSpecialize &&
|
||||
mod.v1->preServerSpecialize && mod.v1->postServerSpecialize;
|
||||
@ -697,8 +749,7 @@ void HookContext::nativeForkAndSpecialize_post() {
|
||||
} // namespace
|
||||
|
||||
static bool hook_refresh() {
|
||||
if (xhook_refresh(0) == 0) {
|
||||
xhook_clear();
|
||||
if (lsplt::CommitHook()) {
|
||||
return true;
|
||||
} else {
|
||||
ZLOGE("xhook failed\n");
|
||||
@ -706,14 +757,12 @@ static bool hook_refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
static int hook_register(const char *path, const char *symbol, void *new_func, void **old_func) {
|
||||
int ret = xhook_register(path, symbol, new_func, old_func);
|
||||
if (ret != 0) {
|
||||
static void hook_register(ino_t inode, const char *symbol, void *new_func, void **old_func) {
|
||||
if (!lsplt::RegisterHook(inode, symbol, new_func, old_func)) {
|
||||
ZLOGE("Failed to register hook \"%s\"\n", symbol);
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
xhook_list->emplace_back(path, symbol, old_func);
|
||||
return 0;
|
||||
xhook_list->emplace_back(inode, symbol, old_func);
|
||||
}
|
||||
|
||||
#define XHOOK_REGISTER_SYM(PATH_REGEX, SYM, NAME) \
|
||||
@ -722,23 +771,24 @@ static int hook_register(const char *path, const char *symbol, void *new_func, v
|
||||
#define XHOOK_REGISTER(PATH_REGEX, NAME) \
|
||||
XHOOK_REGISTER_SYM(PATH_REGEX, #NAME, NAME)
|
||||
|
||||
#define ANDROID_RUNTIME ".*/libandroid_runtime.so$"
|
||||
#define APP_PROCESS "^/system/bin/app_process.*"
|
||||
|
||||
void hook_functions() {
|
||||
#if MAGISK_DEBUG
|
||||
// xhook_enable_debug(1);
|
||||
xhook_enable_sigsegv_protection(0);
|
||||
#endif
|
||||
default_new(xhook_list);
|
||||
default_new(jni_hook_list);
|
||||
default_new(jni_method_map);
|
||||
|
||||
XHOOK_REGISTER(ANDROID_RUNTIME, fork);
|
||||
XHOOK_REGISTER(ANDROID_RUNTIME, unshare);
|
||||
XHOOK_REGISTER(ANDROID_RUNTIME, jniRegisterNativeMethods);
|
||||
XHOOK_REGISTER(ANDROID_RUNTIME, selinux_android_setcontext);
|
||||
XHOOK_REGISTER_SYM(ANDROID_RUNTIME, "__android_log_close", android_log_close);
|
||||
ino_t android_runtime_inode = 0;
|
||||
for (auto &map : lsplt::MapInfo::Scan()) {
|
||||
if (map.path.ends_with("libandroid_runtime.so")) {
|
||||
android_runtime_inode = map.inode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XHOOK_REGISTER(android_runtime_inode, fork);
|
||||
XHOOK_REGISTER(android_runtime_inode, unshare);
|
||||
XHOOK_REGISTER(android_runtime_inode, jniRegisterNativeMethods);
|
||||
XHOOK_REGISTER(android_runtime_inode, selinux_android_setcontext);
|
||||
XHOOK_REGISTER_SYM(android_runtime_inode, "__android_log_close", android_log_close);
|
||||
hook_refresh();
|
||||
|
||||
// Remove unhooked methods
|
||||
@ -749,9 +799,10 @@ void hook_functions() {
|
||||
|
||||
if (old_jniRegisterNativeMethods == nullptr) {
|
||||
ZLOGD("jniRegisterNativeMethods not hooked, using fallback\n");
|
||||
|
||||
struct stat self_stat{};
|
||||
stat("/proc/self/exe", &self_stat);
|
||||
// android::AndroidRuntime::setArgv0(const char*, bool)
|
||||
XHOOK_REGISTER_SYM(APP_PROCESS, "_ZN7android14AndroidRuntime8setArgv0EPKcb", setArgv0);
|
||||
XHOOK_REGISTER_SYM(self_stat.st_ino, "_ZN7android14AndroidRuntime8setArgv0EPKcb", setArgv0);
|
||||
hook_refresh();
|
||||
|
||||
// We still need old_jniRegisterNativeMethods as other code uses it
|
||||
@ -785,8 +836,8 @@ static bool unhook_functions() {
|
||||
delete jni_hook_list;
|
||||
|
||||
// Unhook xhook
|
||||
for (const auto &[path, sym, old_func] : *xhook_list) {
|
||||
if (xhook_register(path, sym, *old_func, nullptr) != 0) {
|
||||
for (const auto &[inode, sym, old_func] : *xhook_list) {
|
||||
if (!lsplt::RegisterHook(inode, sym, *old_func, nullptr)) {
|
||||
ZLOGE("Failed to register xhook [%s]\n", sym);
|
||||
success = false;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "api.hpp"
|
||||
#include <list>
|
||||
#include <regex.h>
|
||||
|
||||
namespace {
|
||||
|
||||
@ -140,6 +142,8 @@ struct api_abi_v2 : public api_abi_v1 {
|
||||
|
||||
struct api_abi_v4 : public api_abi_v2 {
|
||||
bool (*exemptFd)(int);
|
||||
void (*pltHookRegisterInode)(ino_t, const char *, void *, void **);
|
||||
void (*pltHookExcludeInode)(ino_t, const char *);
|
||||
};
|
||||
|
||||
union ApiTable {
|
||||
@ -210,6 +214,29 @@ private:
|
||||
long *api_version;
|
||||
module_abi_v1 *v1;
|
||||
} mod;
|
||||
|
||||
struct RegisterInfo {
|
||||
regex_t regex;
|
||||
ino_t inode;
|
||||
std::string symbol;
|
||||
void *callback;
|
||||
void **backup;
|
||||
};
|
||||
|
||||
struct IgnoreInfo {
|
||||
regex_t regex;
|
||||
ino_t inode;
|
||||
std::string symbol;
|
||||
};
|
||||
inline static pthread_mutex_t hook_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
inline static std::list<RegisterInfo> register_info {};
|
||||
inline static std::list<IgnoreInfo> ignore_info {};
|
||||
|
||||
static void PltHookRegister(const char *lib, const char *symbol, void *callback, void **backup);
|
||||
static void PltHookRegister(ino_t inode, const char *symbol, void *callback, void **backup);
|
||||
static void PltHookExclude(const char *lib, const char *symbol);
|
||||
static void PltHookExclude(ino_t inode, const char *symbol);
|
||||
static bool CommitPltHook();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -2,63 +2,23 @@
|
||||
#include <base.hpp>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
#include <lsplt.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
struct map_info {
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
uintptr_t off;
|
||||
int perms;
|
||||
unsigned long inode;
|
||||
|
||||
map_info() : start(0), end(0), off(0), perms(0), inode(0) {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
template<typename Func>
|
||||
static void parse_maps(int pid, Func fn) {
|
||||
char file[32];
|
||||
|
||||
// format: start-end perms offset dev inode path
|
||||
sprintf(file, "/proc/%d/maps", pid);
|
||||
file_readline(true, file, [=](string_view l) -> bool {
|
||||
char *line = (char *) l.data();
|
||||
map_info info;
|
||||
char perm[5];
|
||||
int path_off;
|
||||
|
||||
if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %lu %n%*s",
|
||||
&info.start, &info.end, perm, &info.off, &info.inode, &path_off) != 5)
|
||||
return true;
|
||||
|
||||
// Parse permissions
|
||||
if (perm[0] != '-')
|
||||
info.perms |= PROT_READ;
|
||||
if (perm[1] != '-')
|
||||
info.perms |= PROT_WRITE;
|
||||
if (perm[2] != '-')
|
||||
info.perms |= PROT_EXEC;
|
||||
|
||||
return fn(info, line + path_off);
|
||||
});
|
||||
static vector<lsplt::MapInfo> find_maps(const char *name) {
|
||||
auto maps = lsplt::MapInfo::Scan();
|
||||
for (auto iter = maps.begin(); iter != maps.end();) {
|
||||
if (iter->path != name) {
|
||||
iter = maps.erase(iter);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
static vector<map_info> find_maps(const char *name) {
|
||||
vector<map_info> maps;
|
||||
parse_maps(getpid(), [=, &maps](const map_info &info, const char *path) -> bool {
|
||||
if (strcmp(path, name) == 0)
|
||||
maps.emplace_back(info);
|
||||
return true;
|
||||
});
|
||||
return maps;
|
||||
}
|
||||
|
||||
std::pair<void *, size_t> find_map_range(const char *name, unsigned long inode) {
|
||||
vector<map_info> maps = find_maps(name);
|
||||
auto maps = find_maps(name);
|
||||
uintptr_t start = 0u;
|
||||
uintptr_t end = 0u;
|
||||
for (const auto &map : maps) {
|
||||
@ -76,8 +36,8 @@ std::pair<void *, size_t> find_map_range(const char *name, unsigned long inode)
|
||||
}
|
||||
|
||||
void unmap_all(const char *name) {
|
||||
vector<map_info> maps = find_maps(name);
|
||||
for (map_info &info : maps) {
|
||||
auto maps = find_maps(name);
|
||||
for (auto &info : maps) {
|
||||
void *addr = reinterpret_cast<void *>(info.start);
|
||||
size_t size = info.end - info.start;
|
||||
if (info.perms & PROT_READ) {
|
||||
@ -91,8 +51,8 @@ void unmap_all(const char *name) {
|
||||
}
|
||||
|
||||
void remap_all(const char *name) {
|
||||
vector<map_info> maps = find_maps(name);
|
||||
for (map_info &info : maps) {
|
||||
auto maps = find_maps(name);
|
||||
for (auto &info : maps) {
|
||||
void *addr = reinterpret_cast<void *>(info.start);
|
||||
size_t size = info.end - info.start;
|
||||
void *copy = xmmap(nullptr, size, PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
@ -106,27 +66,21 @@ void remap_all(const char *name) {
|
||||
}
|
||||
|
||||
uintptr_t get_function_off(int pid, uintptr_t addr, char *lib) {
|
||||
uintptr_t off = 0;
|
||||
parse_maps(pid, [=, &off](const map_info &info, const char *path) -> bool {
|
||||
for (auto &info : lsplt::MapInfo::Scan()) {
|
||||
if (addr >= info.start && addr < info.end) {
|
||||
if (lib)
|
||||
strcpy(lib, path);
|
||||
off = addr - info.start + info.off;
|
||||
return false;
|
||||
strcpy(lib, info.path.data());
|
||||
return addr - info.start + info.offset;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return off;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t get_function_addr(int pid, const char *lib, uintptr_t off) {
|
||||
uintptr_t addr = 0;
|
||||
parse_maps(pid, [=, &addr](const map_info &info, const char *path) -> bool {
|
||||
if (strcmp(path, lib) == 0 && (info.perms & PROT_EXEC)) {
|
||||
addr = info.start - info.off + off;
|
||||
return false;
|
||||
for (auto &info : lsplt::MapInfo::Scan()) {
|
||||
if (info.path == lib && (info.perms & PROT_EXEC)) {
|
||||
return info.start - info.offset + off;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return addr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -84,3 +84,4 @@ export KEEPFORCEENCRYPT=true
|
||||
|
||||
rm -f ramdisk.cpio.orig config magisk*.xz stub.xz
|
||||
./magiskboot compress=gzip ramdisk.cpio ramdisk.cpio.gz
|
||||
pm install magisk.apk || true
|
||||
|
Loading…
Reference in New Issue
Block a user