mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
f7e7132f8f
96
Cargo.lock
generated
96
Cargo.lock
generated
@ -736,10 +736,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.25.3"
|
||||
version = "0.25.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cssparser-macros 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser-macros 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -753,14 +753,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cssparser-macros"
|
||||
version = "0.3.3"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -768,17 +768,17 @@ name = "cstr"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cstr-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cstr-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cstr-macros"
|
||||
version = "0.1.3"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1204,7 +1204,7 @@ name = "geckoservo"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1681,7 +1681,7 @@ name = "malloc_size_of"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashglobe 0.1.0",
|
||||
"selectors 0.21.0",
|
||||
@ -1846,8 +1846,8 @@ name = "mozilla-central-workspace-hack"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2018,13 +2018,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.2.2"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2249,14 +2248,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "prefs_parser"
|
||||
version = "0.0.1"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.27"
|
||||
@ -2300,14 +2291,6 @@ name = "quick-error"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.11"
|
||||
@ -2667,7 +2650,7 @@ name = "selectors"
|
||||
version = "0.21.0"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2884,7 +2867,7 @@ dependencies = [
|
||||
"bindgen 0.49.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fallible 0.0.1",
|
||||
@ -2900,7 +2883,7 @@ dependencies = [
|
||||
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nsstring 0.1.0",
|
||||
"num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2946,7 +2929,7 @@ version = "0.0.1"
|
||||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
@ -2962,7 +2945,7 @@ name = "stylo_tests"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"geckoservo 0.0.1",
|
||||
@ -2983,26 +2966,6 @@ name = "svg_fmt"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.14.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.30"
|
||||
@ -3137,7 +3100,7 @@ dependencies = [
|
||||
name = "to_shmem"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_arc 0.1.1",
|
||||
"smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3696,8 +3659,9 @@ name = "xpcom_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3807,10 +3771,10 @@ dependencies = [
|
||||
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
|
||||
"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b"
|
||||
"checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a"
|
||||
"checksum cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ba1ab4e1814be64bf6b6064ff532db0e34087f11b37706d6c96a21d32478761d"
|
||||
"checksum cssparser-macros 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f3a5383ae18dbfdeb569ed62019f5bddb2a95cd2d3833313c475a0d014777805"
|
||||
"checksum cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e06795910fc2f585a75bdc9690fbcc51e83519f07b6eb981db43944643c04933"
|
||||
"checksum cssparser-macros 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b16e382d9b983fdb9ac6a36b37fdeb84ce3ea81f749febfee3463cfa7f24275e"
|
||||
"checksum cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b6557bdb1dc9647eae1cf7f5601b14cd45fc3c7ccf2df618387416fe542da6ea"
|
||||
"checksum cstr-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0472c17c83d3ec1af32fb6ee2b3ad56ae0b6e69355d63d1d30602055c34324a8"
|
||||
"checksum cstr-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0f12dd847ec773fc98d75edba5394cb87d0f35e7ee548a4c81849ca6374b3d48"
|
||||
"checksum cubeb 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "db3f0df2ad5cb453126364a77921466ba6c1034e8bd9247f326cdb31430dbc2a"
|
||||
"checksum cubeb-backend 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "442cd5cfb980ff62730525278ce320d9b2ff635b725857ad3176832664262fec"
|
||||
"checksum cubeb-core 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0161f9327864922ba7a172c90bd86bc9094938433eca415e2c75629954045022"
|
||||
@ -3914,7 +3878,7 @@ dependencies = [
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
|
||||
"checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
|
||||
"checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7"
|
||||
"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
|
||||
@ -3943,11 +3907,9 @@ dependencies = [
|
||||
"checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9"
|
||||
"checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0"
|
||||
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
"checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4"
|
||||
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
||||
"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
|
||||
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
|
||||
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
|
||||
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
@ -4009,8 +3971,6 @@ dependencies = [
|
||||
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum svg_fmt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c666f0fed8e1e20e057af770af9077d72f3d5a33157b8537c1475dd8ffd6d32b"
|
||||
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
|
||||
"checksum syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4b5274d4a0a3d2749d5c158dc64d3403e60554dc61194648787ada5212473d"
|
||||
"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
|
||||
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
||||
"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb"
|
||||
|
@ -751,8 +751,8 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) {
|
||||
MOZ_ASSERT(mDocument->AccessibleOrTrueContainer(containerNode),
|
||||
"Text node having rendered text hasn't accessible document!");
|
||||
|
||||
Accessible* container = mDocument->AccessibleOrTrueContainer(
|
||||
containerNode, DocAccessible::eNoContainerIfARIAHidden);
|
||||
Accessible* container =
|
||||
mDocument->AccessibleOrTrueContainer(containerNode, true);
|
||||
if (container) {
|
||||
nsTArray<nsCOMPtr<nsIContent>>* list =
|
||||
mContentInsertions.LookupOrAdd(container);
|
||||
|
@ -23,10 +23,10 @@ namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
inline Accessible* DocAccessible::AccessibleOrTrueContainer(
|
||||
nsINode* aNode, int aIgnoreARIAHidden) const {
|
||||
nsINode* aNode, bool aNoContainerIfPruned) const {
|
||||
// HTML comboboxes have no-content list accessible as an intermediate
|
||||
// containing all options.
|
||||
Accessible* container = GetAccessibleOrContainer(aNode, aIgnoreARIAHidden);
|
||||
Accessible* container = GetAccessibleOrContainer(aNode, aNoContainerIfPruned);
|
||||
if (container && container->IsHTMLCombobox()) {
|
||||
return container->FirstChild();
|
||||
}
|
||||
|
@ -1132,8 +1132,8 @@ Accessible* DocAccessible::GetAccessibleByUniqueIDInSubtree(void* aUniqueID) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Accessible* DocAccessible::GetAccessibleOrContainer(nsINode* aNode,
|
||||
int aARIAHiddenFlag) const {
|
||||
Accessible* DocAccessible::GetAccessibleOrContainer(
|
||||
nsINode* aNode, bool aNoContainerIfPruned) const {
|
||||
if (!aNode || !aNode->GetComposedDoc()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1157,11 +1157,26 @@ Accessible* DocAccessible::GetAccessibleOrContainer(nsINode* aNode,
|
||||
MOZ_ASSERT(currNode);
|
||||
for (; currNode; currNode = currNode->GetFlattenedTreeParentNode()) {
|
||||
// No container if is inside of aria-hidden subtree.
|
||||
if (aARIAHiddenFlag == eNoContainerIfARIAHidden && currNode->IsElement() &&
|
||||
if (aNoContainerIfPruned && currNode->IsElement() &&
|
||||
aria::HasDefinedARIAHidden(currNode->AsElement())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if node is in an unselected deck panel
|
||||
if (aNoContainerIfPruned && currNode->IsXULElement()) {
|
||||
if (nsIFrame* frame = currNode->AsContent()->GetPrimaryFrame()) {
|
||||
nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent());
|
||||
if (deckFrame && deckFrame->GetSelectedBox() != frame) {
|
||||
// If deck is not a <tabpanels>, return null
|
||||
nsIContent* parentFrameContent = deckFrame->GetContent();
|
||||
if (!parentFrameContent ||
|
||||
!parentFrameContent->IsXULElement(nsGkAtoms::tabpanels)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Accessible* accessible = GetAccessible(currNode)) {
|
||||
return accessible;
|
||||
}
|
||||
@ -1666,8 +1681,7 @@ bool InsertIterator::Next() {
|
||||
// what means there's no container. Ignore the insertion too.
|
||||
nsIContent* prevNode = mNodes->SafeElementAt(mNodesIdx - 1);
|
||||
nsIContent* node = mNodes->ElementAt(mNodesIdx++);
|
||||
Accessible* container = Document()->AccessibleOrTrueContainer(
|
||||
node, DocAccessible::eNoContainerIfARIAHidden);
|
||||
Accessible* container = Document()->AccessibleOrTrueContainer(node, true);
|
||||
if (container != Context()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -284,11 +284,12 @@ class DocAccessible : public HyperTextAccessibleWrap,
|
||||
|
||||
/**
|
||||
* Return an accessible for the given DOM node or container accessible if
|
||||
* the node is not accessible.
|
||||
* the node is not accessible. If aNoContainerIfPruned is true it will return
|
||||
* null if the node is in a pruned subtree (eg. aria-hidden or unselected deck
|
||||
* panel)
|
||||
*/
|
||||
enum { eIgnoreARIAHidden = 0, eNoContainerIfARIAHidden = 1 };
|
||||
Accessible* GetAccessibleOrContainer(
|
||||
nsINode* aNode, int aARIAHiddenFlag = eIgnoreARIAHidden) const;
|
||||
Accessible* GetAccessibleOrContainer(nsINode* aNode,
|
||||
bool aNoContainerIfPruned = false) const;
|
||||
|
||||
/**
|
||||
* Return a container accessible for the given DOM node.
|
||||
@ -302,7 +303,7 @@ class DocAccessible : public HyperTextAccessibleWrap,
|
||||
* container for it.
|
||||
*/
|
||||
Accessible* AccessibleOrTrueContainer(
|
||||
nsINode* aNode, int aARIAHiddenFlag = eIgnoreARIAHidden) const;
|
||||
nsINode* aNode, bool aNoContainerIfPruned = false) const;
|
||||
|
||||
/**
|
||||
* Return an accessible for the given node or its first accessible descendant.
|
||||
|
@ -64,10 +64,55 @@
|
||||
}
|
||||
}
|
||||
|
||||
function showDeckPanel(aContainerID, aPanelID)
|
||||
{
|
||||
this.container = getAccessible(aContainerID);
|
||||
this.deckNode = getNode(aPanelID);
|
||||
var tree =
|
||||
{ GROUPING: [ // role="group"
|
||||
{ GROUPING: [ // grouping of panel 2
|
||||
{ PUSHBUTTON: [] } // push button in panel 2
|
||||
] }
|
||||
] };
|
||||
|
||||
|
||||
this.unexpectedEventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, this.container)
|
||||
];
|
||||
|
||||
this.invoke = function showDeckPanel_invoke()
|
||||
{
|
||||
// This stops the refreh driver from doing its regular ticks, and leaves
|
||||
// us in control. 100 is an arbitrary positive number to advance the clock
|
||||
// it is not checked or used anywhere.
|
||||
window.windowUtils.advanceTimeAndRefresh(100);
|
||||
|
||||
testAccessibleTree(this.container, tree);
|
||||
this.deckNode.style.display = "-moz-box";
|
||||
|
||||
// This flushes our DOM mutations and forces any pending mutation events.
|
||||
window.windowUtils.advanceTimeAndRefresh(100);
|
||||
}
|
||||
|
||||
this.finalCheck = function showDeckPanel_finalCheck()
|
||||
{
|
||||
testAccessibleTree(this.container, tree);
|
||||
|
||||
// Return to regular refresh driver ticks.
|
||||
window.windowUtils.restoreNormalRefresh();
|
||||
}
|
||||
|
||||
this.getID = function showDeckPanel_getID()
|
||||
{
|
||||
return "show deck panel";
|
||||
}
|
||||
}
|
||||
|
||||
var gQueue = null;
|
||||
function doTest()
|
||||
{
|
||||
gQueue = new eventQueue();
|
||||
gQueue.push(new showDeckPanel("container", "hidden"));
|
||||
gQueue.push(new switchDeckPanel("container", "deck"));
|
||||
gQueue.invoke(); // will call SimpleTest.finish();
|
||||
}
|
||||
@ -99,6 +144,7 @@
|
||||
<groupbox>
|
||||
<button label="This is the second page"/>
|
||||
</groupbox>
|
||||
<hbox id="hidden" style="display: none;"><label>This is the third page</label></hbox>
|
||||
</deck>
|
||||
|
||||
</vbox>
|
||||
|
@ -24,8 +24,8 @@
|
||||
{
|
||||
this.listboxNode = getNode(aListboxID);
|
||||
|
||||
this.listitemNode = document.createElement("richlistitem");
|
||||
var label = document.createElement("label");
|
||||
this.listitemNode = document.createXULElement("richlistitem");
|
||||
var label = document.createXULElement("label");
|
||||
label.setAttribute("value", "item1");
|
||||
this.listitemNode.appendChild(label);
|
||||
|
||||
|
@ -60,6 +60,11 @@ static mozilla::LauncherVoidResult PostCreationSetup(
|
||||
(0x00000001ULL << 60)
|
||||
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
|
||||
|
||||
#if !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF)
|
||||
# define PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF \
|
||||
(0x00000002ULL << 40)
|
||||
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF)
|
||||
|
||||
#if (_WIN32_WINNT < 0x0602)
|
||||
BOOL WINAPI
|
||||
SetProcessMitigationPolicy(PROCESS_MITIGATION_POLICY aMitigationPolicy,
|
||||
@ -76,6 +81,14 @@ static void SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs,
|
||||
aAttrs.AddMitigationPolicy(
|
||||
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON);
|
||||
}
|
||||
|
||||
#if defined(_M_ARM64)
|
||||
// Disable CFG on older versions of ARM64 Windows to avoid a crash in COM.
|
||||
if (!mozilla::IsWin10Sep2018UpdateOrLater()) {
|
||||
aAttrs.AddMitigationPolicy(
|
||||
PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF);
|
||||
}
|
||||
#endif // defined(_M_ARM64)
|
||||
}
|
||||
|
||||
static mozilla::LauncherFlags ProcessCmdLine(int& aArgc, wchar_t* aArgv[]) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
// event.clipboardData.
|
||||
|
||||
add_task(async function() {
|
||||
var textbox = document.createElement("textbox");
|
||||
var textbox = document.createXULElement("textbox");
|
||||
document.documentElement.appendChild(textbox);
|
||||
|
||||
textbox.focus();
|
||||
|
@ -336,7 +336,7 @@ function test_emitLatchedEvents(eventPrefix, initialDelta, cmd) {
|
||||
}
|
||||
|
||||
function test_addCommand(prefName, id) {
|
||||
let cmd = test_commandset.appendChild(document.createElement("command"));
|
||||
let cmd = test_commandset.appendChild(document.createXULElement("command"));
|
||||
cmd.setAttribute("id", id);
|
||||
cmd.setAttribute("oncommand", "this.callCount++;");
|
||||
|
||||
|
@ -28,10 +28,10 @@ browser.jar:
|
||||
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
|
||||
* content/browser/browser.css (content/browser.css)
|
||||
content/browser/browser.js (content/browser.js)
|
||||
#ifdef MOZ_BROWSER_XHTML
|
||||
* content/browser/browser.xhtml (content/browser.xhtml)
|
||||
#else
|
||||
#ifdef MOZ_BROWSER_XUL
|
||||
* content/browser/browser.xul (content/browser.xul)
|
||||
#else
|
||||
* content/browser/browser.xhtml (content/browser.xhtml)
|
||||
#endif
|
||||
content/browser/browser-addons.js (content/browser-addons.js)
|
||||
content/browser/browser-allTabsMenu.js (content/browser-allTabsMenu.js)
|
||||
|
@ -59,8 +59,8 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
|
||||
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
|
||||
DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
|
||||
if CONFIG['MOZ_BROWSER_XHTML']:
|
||||
DEFINES['MOZ_BROWSER_XHTML'] = CONFIG['MOZ_BROWSER_XHTML']
|
||||
if CONFIG['MOZ_BROWSER_XUL']:
|
||||
DEFINES['MOZ_BROWSER_XUL'] = CONFIG['MOZ_BROWSER_XUL']
|
||||
|
||||
DEFINES['APP_LICENSE_BLOCK'] = '%s/content/overrides/app-license.html' % SRCDIR
|
||||
|
||||
|
@ -2316,11 +2316,20 @@ BrowserGlue.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_migrateXULStoreForDocument(fromURL, toURL) {
|
||||
Array.from(Services.xulStore.getIDsEnumerator(fromURL)).forEach((id) => {
|
||||
Array.from(Services.xulStore.getAttributeEnumerator(fromURL, id)).forEach(attr => {
|
||||
let value = Services.xulStore.getValue(fromURL, id, attr);
|
||||
Services.xulStore.setValue(toURL, id, attr, value);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
_migrateUI: function BG__migrateUI() {
|
||||
// Use an increasing number to keep track of the current migration state.
|
||||
// Completely unrelated to the current Firefox release number.
|
||||
const UI_VERSION = 81;
|
||||
const UI_VERSION = 82;
|
||||
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
|
||||
|
||||
let currentUIVersion;
|
||||
@ -2624,6 +2633,11 @@ BrowserGlue.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUIVersion < 82) {
|
||||
this._migrateXULStoreForDocument("chrome://browser/content/browser.xul",
|
||||
"chrome://browser/content/browser.xhtml");
|
||||
}
|
||||
|
||||
// Update the migration version.
|
||||
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||
},
|
||||
@ -3370,16 +3384,16 @@ var DefaultBrowserCheck = {
|
||||
|
||||
_createPopup(win, notNowStrings, neverStrings) {
|
||||
let doc = win.document;
|
||||
let popup = doc.createElement("menupopup");
|
||||
let popup = doc.createXULElement("menupopup");
|
||||
popup.id = this.OPTIONPOPUP;
|
||||
|
||||
let notNowItem = doc.createElement("menuitem");
|
||||
let notNowItem = doc.createXULElement("menuitem");
|
||||
notNowItem.id = "defaultBrowserNotNow";
|
||||
notNowItem.setAttribute("label", notNowStrings.label);
|
||||
notNowItem.setAttribute("accesskey", notNowStrings.accesskey);
|
||||
popup.appendChild(notNowItem);
|
||||
|
||||
let neverItem = doc.createElement("menuitem");
|
||||
let neverItem = doc.createXULElement("menuitem");
|
||||
neverItem.id = "defaultBrowserNever";
|
||||
neverItem.setAttribute("label", neverStrings.label);
|
||||
neverItem.setAttribute("accesskey", neverStrings.accesskey);
|
||||
|
@ -14,8 +14,8 @@ add_task(async function test_about_addons() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:addons", false);
|
||||
|
||||
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
|
||||
ok(content.document.documentURI.startsWith("about:neterror"),
|
||||
"about:addons should display the net error page");
|
||||
ok(content.document.documentURI.startsWith("about:neterror?e=blockedByPolicy"),
|
||||
content.document.documentURI + "should start with about:neterror?e=blockedByPolicy");
|
||||
|
||||
// There is currently a testing-specific race condition that causes this test
|
||||
// to fail, but it is not a problem if we test after the first page load.
|
||||
|
@ -12,8 +12,8 @@ add_task(async function test_about_config() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:config", false);
|
||||
|
||||
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
|
||||
ok(content.document.documentURI.startsWith("about:neterror"),
|
||||
"about:config should display the net error page");
|
||||
ok(content.document.documentURI.startsWith("about:neterror?e=blockedByPolicy"),
|
||||
content.document.documentURI + "should start with about:neterror?e=blockedByPolicy");
|
||||
|
||||
// There is currently a testing-specific race condition that causes this test
|
||||
// to fail, but it is not a problem if we test after the first page load.
|
||||
|
@ -14,8 +14,8 @@ add_task(async function test_about_profiles() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:profiles", false);
|
||||
|
||||
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
|
||||
ok(content.document.documentURI.startsWith("about:neterror"),
|
||||
"about:profiles should display the net error page");
|
||||
ok(content.document.documentURI.startsWith("about:neterror?e=blockedByPolicy"),
|
||||
content.document.documentURI + "should start with about:neterror?e=blockedByPolicy");
|
||||
|
||||
// There is currently a testing-specific race condition that causes this test
|
||||
// to fail, but it is not a problem if we test after the first page load.
|
||||
|
@ -14,8 +14,8 @@ add_task(async function test_about_support() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:support", false);
|
||||
|
||||
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
|
||||
ok(content.document.documentURI.startsWith("about:neterror"),
|
||||
"about:support should display the net error page");
|
||||
ok(content.document.documentURI.startsWith("about:neterror?e=blockedByPolicy"),
|
||||
content.document.documentURI + "should start with about:neterror?e=blockedByPolicy");
|
||||
|
||||
// There is currently a testing-specific race condition that causes this test
|
||||
// to fail, but it is not a problem if we test after the first page load.
|
||||
|
@ -217,7 +217,7 @@ var MigrationWizard = { /* exported MigrationWizard */
|
||||
var sourceProfiles = this.spinResolve(this._migrator.getSourceProfiles());
|
||||
|
||||
for (let profile of sourceProfiles) {
|
||||
var item = document.createElement("radio");
|
||||
var item = document.createXULElement("radio");
|
||||
item.id = profile.id;
|
||||
item.setAttribute("label", profile.name);
|
||||
profiles.appendChild(item);
|
||||
@ -258,7 +258,7 @@ var MigrationWizard = { /* exported MigrationWizard */
|
||||
for (var i = 0; i < 16; ++i) {
|
||||
var itemID = (items >> i) & 0x1 ? Math.pow(2, i) : 0;
|
||||
if (itemID > 0) {
|
||||
var checkbox = document.createElement("checkbox");
|
||||
var checkbox = document.createXULElement("checkbox");
|
||||
checkbox.id = itemID;
|
||||
checkbox.setAttribute("label",
|
||||
MigrationUtils.getLocalizedString(itemID + "_" + this._source));
|
||||
@ -344,7 +344,7 @@ var MigrationWizard = { /* exported MigrationWizard */
|
||||
for (var i = 0; i < 16; ++i) {
|
||||
itemID = (this._itemsFlags >> i) & 0x1 ? Math.pow(2, i) : 0;
|
||||
if (itemID > 0) {
|
||||
var label = document.createElement("label");
|
||||
var label = document.createXULElement("label");
|
||||
label.id = itemID + "_migrated";
|
||||
try {
|
||||
label.setAttribute("value",
|
||||
|
@ -38,10 +38,7 @@ class _BookmarkPanelHub {
|
||||
this._handleMessageRequest = handleMessageRequest;
|
||||
this._addImpression = addImpression;
|
||||
this._dispatch = dispatch;
|
||||
this._l10n = new DOMLocalization([
|
||||
"browser/branding/sync-brand.ftl",
|
||||
"browser/newtab/asrouter.ftl",
|
||||
]);
|
||||
this._l10n = new DOMLocalization();
|
||||
this._initialized = true;
|
||||
}
|
||||
|
||||
@ -92,6 +89,9 @@ class _BookmarkPanelHub {
|
||||
};
|
||||
|
||||
if (response && response.content) {
|
||||
// Only insert localization files if we need to show a message
|
||||
win.MozXULElement.insertFTLIfNeeded("browser/newtab/asrouter.ftl");
|
||||
win.MozXULElement.insertFTLIfNeeded("browser/branding/sync-brand.ftl");
|
||||
this.showMessage(response.content, target, win);
|
||||
this.sendImpression();
|
||||
this.sendUserEventTelemetry("IMPRESSION", win);
|
||||
@ -127,9 +127,10 @@ class _BookmarkPanelHub {
|
||||
});
|
||||
recommendation.style.color = message.color;
|
||||
recommendation.style.background = `-moz-linear-gradient(-45deg, ${message.background_color_1} 0%, ${message.background_color_2} 70%)`;
|
||||
const close = createElement("a");
|
||||
const close = createElement("button");
|
||||
close.setAttribute("id", "cfrClose");
|
||||
close.setAttribute("aria-label", "close");
|
||||
close.style.color = message.color;
|
||||
this._l10n.setAttributes(close, message.close_button.tooltiptext);
|
||||
close.addEventListener("click", e => {
|
||||
this.sendUserEventTelemetry("DISMISS", win);
|
||||
@ -149,7 +150,6 @@ class _BookmarkPanelHub {
|
||||
recommendation.appendChild(title);
|
||||
recommendation.appendChild(content);
|
||||
recommendation.appendChild(cta);
|
||||
this._l10n.translateElements([...recommendation.children]);
|
||||
target.container.appendChild(recommendation);
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ class PageAction {
|
||||
}
|
||||
|
||||
_createElementAndAppend({type, id}, parent) {
|
||||
let element = this.window.document.createElement(type);
|
||||
let element = this.window.document.createXULElement(type);
|
||||
if (id) {
|
||||
element.setAttribute("id", id);
|
||||
}
|
||||
@ -397,12 +397,12 @@ class PageAction {
|
||||
stepsContainer.remove();
|
||||
stepsContainer = stepsContainer.cloneNode(false);
|
||||
} else {
|
||||
stepsContainer = this.window.document.createElement("vbox");
|
||||
stepsContainer = this.window.document.createXULElement("vbox");
|
||||
stepsContainer.setAttribute("id", stepsContainerId);
|
||||
}
|
||||
footerText.parentNode.appendChild(stepsContainer);
|
||||
for (let step of content.descriptionDetails.steps) {
|
||||
const li = this.window.document.createElement("li");
|
||||
const li = this.window.document.createXULElement("li");
|
||||
this._l10n.setAttributes(li, step.string_id);
|
||||
stepsContainer.appendChild(li);
|
||||
}
|
||||
|
@ -487,7 +487,7 @@ var PlacesOrganizer = {
|
||||
}
|
||||
|
||||
let backupDate = PlacesBackups.getDateForFile(backupFiles[i]);
|
||||
let m = restorePopup.insertBefore(document.createElement("menuitem"),
|
||||
let m = restorePopup.insertBefore(document.createXULElement("menuitem"),
|
||||
document.getElementById("restoreFromFile"));
|
||||
m.setAttribute("label", dateFormatter.format(backupDate) + sizeInfo);
|
||||
m.setAttribute("value", OS.Path.basename(backupFiles[i]));
|
||||
@ -496,7 +496,7 @@ var PlacesOrganizer = {
|
||||
}
|
||||
|
||||
// Add the restoreFromFile item.
|
||||
restorePopup.insertBefore(document.createElement("menuseparator"),
|
||||
restorePopup.insertBefore(document.createXULElement("menuseparator"),
|
||||
document.getElementById("restoreFromFile"));
|
||||
})();
|
||||
},
|
||||
@ -972,7 +972,7 @@ var ViewMenu = {
|
||||
var columns = content.columns;
|
||||
for (var i = 0; i < columns.count; ++i) {
|
||||
var column = columns.getColumnAt(i).element;
|
||||
var menuitem = document.createElement("menuitem");
|
||||
var menuitem = document.createXULElement("menuitem");
|
||||
menuitem.id = "menucol_" + column.id;
|
||||
menuitem.column = column;
|
||||
var label = column.getAttribute("label");
|
||||
|
@ -170,11 +170,11 @@ class OrderedListBox {
|
||||
}
|
||||
|
||||
createItem({id, label, value}) {
|
||||
let listitem = document.createElement("richlistitem");
|
||||
let listitem = document.createXULElement("richlistitem");
|
||||
listitem.id = id;
|
||||
listitem.setAttribute("value", value);
|
||||
|
||||
let labelEl = document.createElement("label");
|
||||
let labelEl = document.createXULElement("label");
|
||||
labelEl.textContent = label;
|
||||
listitem.appendChild(labelEl);
|
||||
|
||||
@ -249,7 +249,7 @@ class SortedItemSelectList {
|
||||
}
|
||||
|
||||
createItem({label, value, className, disabled}) {
|
||||
let item = document.createElement("menuitem");
|
||||
let item = document.createXULElement("menuitem");
|
||||
item.setAttribute("label", label);
|
||||
if (value)
|
||||
item.value = value;
|
||||
|
@ -1,3 +1,9 @@
|
||||
# This file is used by all AArch64 Win64 builds
|
||||
|
||||
ac_add_options --target=aarch64-windows-mingw32
|
||||
|
||||
# Temporary signal to toolchain.configure that our compiler is patched to
|
||||
# support CFG, until such support can be assumed.
|
||||
if test -z "$USE_ARTIFACT"; then
|
||||
ac_add_options --enable-hardening
|
||||
fi
|
||||
|
@ -31,10 +31,10 @@ fi
|
||||
# Enable building ./signmar and running libmar signature tests
|
||||
MOZ_ENABLE_SIGNMAR=1
|
||||
|
||||
if [ "${MOZ_BROWSER_XHTML}" = "1" ]; then
|
||||
BROWSER_CHROME_URL=chrome://browser/content/browser.xhtml
|
||||
else
|
||||
if [ "${MOZ_BROWSER_XUL}" = "1" ]; then
|
||||
BROWSER_CHROME_URL=chrome://browser/content/browser.xul
|
||||
else
|
||||
BROWSER_CHROME_URL=chrome://browser/content/browser.xhtml
|
||||
fi
|
||||
|
||||
# MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
|
||||
|
@ -99,13 +99,20 @@
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
#editBookmarkPanelRecommendationCta:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#editBookmarkPanelRecommendation #cfrClose {
|
||||
position: absolute;
|
||||
padding: 3px 2px;
|
||||
inset-inline-end: 16px;
|
||||
padding: 10px;
|
||||
inset-inline-end: 8px;
|
||||
top: 15px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: none;
|
||||
border-radius: var(--toolbarbutton-border-radius);
|
||||
background-color: transparent;
|
||||
background-image: url(chrome://browser/skin/stop.svg);
|
||||
background-size: 12px;
|
||||
background-repeat: no-repeat;
|
||||
@ -113,10 +120,17 @@
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#editBookmarkPanelRecommendation #cfrClose:hover {
|
||||
fill-opacity: 1;
|
||||
background-color: var(--toolbarbutton-hover-background);
|
||||
}
|
||||
|
||||
#editBookmarkPanelRecommendation #cfrClose:active,
|
||||
#editBookmarkPanelRecommendation #cfrClose:focus {
|
||||
box-shadow: var(--focus-ring-box-shadow);
|
||||
}
|
||||
|
||||
html|div#editBookmarkPanelFaviconContainer {
|
||||
|
@ -43,14 +43,6 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.textbox-search-clear:not([disabled]):hover {
|
||||
background-position: -16px 0;
|
||||
}
|
||||
|
||||
.textbox-search-clear:not([disabled]):hover:active {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
|
||||
.client .item.tab > .item-title-container {
|
||||
padding-inline-start: 26px;
|
||||
}
|
||||
|
26
build/build-clang/clang-8-mingw.json
Normal file → Executable file
26
build/build-clang/clang-8-mingw.json
Normal file → Executable file
@ -1,20 +1,32 @@
|
||||
{
|
||||
"llvm_revision": "348363",
|
||||
"llvm_revision": "356265",
|
||||
"stages": "3",
|
||||
"build_libcxx": true,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
|
||||
"lld_repo": "https://llvm.org/svn/llvm-project/lld/trunk",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/trunk",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_800/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_800/final",
|
||||
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_800/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_800/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_800/final",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_800/final",
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
|
||||
"cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
|
||||
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"patches": [
|
||||
"mingwclang-llvm-objcopy-COFF-Remove-a-superfluous-namespace-qua.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Add-support-for-removing-sections.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Implement-strip-debug.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Implement-only-keep-debug.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Implement-only-section.patch",
|
||||
"mingwclang-llvm-objcopy-Consistently-use-createStringError-inst.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Update-symbol-indices-in-weak-exte.patch",
|
||||
"mingwclang-llvm-objcopy-Return-Error-from-Buffer-allocate-ELF-W.patch",
|
||||
"mingwclang-Reapply-llvm-objcopy-COFF-Implement-add-gnu-debuglin.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Clear-the-unwritten-tail-of-coff_s.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Fix-handling-of-aux-symbols-for-bi.patch",
|
||||
"mingwclang-llvm-objcopy-COFF-Error-out-on-use-of-unhandled-opti.patch"
|
||||
]
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
"workaround-issue38586.patch",
|
||||
"unpoison-thread-stacks.patch",
|
||||
"downgrade-mangling-error.patch",
|
||||
"r355141-arm64-cfg.patch",
|
||||
"loosen-msvc-detection.patch",
|
||||
"revert-r355311.patch"
|
||||
]
|
||||
|
@ -0,0 +1,260 @@
|
||||
From 840d70f854a1d550924ced1d00160efcc7b8549a Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Wed, 23 Jan 2019 08:25:28 +0000
|
||||
Subject: [PATCH] Reapply: [llvm-objcopy] [COFF] Implement --add-gnu-debuglink
|
||||
|
||||
This was reverted since it broke a couple buildbots. The reason
|
||||
for the breakage is not yet known, but this time, the test has
|
||||
got more diagnostics added, to hopefully allow figuring out
|
||||
what goes wrong.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D57007
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351931 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../llvm-objcopy/COFF/add-gnu-debuglink.test | 48 +++++++++++++++
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 61 +++++++++++++++++++
|
||||
tools/llvm-objcopy/COFF/Object.cpp | 2 +-
|
||||
tools/llvm-objcopy/COFF/Object.h | 26 +++++++-
|
||||
tools/llvm-objcopy/COFF/Reader.cpp | 4 +-
|
||||
tools/llvm-objcopy/COFF/Writer.cpp | 9 +--
|
||||
6 files changed, 143 insertions(+), 7 deletions(-)
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test b/llvm/test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test
|
||||
new file mode 100644
|
||||
index 00000000000..cf3a9bba920
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test
|
||||
@@ -0,0 +1,48 @@
|
||||
+RUN: yaml2obj %p/Inputs/x86_64-exe.yaml > %t.in123.exe
|
||||
+
|
||||
+# Using a debuglink filename with a length that is a multiple of 4, to
|
||||
+# showcase padding in CONTENTS below.
|
||||
+
|
||||
+RUN: llvm-objcopy --add-gnu-debuglink=%t.in123.exe %t.in123.exe %t.out.exe
|
||||
+
|
||||
+# Temporary debugging of issues with this test:
|
||||
+RUN: ls -l %t.out.exe || true
|
||||
+RUN: od -Ax -t x1 %t.out.exe || true
|
||||
+RUN: llvm-readobj -sections %t.out.exe || true
|
||||
+
|
||||
+RUN: llvm-readobj -sections %t.out.exe | FileCheck %s --check-prefix=SECTIONS
|
||||
+RUN: llvm-objdump -s %t.out.exe | FileCheck %s --check-prefix=CONTENTS
|
||||
+
|
||||
+# Show the last of the preexisting sections, which is used for choosing
|
||||
+# a virtual address for the generated one.
|
||||
+
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS: Number: 4
|
||||
+SECTIONS-NEXT: Name: .pdata
|
||||
+SECTIONS-NEXT: VirtualSize: 0x18
|
||||
+SECTIONS-NEXT: VirtualAddress: 0x4000
|
||||
+SECTIONS-NEXT: RawDataSize: 512
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS-NEXT: Number: 5
|
||||
+SECTIONS-NEXT: Name: .gnu_debuglink
|
||||
+SECTIONS-NEXT: VirtualSize: 0x2C
|
||||
+SECTIONS-NEXT: VirtualAddress: 0x5000
|
||||
+SECTIONS-NEXT: RawDataSize: 512
|
||||
+SECTIONS-NEXT: PointerToRawData:
|
||||
+SECTIONS-NEXT: PointerToRelocations:
|
||||
+SECTIONS-NEXT: PointerToLineNumbers:
|
||||
+SECTIONS-NEXT: RelocationCount:
|
||||
+SECTIONS-NEXT: LineNumberCount:
|
||||
+SECTIONS-NEXT: Characteristics [ (0x42000040)
|
||||
+SECTIONS-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
|
||||
+SECTIONS-NEXT: IMAGE_SCN_MEM_DISCARDABLE (0x2000000)
|
||||
+SECTIONS-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
|
||||
+SECTIONS-NEXT: ]
|
||||
+
|
||||
+# Note: The last 4 bytes here are the crc of the referenced file - if the
|
||||
+# yaml2obj generated file changes, this crc changes.
|
||||
+
|
||||
+CONTENTS: Contents of section .gnu_debuglink:
|
||||
+CONTENTS: 40005000 6164642d 676e752d 64656275 676c696e add-gnu-debuglin
|
||||
+CONTENTS: 40005010 6b2e7465 73742e74 6d702e69 6e313233 k.test.tmp.in123
|
||||
+CONTENTS: 40005020 2e657865 00000000 7929adc3 .exe
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index 8d8f53d13d8..20adbe11e7a 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
+#include "llvm/Support/JamCRC.h"
|
||||
+#include "llvm/Support/Path.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
@@ -30,6 +32,61 @@ static bool isDebugSection(const Section &Sec) {
|
||||
return Sec.Name.startswith(".debug");
|
||||
}
|
||||
|
||||
+static uint64_t getNextRVA(const Object &Obj) {
|
||||
+ if (Obj.getSections().empty())
|
||||
+ return 0;
|
||||
+ const Section &Last = Obj.getSections().back();
|
||||
+ return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
|
||||
+ Obj.PeHeader.SectionAlignment);
|
||||
+}
|
||||
+
|
||||
+static uint32_t getCRC32(StringRef Data) {
|
||||
+ JamCRC CRC;
|
||||
+ CRC.update(ArrayRef<char>(Data.data(), Data.size()));
|
||||
+ // The CRC32 value needs to be complemented because the JamCRC dosn't
|
||||
+ // finalize the CRC32 value. It also dosn't negate the initial CRC32 value
|
||||
+ // but it starts by default at 0xFFFFFFFF which is the complement of zero.
|
||||
+ return ~CRC.getCRC();
|
||||
+}
|
||||
+
|
||||
+static std::vector<uint8_t> createGnuDebugLinkSectionContents(StringRef File) {
|
||||
+ ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
|
||||
+ MemoryBuffer::getFile(File);
|
||||
+ if (!LinkTargetOrErr)
|
||||
+ error("'" + File + "': " + LinkTargetOrErr.getError().message());
|
||||
+ auto LinkTarget = std::move(*LinkTargetOrErr);
|
||||
+ uint32_t CRC32 = getCRC32(LinkTarget->getBuffer());
|
||||
+
|
||||
+ StringRef FileName = sys::path::filename(File);
|
||||
+ size_t CRCPos = alignTo(FileName.size() + 1, 4);
|
||||
+ std::vector<uint8_t> Data(CRCPos + 4);
|
||||
+ memcpy(Data.data(), FileName.data(), FileName.size());
|
||||
+ support::endian::write32le(Data.data() + CRCPos, CRC32);
|
||||
+ return Data;
|
||||
+}
|
||||
+
|
||||
+static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
|
||||
+ uint32_t StartRVA = getNextRVA(Obj);
|
||||
+
|
||||
+ std::vector<Section> Sections;
|
||||
+ Section Sec;
|
||||
+ Sec.setOwnedContents(createGnuDebugLinkSectionContents(DebugLinkFile));
|
||||
+ Sec.Name = ".gnu_debuglink";
|
||||
+ Sec.Header.VirtualSize = Sec.getContents().size();
|
||||
+ Sec.Header.VirtualAddress = StartRVA;
|
||||
+ Sec.Header.SizeOfRawData =
|
||||
+ alignTo(Sec.Header.VirtualSize, Obj.PeHeader.FileAlignment);
|
||||
+ // Sec.Header.PointerToRawData is filled in by the writer.
|
||||
+ Sec.Header.PointerToRelocations = 0;
|
||||
+ Sec.Header.PointerToLinenumbers = 0;
|
||||
+ // Sec.Header.NumberOfRelocations is filled in by the writer.
|
||||
+ Sec.Header.NumberOfLinenumbers = 0;
|
||||
+ Sec.Header.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
|
||||
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE;
|
||||
+ Sections.push_back(Sec);
|
||||
+ Obj.addSections(Sections);
|
||||
+}
|
||||
+
|
||||
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
// Perform the actual section removals.
|
||||
Obj.removeSections([&Config](const Section &Sec) {
|
||||
@@ -109,6 +166,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
|
||||
return false;
|
||||
});
|
||||
+
|
||||
+ if (!Config.AddGnuDebugLink.empty())
|
||||
+ addGnuDebugLink(Obj, Config.AddGnuDebugLink);
|
||||
+
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.cpp b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
index 83435dffa98..8c382c1faef 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
@@ -129,7 +129,7 @@ void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
|
||||
void Object::truncateSections(function_ref<bool(const Section &)> ToTruncate) {
|
||||
for (Section &Sec : Sections) {
|
||||
if (ToTruncate(Sec)) {
|
||||
- Sec.Contents = ArrayRef<uint8_t>();
|
||||
+ Sec.clearContents();
|
||||
Sec.Relocs.clear();
|
||||
Sec.Header.SizeOfRawData = 0;
|
||||
}
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
index 0630f9c5ff8..afa272286ef 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
@@ -35,11 +35,35 @@ struct Relocation {
|
||||
|
||||
struct Section {
|
||||
object::coff_section Header;
|
||||
- ArrayRef<uint8_t> Contents;
|
||||
std::vector<Relocation> Relocs;
|
||||
StringRef Name;
|
||||
ssize_t UniqueId;
|
||||
size_t Index;
|
||||
+
|
||||
+ ArrayRef<uint8_t> getContents() const {
|
||||
+ if (!OwnedContents.empty())
|
||||
+ return OwnedContents;
|
||||
+ return ContentsRef;
|
||||
+ }
|
||||
+
|
||||
+ void setContentsRef(ArrayRef<uint8_t> Data) {
|
||||
+ OwnedContents.clear();
|
||||
+ ContentsRef = Data;
|
||||
+ }
|
||||
+
|
||||
+ void setOwnedContents(std::vector<uint8_t> &&Data) {
|
||||
+ ContentsRef = ArrayRef<uint8_t>();
|
||||
+ OwnedContents = std::move(Data);
|
||||
+ }
|
||||
+
|
||||
+ void clearContents() {
|
||||
+ ContentsRef = ArrayRef<uint8_t>();
|
||||
+ OwnedContents.clear();
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+ ArrayRef<uint8_t> ContentsRef;
|
||||
+ std::vector<uint8_t> OwnedContents;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
index 2446277cc2b..87dd60a43cf 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
@@ -69,8 +69,10 @@ Error COFFReader::readSections(Object &Obj) const {
|
||||
Sections.push_back(Section());
|
||||
Section &S = Sections.back();
|
||||
S.Header = *Sec;
|
||||
- if (auto EC = COFFObj.getSectionContents(Sec, S.Contents))
|
||||
+ ArrayRef<uint8_t> Contents;
|
||||
+ if (auto EC = COFFObj.getSectionContents(Sec, Contents))
|
||||
return errorCodeToError(EC);
|
||||
+ S.setContentsRef(Contents);
|
||||
ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
|
||||
for (const coff_relocation &R : Relocs)
|
||||
S.Relocs.push_back(R);
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
index db3589bb119..05e46291c39 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
@@ -286,14 +286,15 @@ void COFFWriter::writeHeaders(bool IsBigObj) {
|
||||
void COFFWriter::writeSections() {
|
||||
for (const auto &S : Obj.getSections()) {
|
||||
uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
|
||||
- std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
|
||||
+ ArrayRef<uint8_t> Contents = S.getContents();
|
||||
+ std::copy(Contents.begin(), Contents.end(), Ptr);
|
||||
|
||||
// For executable sections, pad the remainder of the raw data size with
|
||||
// 0xcc, which is int3 on x86.
|
||||
if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
|
||||
- S.Header.SizeOfRawData > S.Contents.size())
|
||||
- memset(Ptr + S.Contents.size(), 0xcc,
|
||||
- S.Header.SizeOfRawData - S.Contents.size());
|
||||
+ S.Header.SizeOfRawData > Contents.size())
|
||||
+ memset(Ptr + Contents.size(), 0xcc,
|
||||
+ S.Header.SizeOfRawData - Contents.size());
|
||||
|
||||
Ptr += S.Header.SizeOfRawData;
|
||||
for (const auto &R : S.Relocs) {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,665 @@
|
||||
From 2ccafacb7ddd740054dbee06655749ebc55a4d86 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Sat, 19 Jan 2019 19:42:35 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Add support for removing sections
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D56683
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351660 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../llvm-objcopy/COFF/remove-section.test | 210 ++++++++++++++++++
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 10 +-
|
||||
tools/llvm-objcopy/COFF/Object.cpp | 63 ++++++
|
||||
tools/llvm-objcopy/COFF/Object.h | 27 ++-
|
||||
tools/llvm-objcopy/COFF/Reader.cpp | 31 ++-
|
||||
tools/llvm-objcopy/COFF/Writer.cpp | 68 ++++--
|
||||
tools/llvm-objcopy/COFF/Writer.h | 1 +
|
||||
7 files changed, 391 insertions(+), 19 deletions(-)
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/remove-section.test
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/remove-section.test b/llvm/test/tools/llvm-objcopy/COFF/remove-section.test
|
||||
new file mode 100644
|
||||
index 00000000000..b3dfb0b98cb
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/remove-section.test
|
||||
@@ -0,0 +1,210 @@
|
||||
+# RUN: yaml2obj %s > %t.in.o
|
||||
+#
|
||||
+# RUN: llvm-objdump -section-headers %t.in.o | FileCheck %s --check-prefixes=SECTIONS-PRE
|
||||
+# RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS-PRE
|
||||
+#
|
||||
+# RUN: llvm-objcopy -R .bss %t.in.o %t.remove-bss.o
|
||||
+# RUN: llvm-objdump -section-headers %t.remove-bss.o | FileCheck %s --check-prefix=SECTIONS-REMOVE-BSS
|
||||
+# RUN: llvm-objdump -t %t.remove-bss.o | FileCheck %s --check-prefix=SYMBOLS-REMOVE-BSS
|
||||
+#
|
||||
+# RUN: llvm-objcopy --remove-section .bss %t.in.o %t.cmp.o
|
||||
+# RUN: cmp %t.remove-bss.o %t.cmp.o
|
||||
+#
|
||||
+# RUN: llvm-objcopy -R .text %t.in.o %t.remove-text.o
|
||||
+# RUN: llvm-objdump -section-headers %t.remove-text.o | FileCheck %s --check-prefix=SECTIONS-REMOVE-TEXT
|
||||
+# RUN: llvm-objdump -t %t.remove-text.o | FileCheck %s --check-prefix=SYMBOLS-REMOVE-TEXT
|
||||
+#
|
||||
+# RUN: not llvm-objcopy -R .comdat %t.in.o %t.remove-comdat.o 2>&1 | FileCheck %s --check-prefix=ERROR-RELOC
|
||||
+#
|
||||
+# RUN: llvm-objcopy -R .text -R .comdat %t.in.o %t.remove-text-comdat.o
|
||||
+# RUN: llvm-objdump -section-headers %t.remove-text-comdat.o | FileCheck %s --check-prefix=SECTIONS-REMOVE-TEXT-COMDAT
|
||||
+# RUN: llvm-objdump -t %t.remove-text-comdat.o | FileCheck %s --check-prefix=SYMBOLS-REMOVE-TEXT-COMDAT
|
||||
+#
|
||||
+#
|
||||
+# SECTIONS-PRE: Sections:
|
||||
+# SECTIONS-PRE-NEXT: Idx Name
|
||||
+# SECTIONS-PRE-NEXT: 0 .text
|
||||
+# SECTIONS-PRE-NEXT: 1 .bss
|
||||
+# SECTIONS-PRE-NEXT: 2 .comdat
|
||||
+# SECTIONS-PRE-NEXT: 3 .associative
|
||||
+# SECTIONS-PRE-EMPTY:
|
||||
+#
|
||||
+# SYMBOLS-PRE: SYMBOL TABLE:
|
||||
+# SYMBOLS-PRE-NEXT: {{.*}}(sec -1){{.*}} @feat.00
|
||||
+# SYMBOLS-PRE-NEXT: {{.*}}(sec 1){{.*}} .text
|
||||
+# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
|
||||
+# SYMBOLS-PRE-NEXT: {{.*}}(sec 2){{.*}} .bss
|
||||
+# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 2 comdat 0
|
||||
+# SYMBOLS-PRE-NEXT: {{.*}}(sec 4){{.*}} .associative
|
||||
+# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 3 comdat 5
|
||||
+# SYMBOLS-PRE-NEXT: {{.*}}(sec 3){{.*}} .comdat
|
||||
+# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 3 comdat 2
|
||||
+# SYMBOLS-PRE-NEXT: {{.*}}(sec 3){{.*}} foo
|
||||
+# SYMBOLS-PRE-NEXT: {{.*}}(sec 1){{.*}} main
|
||||
+# SYMBOLS-PRE-EMPTY:
|
||||
+#
|
||||
+#
|
||||
+# Removing the .bss section removes one symbol and its aux symbol,
|
||||
+# and updates the section indices in symbols pointing to later
|
||||
+# symbols, including the aux section defintitions.
|
||||
+#
|
||||
+# Testing that the absolute symbol @feat.00 survives the section number
|
||||
+# mangling.
|
||||
+#
|
||||
+# SECTIONS-REMOVE-BSS: Sections:
|
||||
+# SECTIONS-REMOVE-BSS-NEXT: Idx Name
|
||||
+# SECTIONS-REMOVE-BSS-NEXT: 0 .text
|
||||
+# SECTIONS-REMOVE-BSS-NEXT: 1 .comdat
|
||||
+# SECTIONS-REMOVE-BSS-NEXT: 2 .associative
|
||||
+# SECTIONS-REMOVE-BSS-EMPTY:
|
||||
+#
|
||||
+# SYMBOLS-REMOVE-BSS: SYMBOL TABLE:
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec -1){{.*}} @feat.00
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 1){{.*}} .text
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 3){{.*}} .associative
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: AUX scnlen {{.*}} assoc 2 comdat 5
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 2){{.*}} .comdat
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: AUX scnlen {{.*}} assoc 2 comdat 2
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 2){{.*}} foo
|
||||
+# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 1){{.*}} main
|
||||
+# SYMBOLS-REMOVE-BSS-EMPTY:
|
||||
+#
|
||||
+#
|
||||
+# Removing the .text section is ok and just removes the external symbol
|
||||
+# referring to it.
|
||||
+#
|
||||
+# SECTIONS-REMOVE-TEXT: Sections:
|
||||
+# SECTIONS-REMOVE-TEXT-NEXT: Idx Name
|
||||
+# SECTIONS-REMOVE-TEXT-NEXT: 0 .bss
|
||||
+# SECTIONS-REMOVE-TEXT-NEXT: 1 .comdat
|
||||
+# SECTIONS-REMOVE-TEXT-NEXT: 2 .associative
|
||||
+# SECTIONS-REMOVE-TEXT-EMPTY:
|
||||
+#
|
||||
+# SYMBOLS-REMOVE-TEXT: SYMBOL TABLE:
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec -1){{.*}} @feat.00
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 1){{.*}} .bss
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 3){{.*}} .associative
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: AUX scnlen {{.*}} assoc 2 comdat 5
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 2){{.*}} .comdat
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: AUX scnlen {{.*}} assoc 2 comdat 2
|
||||
+# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 2){{.*}} foo
|
||||
+# SYMBOLS-REMOVE-TEXT-EMPTY:
|
||||
+#
|
||||
+#
|
||||
+# Removing the .comdat section fails, since the .text section has relocations
|
||||
+# against it.
|
||||
+#
|
||||
+# ERROR-RELOC: Relocation target foo ({{.*}}) not found
|
||||
+#
|
||||
+#
|
||||
+# Removing the .comdat section and .text (with a relocation against .comdat)
|
||||
+# works, as it also removes the .associative section transitively.
|
||||
+#
|
||||
+# SECTIONS-REMOVE-TEXT-COMDAT: Sections:
|
||||
+# SECTIONS-REMOVE-TEXT-COMDAT-NEXT: Idx Name
|
||||
+# SECTIONS-REMOVE-TEXT-COMDAT-NEXT: 0 .bss
|
||||
+# SECTIONS-REMOVE-TEXT-COMDAT-EMPTY:
|
||||
+#
|
||||
+# SYMBOLS-REMOVE-TEXT-COMDAT: SYMBOL TABLE:
|
||||
+# SYMBOLS-REMOVE-TEXT-COMDAT-NEXT: {{.*}}(sec -1){{.*}} @feat.00
|
||||
+# SYMBOLS-REMOVE-TEXT-COMDAT-NEXT: {{.*}}(sec 1){{.*}} .bss
|
||||
+# SYMBOLS-REMOVE-TEXT-COMDAT-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
|
||||
+# SYMBOLS-REMOVE-TEXT-COMDAT-EMPTY:
|
||||
+
|
||||
+--- !COFF
|
||||
+header:
|
||||
+ Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
+ Characteristics: [ ]
|
||||
+sections:
|
||||
+ - Name: .text
|
||||
+ Characteristics: [ ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 488B0500000000C3
|
||||
+ Relocations:
|
||||
+ - VirtualAddress: 3
|
||||
+ SymbolName: foo
|
||||
+ Type: IMAGE_REL_AMD64_REL32
|
||||
+ - Name: .bss
|
||||
+ Characteristics: [ ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: ''
|
||||
+ - Name: .comdat
|
||||
+ Characteristics: [ IMAGE_SCN_LNK_COMDAT ]
|
||||
+ Alignment: 1
|
||||
+ SectionData: '2A000000'
|
||||
+ - Name: .associative
|
||||
+ Characteristics: [ IMAGE_SCN_LNK_COMDAT ]
|
||||
+ Alignment: 1
|
||||
+ SectionData: '0000000000000000'
|
||||
+symbols:
|
||||
+ - Name: '@feat.00'
|
||||
+ Value: 0
|
||||
+ SectionNumber: -1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
+ - Name: .text
|
||||
+ Value: 0
|
||||
+ SectionNumber: 1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
+ SectionDefinition:
|
||||
+ Length: 8
|
||||
+ NumberOfRelocations: 1
|
||||
+ NumberOfLinenumbers: 0
|
||||
+ CheckSum: 583624169
|
||||
+ Number: 1
|
||||
+ - Name: .bss
|
||||
+ Value: 0
|
||||
+ SectionNumber: 2
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
+ SectionDefinition:
|
||||
+ Length: 0
|
||||
+ NumberOfRelocations: 0
|
||||
+ NumberOfLinenumbers: 0
|
||||
+ CheckSum: 0
|
||||
+ Number: 2
|
||||
+ - Name: .associative
|
||||
+ Value: 0
|
||||
+ SectionNumber: 4
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
+ SectionDefinition:
|
||||
+ Length: 8
|
||||
+ NumberOfRelocations: 0
|
||||
+ NumberOfLinenumbers: 0
|
||||
+ CheckSum: 0
|
||||
+ Number: 3
|
||||
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
|
||||
+ - Name: .comdat
|
||||
+ Value: 0
|
||||
+ SectionNumber: 3
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
+ SectionDefinition:
|
||||
+ Length: 4
|
||||
+ NumberOfRelocations: 0
|
||||
+ NumberOfLinenumbers: 0
|
||||
+ CheckSum: 3482275674
|
||||
+ Number: 3
|
||||
+ Selection: IMAGE_COMDAT_SELECT_ANY
|
||||
+ - Name: foo
|
||||
+ Value: 0
|
||||
+ SectionNumber: 3
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+ - Name: main
|
||||
+ Value: 0
|
||||
+ SectionNumber: 1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+...
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index 437dccbd3d5..dd2e4829218 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -27,9 +27,17 @@ using namespace object;
|
||||
using namespace COFF;
|
||||
|
||||
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
+ // Perform the actual section removals.
|
||||
+ Obj.removeSections([&Config](const Section &Sec) {
|
||||
+ if (is_contained(Config.ToRemove, Sec.Name))
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+ });
|
||||
+
|
||||
// StripAll removes all symbols and thus also removes all relocations.
|
||||
if (Config.StripAll || Config.StripAllGNU)
|
||||
- for (Section &Sec : Obj.Sections)
|
||||
+ for (Section &Sec : Obj.getMutableSections())
|
||||
Sec.Relocs.clear();
|
||||
|
||||
// If we need to do per-symbol removals, initialize the Referenced field.
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.cpp b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
index e58e161e7d2..e19cea6aa9d 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
@@ -7,6 +7,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Object.h"
|
||||
+#include "llvm/ADT/DenseSet.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace llvm {
|
||||
@@ -64,6 +65,68 @@ Error Object::markSymbols() {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
+void Object::addSections(ArrayRef<Section> NewSections) {
|
||||
+ for (Section S : NewSections) {
|
||||
+ S.UniqueId = NextSectionUniqueId++;
|
||||
+ Sections.emplace_back(S);
|
||||
+ }
|
||||
+ updateSections();
|
||||
+}
|
||||
+
|
||||
+void Object::updateSections() {
|
||||
+ SectionMap = DenseMap<ssize_t, Section *>(Sections.size());
|
||||
+ size_t Index = 1;
|
||||
+ for (Section &S : Sections) {
|
||||
+ SectionMap[S.UniqueId] = &S;
|
||||
+ S.Index = Index++;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+const Section *Object::findSection(ssize_t UniqueId) const {
|
||||
+ auto It = SectionMap.find(UniqueId);
|
||||
+ if (It == SectionMap.end())
|
||||
+ return nullptr;
|
||||
+ return It->second;
|
||||
+}
|
||||
+
|
||||
+void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
|
||||
+ DenseSet<ssize_t> AssociatedSections;
|
||||
+ auto RemoveAssociated = [&AssociatedSections](const Section &Sec) {
|
||||
+ return AssociatedSections.count(Sec.UniqueId) == 1;
|
||||
+ };
|
||||
+ do {
|
||||
+ DenseSet<ssize_t> RemovedSections;
|
||||
+ Sections.erase(
|
||||
+ std::remove_if(std::begin(Sections), std::end(Sections),
|
||||
+ [ToRemove, &RemovedSections](const Section &Sec) {
|
||||
+ bool Remove = ToRemove(Sec);
|
||||
+ if (Remove)
|
||||
+ RemovedSections.insert(Sec.UniqueId);
|
||||
+ return Remove;
|
||||
+ }),
|
||||
+ std::end(Sections));
|
||||
+ // Remove all symbols referring to the removed sections.
|
||||
+ AssociatedSections.clear();
|
||||
+ Symbols.erase(
|
||||
+ std::remove_if(
|
||||
+ std::begin(Symbols), std::end(Symbols),
|
||||
+ [&RemovedSections, &AssociatedSections](const Symbol &Sym) {
|
||||
+ // If there are sections that are associative to a removed
|
||||
+ // section,
|
||||
+ // remove those as well as nothing will include them (and we can't
|
||||
+ // leave them dangling).
|
||||
+ if (RemovedSections.count(Sym.AssociativeComdatTargetSectionId) ==
|
||||
+ 1)
|
||||
+ AssociatedSections.insert(Sym.TargetSectionId);
|
||||
+ return RemovedSections.count(Sym.TargetSectionId) == 1;
|
||||
+ }),
|
||||
+ std::end(Symbols));
|
||||
+ ToRemove = RemoveAssociated;
|
||||
+ } while (!AssociatedSections.empty());
|
||||
+ updateSections();
|
||||
+ updateSymbols();
|
||||
+}
|
||||
+
|
||||
} // end namespace coff
|
||||
} // end namespace objcopy
|
||||
} // end namespace llvm
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
index e6147c40b7c..a73e93620d3 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
@@ -37,12 +37,16 @@ struct Section {
|
||||
ArrayRef<uint8_t> Contents;
|
||||
std::vector<Relocation> Relocs;
|
||||
StringRef Name;
|
||||
+ ssize_t UniqueId;
|
||||
+ size_t Index;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
object::coff_symbol32 Sym;
|
||||
StringRef Name;
|
||||
- ArrayRef<uint8_t> AuxData;
|
||||
+ std::vector<uint8_t> AuxData;
|
||||
+ ssize_t TargetSectionId;
|
||||
+ ssize_t AssociativeComdatTargetSectionId = 0;
|
||||
size_t UniqueId;
|
||||
size_t RawIndex;
|
||||
bool Referenced;
|
||||
@@ -61,7 +65,6 @@ struct Object {
|
||||
uint32_t BaseOfData = 0; // pe32plus_header lacks this field.
|
||||
|
||||
std::vector<object::data_directory> DataDirectories;
|
||||
- std::vector<Section> Sections;
|
||||
|
||||
ArrayRef<Symbol> getSymbols() const { return Symbols; }
|
||||
// This allows mutating individual Symbols, but not mutating the list
|
||||
@@ -79,14 +82,34 @@ struct Object {
|
||||
// all sections.
|
||||
Error markSymbols();
|
||||
|
||||
+ ArrayRef<Section> getSections() const { return Sections; }
|
||||
+ // This allows mutating individual Sections, but not mutating the list
|
||||
+ // of symbols itself.
|
||||
+ iterator_range<std::vector<Section>::iterator> getMutableSections() {
|
||||
+ return make_range(Sections.begin(), Sections.end());
|
||||
+ }
|
||||
+
|
||||
+ const Section *findSection(ssize_t UniqueId) const;
|
||||
+
|
||||
+ void addSections(ArrayRef<Section> NewSections);
|
||||
+ void removeSections(function_ref<bool(const Section &)> ToRemove);
|
||||
+
|
||||
private:
|
||||
std::vector<Symbol> Symbols;
|
||||
DenseMap<size_t, Symbol *> SymbolMap;
|
||||
|
||||
size_t NextSymbolUniqueId = 0;
|
||||
|
||||
+ std::vector<Section> Sections;
|
||||
+ DenseMap<ssize_t, Section *> SectionMap;
|
||||
+
|
||||
+ ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.
|
||||
+
|
||||
// Update SymbolMap and RawIndex in each Symbol.
|
||||
void updateSymbols();
|
||||
+
|
||||
+ // Update SectionMap and Index in each Section.
|
||||
+ void updateSections();
|
||||
};
|
||||
|
||||
// Copy between coff_symbol16 and coff_symbol32.
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
index d794042ae24..c8abe2913a2 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "llvm-objcopy.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
+#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cstddef>
|
||||
@@ -21,6 +22,7 @@ namespace objcopy {
|
||||
namespace coff {
|
||||
|
||||
using namespace object;
|
||||
+using namespace COFF;
|
||||
|
||||
Error COFFReader::readExecutableHeaders(Object &Obj) const {
|
||||
const dos_header *DH = COFFObj.getDOSHeader();
|
||||
@@ -58,13 +60,14 @@ Error COFFReader::readExecutableHeaders(Object &Obj) const {
|
||||
}
|
||||
|
||||
Error COFFReader::readSections(Object &Obj) const {
|
||||
+ std::vector<Section> Sections;
|
||||
// Section indexing starts from 1.
|
||||
for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
|
||||
const coff_section *Sec;
|
||||
if (auto EC = COFFObj.getSection(I, Sec))
|
||||
return errorCodeToError(EC);
|
||||
- Obj.Sections.push_back(Section());
|
||||
- Section &S = Obj.Sections.back();
|
||||
+ Sections.push_back(Section());
|
||||
+ Section &S = Sections.back();
|
||||
S.Header = *Sec;
|
||||
if (auto EC = COFFObj.getSectionContents(Sec, S.Contents))
|
||||
return errorCodeToError(EC);
|
||||
@@ -77,12 +80,14 @@ Error COFFReader::readSections(Object &Obj) const {
|
||||
return make_error<StringError>("Extended relocations not supported yet",
|
||||
object_error::parse_failed);
|
||||
}
|
||||
+ Obj.addSections(Sections);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
|
||||
std::vector<Symbol> Symbols;
|
||||
Symbols.reserve(COFFObj.getRawNumberOfSymbols());
|
||||
+ ArrayRef<Section> Sections = Obj.getSections();
|
||||
for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
|
||||
Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
|
||||
if (!SymOrErr)
|
||||
@@ -103,6 +108,26 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
|
||||
Sym.AuxData = COFFObj.getSymbolAuxData(SymRef);
|
||||
assert((Sym.AuxData.size() %
|
||||
(IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0);
|
||||
+ // Find the unique id of the section
|
||||
+ if (SymRef.getSectionNumber() <=
|
||||
+ 0) // Special symbol (undefined/absolute/debug)
|
||||
+ Sym.TargetSectionId = SymRef.getSectionNumber();
|
||||
+ else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
|
||||
+ Sections.size())
|
||||
+ Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
|
||||
+ else
|
||||
+ return make_error<StringError>("Section number out of range",
|
||||
+ object_error::parse_failed);
|
||||
+ // For section definitions, check if it is comdat associative, and if
|
||||
+ // it is, find the target section unique id.
|
||||
+ const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
|
||||
+ if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
|
||||
+ int32_t Index = SD->getNumber(IsBigObj);
|
||||
+ if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
|
||||
+ return make_error<StringError>("Unexpected associative section index",
|
||||
+ object_error::parse_failed);
|
||||
+ Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
|
||||
+ }
|
||||
I += 1 + SymRef.getNumberOfAuxSymbols();
|
||||
}
|
||||
Obj.addSymbols(Symbols);
|
||||
@@ -116,7 +141,7 @@ Error COFFReader::setRelocTargets(Object &Obj) const {
|
||||
for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
|
||||
RawSymbolTable.push_back(nullptr);
|
||||
}
|
||||
- for (Section &Sec : Obj.Sections) {
|
||||
+ for (Section &Sec : Obj.getMutableSections()) {
|
||||
for (Relocation &R : Sec.Relocs) {
|
||||
if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
|
||||
return make_error<StringError>("SymbolTableIndex out of range",
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
index c347810dd24..9fb7812672b 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
@@ -25,7 +25,7 @@ using namespace object;
|
||||
using namespace COFF;
|
||||
|
||||
Error COFFWriter::finalizeRelocTargets() {
|
||||
- for (Section &Sec : Obj.Sections) {
|
||||
+ for (Section &Sec : Obj.getMutableSections()) {
|
||||
for (Relocation &R : Sec.Relocs) {
|
||||
const Symbol *Sym = Obj.findSymbol(R.Target);
|
||||
if (Sym == nullptr)
|
||||
@@ -39,8 +39,48 @@ Error COFFWriter::finalizeRelocTargets() {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
+Error COFFWriter::finalizeSectionNumbers() {
|
||||
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
|
||||
+ if (Sym.TargetSectionId <= 0) {
|
||||
+ // Undefined, or a special kind of symbol. These negative values
|
||||
+ // are stored in the SectionNumber field which is unsigned.
|
||||
+ Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId);
|
||||
+ } else {
|
||||
+ const Section *Sec = Obj.findSection(Sym.TargetSectionId);
|
||||
+ if (Sec == nullptr)
|
||||
+ return make_error<StringError>("Symbol " + Sym.Name +
|
||||
+ " points to a removed section",
|
||||
+ object_error::invalid_symbol_index);
|
||||
+ Sym.Sym.SectionNumber = Sec->Index;
|
||||
+
|
||||
+ if (Sym.Sym.NumberOfAuxSymbols == 1 &&
|
||||
+ Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
|
||||
+ coff_aux_section_definition *SD =
|
||||
+ reinterpret_cast<coff_aux_section_definition *>(Sym.AuxData.data());
|
||||
+ uint32_t SDSectionNumber;
|
||||
+ if (Sym.AssociativeComdatTargetSectionId == 0) {
|
||||
+ // Not a comdat associative section; just set the Number field to
|
||||
+ // the number of the section itself.
|
||||
+ SDSectionNumber = Sec->Index;
|
||||
+ } else {
|
||||
+ Sec = Obj.findSection(Sym.AssociativeComdatTargetSectionId);
|
||||
+ if (Sec == nullptr)
|
||||
+ return make_error<StringError>(
|
||||
+ "Symbol " + Sym.Name + " is associative to a removed section",
|
||||
+ object_error::invalid_symbol_index);
|
||||
+ SDSectionNumber = Sec->Index;
|
||||
+ }
|
||||
+ // Update the section definition with the new section number.
|
||||
+ SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber);
|
||||
+ SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return Error::success();
|
||||
+}
|
||||
+
|
||||
void COFFWriter::layoutSections() {
|
||||
- for (auto &S : Obj.Sections) {
|
||||
+ for (auto &S : Obj.getMutableSections()) {
|
||||
if (S.Header.SizeOfRawData > 0)
|
||||
S.Header.PointerToRawData = FileSize;
|
||||
FileSize += S.Header.SizeOfRawData; // For executables, this is already
|
||||
@@ -57,7 +97,7 @@ void COFFWriter::layoutSections() {
|
||||
}
|
||||
|
||||
size_t COFFWriter::finalizeStringTable() {
|
||||
- for (auto &S : Obj.Sections)
|
||||
+ for (const auto &S : Obj.getSections())
|
||||
if (S.Name.size() > COFF::NameSize)
|
||||
StrTabBuilder.add(S.Name);
|
||||
|
||||
@@ -67,7 +107,7 @@ size_t COFFWriter::finalizeStringTable() {
|
||||
|
||||
StrTabBuilder.finalize();
|
||||
|
||||
- for (auto &S : Obj.Sections) {
|
||||
+ for (auto &S : Obj.getMutableSections()) {
|
||||
if (S.Name.size() > COFF::NameSize) {
|
||||
snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
|
||||
(int)StrTabBuilder.getOffset(S.Name));
|
||||
@@ -97,6 +137,8 @@ std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
|
||||
Error COFFWriter::finalize(bool IsBigObj) {
|
||||
if (Error E = finalizeRelocTargets())
|
||||
return E;
|
||||
+ if (Error E = finalizeSectionNumbers())
|
||||
+ return E;
|
||||
|
||||
size_t SizeOfHeaders = 0;
|
||||
FileAlignment = 1;
|
||||
@@ -113,10 +155,10 @@ Error COFFWriter::finalize(bool IsBigObj) {
|
||||
SizeOfHeaders +=
|
||||
PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
|
||||
}
|
||||
- Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size();
|
||||
+ Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size();
|
||||
SizeOfHeaders +=
|
||||
IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
|
||||
- SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size();
|
||||
+ SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size();
|
||||
SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
|
||||
|
||||
Obj.CoffFileHeader.SizeOfOptionalHeader =
|
||||
@@ -131,8 +173,8 @@ Error COFFWriter::finalize(bool IsBigObj) {
|
||||
Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
|
||||
Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
|
||||
|
||||
- if (!Obj.Sections.empty()) {
|
||||
- const Section &S = Obj.Sections.back();
|
||||
+ if (!Obj.getSections().empty()) {
|
||||
+ const Section &S = Obj.getSections().back();
|
||||
Obj.PeHeader.SizeOfImage =
|
||||
alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
|
||||
Obj.PeHeader.SectionAlignment);
|
||||
@@ -198,7 +240,7 @@ void COFFWriter::writeHeaders(bool IsBigObj) {
|
||||
BigObjHeader.unused4 = 0;
|
||||
// The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
|
||||
// get the original one instead.
|
||||
- BigObjHeader.NumberOfSections = Obj.Sections.size();
|
||||
+ BigObjHeader.NumberOfSections = Obj.getSections().size();
|
||||
BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
|
||||
BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
|
||||
|
||||
@@ -223,14 +265,14 @@ void COFFWriter::writeHeaders(bool IsBigObj) {
|
||||
Ptr += sizeof(DD);
|
||||
}
|
||||
}
|
||||
- for (const auto &S : Obj.Sections) {
|
||||
+ for (const auto &S : Obj.getSections()) {
|
||||
memcpy(Ptr, &S.Header, sizeof(S.Header));
|
||||
Ptr += sizeof(S.Header);
|
||||
}
|
||||
}
|
||||
|
||||
void COFFWriter::writeSections() {
|
||||
- for (const auto &S : Obj.Sections) {
|
||||
+ for (const auto &S : Obj.getSections()) {
|
||||
uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
|
||||
std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
|
||||
|
||||
@@ -295,7 +337,7 @@ Error COFFWriter::patchDebugDirectory() {
|
||||
const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
|
||||
if (Dir->Size <= 0)
|
||||
return Error::success();
|
||||
- for (const auto &S : Obj.Sections) {
|
||||
+ for (const auto &S : Obj.getSections()) {
|
||||
if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
|
||||
Dir->RelativeVirtualAddress <
|
||||
S.Header.VirtualAddress + S.Header.SizeOfRawData) {
|
||||
@@ -324,7 +366,7 @@ Error COFFWriter::patchDebugDirectory() {
|
||||
}
|
||||
|
||||
Error COFFWriter::write() {
|
||||
- bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16;
|
||||
+ bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16;
|
||||
if (IsBigObj && Obj.IsPE)
|
||||
return make_error<StringError>("Too many sections for executable",
|
||||
object_error::parse_failed);
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.h b/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
index 52fef385926..a967a103df9 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
@@ -31,6 +31,7 @@ class COFFWriter {
|
||||
StringTableBuilder StrTabBuilder;
|
||||
|
||||
Error finalizeRelocTargets();
|
||||
+ Error finalizeSectionNumbers();
|
||||
void layoutSections();
|
||||
size_t finalizeStringTable();
|
||||
template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,28 @@
|
||||
From 1284ee3c47bab17ec081b5169633aea4f8abfd30 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Wed, 23 Jan 2019 09:12:53 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Clear the unwritten tail of
|
||||
coff_section::Header::Name
|
||||
|
||||
This should fix the add-gnu-debuglink test on all buildbots.
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351934 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
tools/llvm-objcopy/COFF/Writer.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
index 05e46291c39..db897e2ff33 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
@@ -121,6 +121,7 @@ size_t COFFWriter::finalizeStringTable() {
|
||||
|
||||
for (auto &S : Obj.getMutableSections()) {
|
||||
if (S.Name.size() > COFF::NameSize) {
|
||||
+ memset(S.Header.Name, 0, sizeof(S.Header.Name));
|
||||
snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
|
||||
(int)StrTabBuilder.getOffset(S.Name));
|
||||
} else {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,43 @@
|
||||
From abacd83232acf69d7cbacd53fc2f9aae66c1a32e Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Wed, 23 Jan 2019 11:54:55 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Error out on use of unhandled options
|
||||
|
||||
Prefer erroring out than silently not doing what was requested.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D57045
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351948 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 15 +++++++++++++++
|
||||
1 file changed, 15 insertions(+)
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index 64b4e79a4e0..b7b3d3cb629 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -170,6 +170,21 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
if (!Config.AddGnuDebugLink.empty())
|
||||
addGnuDebugLink(Obj, Config.AddGnuDebugLink);
|
||||
|
||||
+ if (!Config.BuildIdLinkDir.empty() || Config.BuildIdLinkInput ||
|
||||
+ Config.BuildIdLinkOutput || !Config.SplitDWO.empty() ||
|
||||
+ !Config.SymbolsPrefix.empty() || !Config.AddSection.empty() ||
|
||||
+ !Config.DumpSection.empty() || !Config.KeepSection.empty() ||
|
||||
+ !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
|
||||
+ !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
|
||||
+ !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
|
||||
+ !Config.SymbolsToRename.empty() || Config.ExtractDWO ||
|
||||
+ Config.KeepFileSymbols || Config.LocalizeHidden || Config.PreserveDates ||
|
||||
+ Config.StripDWO || Config.StripNonAlloc || Config.StripSections ||
|
||||
+ Config.Weaken || Config.DecompressDebugSections) {
|
||||
+ return createStringError(llvm::errc::invalid_argument,
|
||||
+ "Option not supported by llvm-objcopy for COFF");
|
||||
+ }
|
||||
+
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,377 @@
|
||||
From 74c7d422cba163635394ec32f2b243b1de502a18 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Wed, 23 Jan 2019 11:54:51 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Fix handling of aux symbols for big
|
||||
objects
|
||||
|
||||
The aux symbols were stored in an opaque std::vector<uint8_t>,
|
||||
with contents interpreted according to the rest of the symbol.
|
||||
|
||||
All aux symbol types but one fit in 18 bytes (sizeof(coff_symbol16)),
|
||||
and if written to a bigobj, two extra padding bytes are written (as
|
||||
sizeof(coff_symbol32) is 20). In the storage agnostic intermediate
|
||||
representation, store the aux symbols as a series of coff_symbol16
|
||||
sized opaque blobs. (In practice, all such aux symbols only consist
|
||||
of one aux symbol, so this is more flexible than what reality needs.)
|
||||
|
||||
The special case is the file aux symbols, which are written in
|
||||
potentially more than one aux symbol slot, without any padding,
|
||||
as one single long string. This can't be stored in the same opaque
|
||||
vector of fixed sized aux symbol entries. The file aux symbols will
|
||||
occupy a different number of aux symbol slots depending on the type
|
||||
of output object file. As nothing in the intermediate process needs
|
||||
to have accurate raw symbol indices, updating that is moved into the
|
||||
writer class.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D57009
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351947 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../llvm-objcopy/COFF/Inputs/bigobj.o.gz | Bin 0 -> 7841 bytes
|
||||
test/tools/llvm-objcopy/COFF/bigobj.test | 35 +++++++++++++
|
||||
.../llvm-objcopy/ELF/auto-remove-shndx.test | 2 +-
|
||||
.../tools/llvm-objcopy/ELF/many-sections.test | 2 +-
|
||||
test/tools/llvm-objcopy/ELF/remove-shndx.test | 2 +-
|
||||
.../tools/llvm-objcopy/ELF/strict-no-add.test | 2 +-
|
||||
.../llvm-objcopy/{ELF => }/Inputs/ungzip.py | 0
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 6 +--
|
||||
tools/llvm-objcopy/COFF/Object.cpp | 6 +--
|
||||
tools/llvm-objcopy/COFF/Object.h | 18 ++++++-
|
||||
tools/llvm-objcopy/COFF/Reader.cpp | 21 ++++++--
|
||||
tools/llvm-objcopy/COFF/Writer.cpp | 49 +++++++++++++-----
|
||||
tools/llvm-objcopy/COFF/Writer.h | 2 +-
|
||||
13 files changed, 115 insertions(+), 30 deletions(-)
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/Inputs/bigobj.o.gz
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/bigobj.test
|
||||
rename test/tools/llvm-objcopy/{ELF => }/Inputs/ungzip.py (100%)
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/Inputs/bigobj.o.gz b/llvm/test/tools/llvm-objcopy/COFF/Inputs/bigobj.o.gz
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6435f4785ff76e0c6bca12f3e57bc6ad8888bece
|
||||
GIT binary patch
|
||||
literal 7841
|
||||
zcmb2|=3r3v^@w3&etUMmo^zoH`-kGKM_vfJsF<z%6+Sz#g6qq)pf0Hj#_r`4B7DML
|
||||
zW(h1l`+!x)t@&W-R@I~lyKmU3Ti&1Z=iKur;uBMy1MR!_ywlsouYY&-*4H1mU!Qw=
|
||||
z`RpIDkw;!V4(WOF_)B3`(Vt|~S>?L-b)Wx@^wig`HIMAw|N8V<v65oeyETs611{)_
|
||||
zm27RwTe)ENN|7SLgM~83N6}~qjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mk
|
||||
zz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kgRokHNw|D97mKRo|%+Z6Ym
|
||||
z*X{Ku$4#4*Vqm}gyYR^b^Sc?_E*<<cFE#Q=*rt6OBmJeLZ=aoe_u9R>-w!^l5biDe
|
||||
p{d@nvw*mU6<NG83=jxn4_wt_G?yUy#YeOF~KhH^=cj<;Y0{~9Br>p<~
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/bigobj.test b/llvm/test/tools/llvm-objcopy/COFF/bigobj.test
|
||||
new file mode 100644
|
||||
index 00000000000..17968f12b8a
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/bigobj.test
|
||||
@@ -0,0 +1,35 @@
|
||||
+RUN: %python %p/../Inputs/ungzip.py %p/Inputs/bigobj.o.gz > %t.in.o
|
||||
+
|
||||
+RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-BIG,SYMBOLS-ORIG
|
||||
+
|
||||
+# Do a plain copy, to check that section numbers in symbols referring
|
||||
+# to sections outside of the small object format are handled correctly.
|
||||
+RUN: llvm-objcopy -R '.text$4' %t.in.o %t.small.o
|
||||
+RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-BIG,SYMBOLS-ORIG
|
||||
+
|
||||
+# Remove a section, making the section count fit into a small object.
|
||||
+RUN: llvm-objcopy -R '.text$4' %t.in.o %t.small.o
|
||||
+RUN: llvm-objdump -t %t.small.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-SMALL,SYMBOLS-REMOVED-SMALL
|
||||
+
|
||||
+# Add a .gnu_debuglink section, forcing the object back to big format.
|
||||
+RUN: llvm-objcopy --add-gnu-debuglink=%t.in.o %t.small.o %t.big.o
|
||||
+ llvm-objdump -t %t.big.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-BIG,SYMBOLS-REMOVED-BIG
|
||||
+
|
||||
+# In big object format, the .file symbol occupies one symbol table entry for
|
||||
+# the auxillary data, but needs two entries in the small format, forcing the
|
||||
+# raw symbol indices of later symbols to change.
|
||||
+SYMBOLS: SYMBOL TABLE:
|
||||
+SYMBOLS-NEXT: [ 0]{{.*}} (nx 1) {{.*}} .text
|
||||
+SYMBOLS-NEXT: AUX scnlen
|
||||
+SYMBOLS-SMALL-NEXT: [ 2]{{.*}} (nx 2) {{.*}} .file
|
||||
+SYMBOLS-BIG-NEXT: [ 2]{{.*}} (nx 1) {{.*}} .file
|
||||
+SYMBOLS-NEXT: AUX abcdefghijklmnopqrs
|
||||
+SYMBOLS-SMALL-NEXT: [ 5]{{.*}} (nx 0) {{.*}} foo
|
||||
+SYMBOLS-BIG-NEXT: [ 4]{{.*}} (nx 0) {{.*}} foo
|
||||
+
|
||||
+# Check that the section numbers outside of signed 16 bit int range
|
||||
+# are represented properly. After removing one section, the section
|
||||
+# numbers decrease.
|
||||
+SYMBOLS-ORIG: [ 5](sec 65280){{.*}} symbol65280
|
||||
+SYMBOLS-REMOVED-SMALL: [ 6](sec 65279){{.*}} symbol65280
|
||||
+SYMBOLS-REMOVED-BIG: [ 5](sec 65279){{.*}} symbol65280
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/ELF/auto-remove-shndx.test b/llvm/test/tools/llvm-objcopy/ELF/auto-remove-shndx.test
|
||||
index 5a23493fa94..8e6c788bf48 100644
|
||||
--- a/llvm/test/tools/llvm-objcopy/ELF/auto-remove-shndx.test
|
||||
+++ b/llvm/test/tools/llvm-objcopy/ELF/auto-remove-shndx.test
|
||||
@@ -1,4 +1,4 @@
|
||||
-# RUN: %python %p/Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t
|
||||
+# RUN: %python %p/../Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t
|
||||
# RUN: llvm-objcopy -R .text -R s0 -R s1 -R s2 -R s3 -R s4 -R s5 -R s6 %t %t2
|
||||
# RUN: llvm-readobj --sections %t2 | FileCheck --check-prefix=SECS %s
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/ELF/many-sections.test b/llvm/test/tools/llvm-objcopy/ELF/many-sections.test
|
||||
index 57239f32e4a..1dd41cfb10c 100644
|
||||
--- a/llvm/test/tools/llvm-objcopy/ELF/many-sections.test
|
||||
+++ b/llvm/test/tools/llvm-objcopy/ELF/many-sections.test
|
||||
@@ -1,4 +1,4 @@
|
||||
-RUN: %python %p/Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t
|
||||
+RUN: %python %p/../Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t
|
||||
RUN: llvm-objcopy %t %t2
|
||||
RUN: llvm-readobj --file-headers %t2 | FileCheck --check-prefix=EHDR %s
|
||||
RUN: llvm-readobj --sections %t2 | FileCheck --check-prefix=SECS %s
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-shndx.test b/llvm/test/tools/llvm-objcopy/ELF/remove-shndx.test
|
||||
index 6cc3a1a291f..53ca8e7f220 100644
|
||||
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-shndx.test
|
||||
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-shndx.test
|
||||
@@ -1,6 +1,6 @@
|
||||
# This test checks to see that a .symtab_shndx section is added to any binary
|
||||
# that needs it, even if the original was removed.
|
||||
-RUN: %python %p/Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t
|
||||
+RUN: %python %p/../Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t
|
||||
RUN: llvm-objcopy -R .symtab_shndx %t %t2
|
||||
RUN: llvm-readobj --sections %t2 | FileCheck %s
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/ELF/strict-no-add.test b/llvm/test/tools/llvm-objcopy/ELF/strict-no-add.test
|
||||
index 4f24df31bf9..348ab7c4fbd 100644
|
||||
--- a/llvm/test/tools/llvm-objcopy/ELF/strict-no-add.test
|
||||
+++ b/llvm/test/tools/llvm-objcopy/ELF/strict-no-add.test
|
||||
@@ -1,7 +1,7 @@
|
||||
# This test makes sure that sections added at the end that don't have symbols
|
||||
# defined in them don't trigger the creation of a large index table.
|
||||
|
||||
-RUN: %python %p/Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t.0
|
||||
+RUN: %python %p/../Inputs/ungzip.py %p/Inputs/many-sections.o.gz > %t.0
|
||||
RUN: cat %p/Inputs/alloc-symtab.o > %t
|
||||
RUN: llvm-objcopy -R .text -R s0 -R s1 -R s2 -R s3 -R s4 -R s5 -R s6 %t.0 %t2
|
||||
RUN: llvm-objcopy --add-section=.s0=%t --add-section=.s1=%t --add-section=.s2=%t %t2 %t2
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/ELF/Inputs/ungzip.py b/llvm/test/tools/llvm-objcopy/Inputs/ungzip.py
|
||||
similarity index 100%
|
||||
rename from test/tools/llvm-objcopy/ELF/Inputs/ungzip.py
|
||||
rename to test/tools/llvm-objcopy/Inputs/ungzip.py
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index 20adbe11e7a..64b4e79a4e0 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -37,7 +37,7 @@ static uint64_t getNextRVA(const Object &Obj) {
|
||||
return 0;
|
||||
const Section &Last = Obj.getSections().back();
|
||||
return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
|
||||
- Obj.PeHeader.SectionAlignment);
|
||||
+ Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);
|
||||
}
|
||||
|
||||
static uint32_t getCRC32(StringRef Data) {
|
||||
@@ -74,8 +74,8 @@ static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
|
||||
Sec.Name = ".gnu_debuglink";
|
||||
Sec.Header.VirtualSize = Sec.getContents().size();
|
||||
Sec.Header.VirtualAddress = StartRVA;
|
||||
- Sec.Header.SizeOfRawData =
|
||||
- alignTo(Sec.Header.VirtualSize, Obj.PeHeader.FileAlignment);
|
||||
+ Sec.Header.SizeOfRawData = alignTo(Sec.Header.VirtualSize,
|
||||
+ Obj.IsPE ? Obj.PeHeader.FileAlignment : 1);
|
||||
// Sec.Header.PointerToRawData is filled in by the writer.
|
||||
Sec.Header.PointerToRelocations = 0;
|
||||
Sec.Header.PointerToLinenumbers = 0;
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.cpp b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
index 8c382c1faef..0ad5a05a144 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
@@ -26,12 +26,8 @@ void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
|
||||
|
||||
void Object::updateSymbols() {
|
||||
SymbolMap = DenseMap<size_t, Symbol *>(Symbols.size());
|
||||
- size_t RawSymIndex = 0;
|
||||
- for (Symbol &Sym : Symbols) {
|
||||
+ for (Symbol &Sym : Symbols)
|
||||
SymbolMap[Sym.UniqueId] = &Sym;
|
||||
- Sym.RawIndex = RawSymIndex;
|
||||
- RawSymIndex += 1 + Sym.Sym.NumberOfAuxSymbols;
|
||||
- }
|
||||
}
|
||||
|
||||
const Symbol *Object::findSymbol(size_t UniqueId) const {
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
index afa272286ef..21475b06862 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
@@ -66,10 +66,24 @@ private:
|
||||
std::vector<uint8_t> OwnedContents;
|
||||
};
|
||||
|
||||
+struct AuxSymbol {
|
||||
+ AuxSymbol(ArrayRef<uint8_t> In) {
|
||||
+ assert(In.size() == sizeof(Opaque));
|
||||
+ std::copy(In.begin(), In.end(), Opaque);
|
||||
+ }
|
||||
+
|
||||
+ ArrayRef<uint8_t> getRef() const {
|
||||
+ return ArrayRef<uint8_t>(Opaque, sizeof(Opaque));
|
||||
+ }
|
||||
+
|
||||
+ uint8_t Opaque[sizeof(object::coff_symbol16)];
|
||||
+};
|
||||
+
|
||||
struct Symbol {
|
||||
object::coff_symbol32 Sym;
|
||||
StringRef Name;
|
||||
- std::vector<uint8_t> AuxData;
|
||||
+ std::vector<AuxSymbol> AuxData;
|
||||
+ StringRef AuxFile;
|
||||
ssize_t TargetSectionId;
|
||||
ssize_t AssociativeComdatTargetSectionId = 0;
|
||||
Optional<size_t> WeakTargetSymbolId;
|
||||
@@ -132,7 +146,7 @@ private:
|
||||
|
||||
ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.
|
||||
|
||||
- // Update SymbolMap and RawIndex in each Symbol.
|
||||
+ // Update SymbolMap.
|
||||
void updateSymbols();
|
||||
|
||||
// Update SectionMap and Index in each Section.
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
index 87dd60a43cf..7270bbf94de 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
@@ -107,9 +107,24 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
|
||||
*reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
|
||||
if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name))
|
||||
return errorCodeToError(EC);
|
||||
- Sym.AuxData = COFFObj.getSymbolAuxData(SymRef);
|
||||
- assert((Sym.AuxData.size() %
|
||||
- (IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0);
|
||||
+
|
||||
+ ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
|
||||
+ size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
|
||||
+ assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
|
||||
+ // The auxillary symbols are structs of sizeof(coff_symbol16) each.
|
||||
+ // In the big object format (where symbols are coff_symbol32), each
|
||||
+ // auxillary symbol is padded with 2 bytes at the end. Copy each
|
||||
+ // auxillary symbol to the Sym.AuxData vector. For file symbols,
|
||||
+ // the whole range of aux symbols are interpreted as one null padded
|
||||
+ // string instead.
|
||||
+ if (SymRef.isFileRecord())
|
||||
+ Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
|
||||
+ AuxData.size())
|
||||
+ .rtrim('\0');
|
||||
+ else
|
||||
+ for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
|
||||
+ Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
|
||||
+
|
||||
// Find the unique id of the section
|
||||
if (SymRef.getSectionNumber() <=
|
||||
0) // Special symbol (undefined/absolute/debug)
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
index db897e2ff33..6e69c597217 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
@@ -55,7 +55,8 @@ Error COFFWriter::finalizeSymbolContents() {
|
||||
if (Sym.Sym.NumberOfAuxSymbols == 1 &&
|
||||
Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
|
||||
coff_aux_section_definition *SD =
|
||||
- reinterpret_cast<coff_aux_section_definition *>(Sym.AuxData.data());
|
||||
+ reinterpret_cast<coff_aux_section_definition *>(
|
||||
+ Sym.AuxData[0].Opaque);
|
||||
uint32_t SDSectionNumber;
|
||||
if (Sym.AssociativeComdatTargetSectionId == 0) {
|
||||
// Not a comdat associative section; just set the Number field to
|
||||
@@ -79,7 +80,7 @@ Error COFFWriter::finalizeSymbolContents() {
|
||||
// we want to set. Only >= 1 would be required, but only == 1 makes sense.
|
||||
if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) {
|
||||
coff_aux_weak_external *WE =
|
||||
- reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData.data());
|
||||
+ reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque);
|
||||
const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId);
|
||||
if (Target == nullptr)
|
||||
return createStringError(object_error::invalid_symbol_index,
|
||||
@@ -141,13 +142,26 @@ size_t COFFWriter::finalizeStringTable() {
|
||||
|
||||
template <class SymbolTy>
|
||||
std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
|
||||
- size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy);
|
||||
- for (const auto &S : Obj.getSymbols())
|
||||
- SymTabSize += S.AuxData.size();
|
||||
- return std::make_pair(SymTabSize, sizeof(SymbolTy));
|
||||
+ size_t RawSymIndex = 0;
|
||||
+ for (auto &S : Obj.getMutableSymbols()) {
|
||||
+ // Symbols normally have NumberOfAuxSymbols set correctly all the time.
|
||||
+ // For file symbols, we need to know the output file's symbol size to be
|
||||
+ // able to calculate the number of slots it occupies.
|
||||
+ if (!S.AuxFile.empty())
|
||||
+ S.Sym.NumberOfAuxSymbols =
|
||||
+ alignTo(S.AuxFile.size(), sizeof(SymbolTy)) / sizeof(SymbolTy);
|
||||
+ S.RawIndex = RawSymIndex;
|
||||
+ RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols;
|
||||
+ }
|
||||
+ return std::make_pair(RawSymIndex * sizeof(SymbolTy), sizeof(SymbolTy));
|
||||
}
|
||||
|
||||
Error COFFWriter::finalize(bool IsBigObj) {
|
||||
+ size_t SymTabSize, SymbolSize;
|
||||
+ std::tie(SymTabSize, SymbolSize) = IsBigObj
|
||||
+ ? finalizeSymbolTable<coff_symbol32>()
|
||||
+ : finalizeSymbolTable<coff_symbol16>();
|
||||
+
|
||||
if (Error E = finalizeRelocTargets())
|
||||
return E;
|
||||
if (Error E = finalizeSymbolContents())
|
||||
@@ -199,10 +213,6 @@ Error COFFWriter::finalize(bool IsBigObj) {
|
||||
}
|
||||
|
||||
size_t StrTabSize = finalizeStringTable();
|
||||
- size_t SymTabSize, SymbolSize;
|
||||
- std::tie(SymTabSize, SymbolSize) = IsBigObj
|
||||
- ? finalizeSymbolTable<coff_symbol32>()
|
||||
- : finalizeSymbolTable<coff_symbol16>();
|
||||
|
||||
size_t PointerToSymbolTable = FileSize;
|
||||
// StrTabSize <= 4 is the size of an empty string table, only consisting
|
||||
@@ -312,8 +322,23 @@ template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
|
||||
copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
|
||||
S.Sym);
|
||||
Ptr += sizeof(SymbolTy);
|
||||
- std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr);
|
||||
- Ptr += S.AuxData.size();
|
||||
+ if (!S.AuxFile.empty()) {
|
||||
+ // For file symbols, just write the string into the aux symbol slots,
|
||||
+ // assuming that the unwritten parts are initialized to zero in the memory
|
||||
+ // mapped file.
|
||||
+ std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr);
|
||||
+ Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy);
|
||||
+ } else {
|
||||
+ // For other auxillary symbols, write their opaque payload into one symbol
|
||||
+ // table slot each. For big object files, the symbols are larger than the
|
||||
+ // opaque auxillary symbol struct and we leave padding at the end of each
|
||||
+ // entry.
|
||||
+ for (const AuxSymbol &AuxSym : S.AuxData) {
|
||||
+ ArrayRef<uint8_t> Ref = AuxSym.getRef();
|
||||
+ std::copy(Ref.begin(), Ref.end(), Ptr);
|
||||
+ Ptr += sizeof(SymbolTy);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
|
||||
// Always write a string table in object files, even an empty one.
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.h b/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
index 9b1cfa91d00..681a8d5e4a6 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
@@ -30,11 +30,11 @@ class COFFWriter {
|
||||
size_t SizeOfInitializedData;
|
||||
StringTableBuilder StrTabBuilder;
|
||||
|
||||
+ template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
|
||||
Error finalizeRelocTargets();
|
||||
Error finalizeSymbolContents();
|
||||
void layoutSections();
|
||||
size_t finalizeStringTable();
|
||||
- template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
|
||||
|
||||
Error finalize(bool IsBigObj);
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,222 @@
|
||||
From 526aa2e94355b7feb3bf7774a6e1899f68e94ad8 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Sat, 19 Jan 2019 19:42:48 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Implement --only-keep-debug
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D56840
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351662 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../COFF/Inputs/only-keep-sections.yaml | 77 +++++++++++++++++++
|
||||
.../llvm-objcopy/COFF/only-keep-debug.test | 58 ++++++++++++++
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 10 +++
|
||||
tools/llvm-objcopy/COFF/Object.cpp | 10 +++
|
||||
tools/llvm-objcopy/COFF/Object.h | 1 +
|
||||
5 files changed, 156 insertions(+)
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/Inputs/only-keep-sections.yaml
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/only-keep-debug.test
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/Inputs/only-keep-sections.yaml b/llvm/test/tools/llvm-objcopy/COFF/Inputs/only-keep-sections.yaml
|
||||
new file mode 100644
|
||||
index 00000000000..b5437e10763
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/Inputs/only-keep-sections.yaml
|
||||
@@ -0,0 +1,77 @@
|
||||
+--- !COFF
|
||||
+OptionalHeader:
|
||||
+ AddressOfEntryPoint: 4144
|
||||
+ ImageBase: 1073741824
|
||||
+ SectionAlignment: 4096
|
||||
+ FileAlignment: 512
|
||||
+ MajorOperatingSystemVersion: 6
|
||||
+ MinorOperatingSystemVersion: 0
|
||||
+ MajorImageVersion: 0
|
||||
+ MinorImageVersion: 0
|
||||
+ MajorSubsystemVersion: 6
|
||||
+ MinorSubsystemVersion: 0
|
||||
+ Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
|
||||
+ DLLCharacteristics: [ ]
|
||||
+ SizeOfStackReserve: 1048576
|
||||
+ SizeOfStackCommit: 4096
|
||||
+ SizeOfHeapReserve: 1048576
|
||||
+ SizeOfHeapCommit: 4096
|
||||
+header:
|
||||
+ Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
+ Characteristics: [ ]
|
||||
+sections:
|
||||
+ - Name: .text
|
||||
+ Characteristics: [ IMAGE_SCN_CNT_CODE ]
|
||||
+ VirtualAddress: 4096
|
||||
+ VirtualSize: 4
|
||||
+ SectionData: C3C3C3C3
|
||||
+ - Name: .rdata
|
||||
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA ]
|
||||
+ VirtualAddress: 8192
|
||||
+ VirtualSize: 4
|
||||
+ SectionData: 2A000000
|
||||
+ - Name: .buildid
|
||||
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA ]
|
||||
+ VirtualAddress: 12288
|
||||
+ VirtualSize: 4
|
||||
+ SectionData: 2B000000
|
||||
+ - Name: .reloc
|
||||
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE ]
|
||||
+ VirtualAddress: 16384
|
||||
+ VirtualSize: 4
|
||||
+ SectionData: 2C000000
|
||||
+ - Name: .debug_discardable
|
||||
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE ]
|
||||
+ VirtualAddress: 20480
|
||||
+ VirtualSize: 4
|
||||
+ SectionData: 2D000000
|
||||
+ - Name: .debug_undiscardable
|
||||
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA ]
|
||||
+ VirtualAddress: 24576
|
||||
+ VirtualSize: 4
|
||||
+ SectionData: 2E000000
|
||||
+ - Name: .unflagged
|
||||
+ Characteristics: [ ]
|
||||
+ VirtualAddress: 28672
|
||||
+ VirtualSize: 4
|
||||
+ SectionData: 2F000000
|
||||
+symbols:
|
||||
+ - Name: main
|
||||
+ Value: 2
|
||||
+ SectionNumber: 1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+ - Name: debug_discardable_sym
|
||||
+ Value: 0
|
||||
+ SectionNumber: 5
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+ - Name: debug_undiscardable_sym
|
||||
+ Value: 0
|
||||
+ SectionNumber: 6
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+...
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/only-keep-debug.test b/llvm/test/tools/llvm-objcopy/COFF/only-keep-debug.test
|
||||
new file mode 100644
|
||||
index 00000000000..5518d4000fc
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/only-keep-debug.test
|
||||
@@ -0,0 +1,58 @@
|
||||
+RUN: yaml2obj %p/Inputs/only-keep-sections.yaml > %t.in.exe
|
||||
+
|
||||
+RUN: llvm-objcopy --only-keep-debug %t.in.exe %t.out.exe
|
||||
+RUN: llvm-readobj --sections %t.out.exe | FileCheck %s --check-prefix=SECTIONS
|
||||
+RUN: llvm-objdump -t %t.out.exe | FileCheck %s --check-prefix=SYMBOLS
|
||||
+
|
||||
+Check that all non-debug/buildid sections with IMAGE_SCN_CNT_CODE
|
||||
+or IMAGE_SCN_CNT_INITIALIZED_DATA are truncated, and no others.
|
||||
+
|
||||
+SECTIONS: Sections [
|
||||
+SECTIONS-NEXT: Section {
|
||||
+SECTIONS-NEXT: Number: 1
|
||||
+SECTIONS-NEXT: Name: .text
|
||||
+SECTIONS-NEXT: VirtualSize: 0x4
|
||||
+SECTIONS-NEXT: VirtualAddress:
|
||||
+SECTIONS-NEXT: RawDataSize: 0
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS-NEXT: Number: 2
|
||||
+SECTIONS-NEXT: Name: .rdata
|
||||
+SECTIONS-NEXT: VirtualSize: 0x4
|
||||
+SECTIONS-NEXT: VirtualAddress:
|
||||
+SECTIONS-NEXT: RawDataSize: 0
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS-NEXT: Number: 3
|
||||
+SECTIONS-NEXT: Name: .buildid
|
||||
+SECTIONS-NEXT: VirtualSize: 0x4
|
||||
+SECTIONS-NEXT: VirtualAddress:
|
||||
+SECTIONS-NEXT: RawDataSize: 512
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS-NEXT: Number: 4
|
||||
+SECTIONS-NEXT: Name: .reloc
|
||||
+SECTIONS-NEXT: VirtualSize: 0x4
|
||||
+SECTIONS-NEXT: VirtualAddress:
|
||||
+SECTIONS-NEXT: RawDataSize: 0
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS-NEXT: Number: 5
|
||||
+SECTIONS-NEXT: Name: .debug_discardable
|
||||
+SECTIONS-NEXT: VirtualSize: 0x4
|
||||
+SECTIONS-NEXT: VirtualAddress:
|
||||
+SECTIONS-NEXT: RawDataSize: 512
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS-NEXT: Number: 6
|
||||
+SECTIONS-NEXT: Name: .debug_undiscardable
|
||||
+SECTIONS-NEXT: VirtualSize: 0x4
|
||||
+SECTIONS-NEXT: VirtualAddress:
|
||||
+SECTIONS-NEXT: RawDataSize: 512
|
||||
+SECTIONS: Section {
|
||||
+SECTIONS-NEXT: Number: 7
|
||||
+SECTIONS-NEXT: Name: .unflagged
|
||||
+SECTIONS-NEXT: VirtualSize: 0x4
|
||||
+SECTIONS-NEXT: VirtualAddress:
|
||||
+SECTIONS-NEXT: RawDataSize: 512
|
||||
+
|
||||
+SYMBOLS: SYMBOL TABLE:
|
||||
+SYMBOLS-NEXT: main
|
||||
+SYMBOLS-NEXT: debug_discardable_sym
|
||||
+SYMBOLS-NEXT: debug_undiscardable_sym
|
||||
+SYMBOLS-EMPTY:
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index 13d8efde37c..60afbf7bb54 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -46,6 +46,16 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
return false;
|
||||
});
|
||||
|
||||
+ if (Config.OnlyKeepDebug) {
|
||||
+ // For --only-keep-debug, we keep all other sections, but remove their
|
||||
+ // content. The VirtualSize field in the section header is kept intact.
|
||||
+ Obj.truncateSections([](const Section &Sec) {
|
||||
+ return !isDebugSection(Sec) && Sec.Name != ".buildid" &&
|
||||
+ ((Sec.Header.Characteristics &
|
||||
+ (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
// StripAll removes all symbols and thus also removes all relocations.
|
||||
if (Config.StripAll || Config.StripAllGNU)
|
||||
for (Section &Sec : Obj.getMutableSections())
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.cpp b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
index e19cea6aa9d..fc87d9e574d 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
@@ -127,6 +127,16 @@ void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
|
||||
updateSymbols();
|
||||
}
|
||||
|
||||
+void Object::truncateSections(function_ref<bool(const Section &)> ToTruncate) {
|
||||
+ for (Section &Sec : Sections) {
|
||||
+ if (ToTruncate(Sec)) {
|
||||
+ Sec.Contents = ArrayRef<uint8_t>();
|
||||
+ Sec.Relocs.clear();
|
||||
+ Sec.Header.SizeOfRawData = 0;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
} // end namespace coff
|
||||
} // end namespace objcopy
|
||||
} // end namespace llvm
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
index a73e93620d3..8e200369f0b 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
@@ -93,6 +93,7 @@ struct Object {
|
||||
|
||||
void addSections(ArrayRef<Section> NewSections);
|
||||
void removeSections(function_ref<bool(const Section &)> ToRemove);
|
||||
+ void truncateSections(function_ref<bool(const Section &)> ToTruncate);
|
||||
|
||||
private:
|
||||
std::vector<Symbol> Symbols;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,61 @@
|
||||
From 17dcf25b3ade15605ca27150e4440bcc75caed65 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Sat, 19 Jan 2019 19:42:54 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Implement --only-section
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D56873
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351663 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../tools/llvm-objcopy/COFF/only-section.test | 21 +++++++++++++++++++
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 6 ++++++
|
||||
2 files changed, 27 insertions(+)
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/only-section.test
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/only-section.test b/llvm/test/tools/llvm-objcopy/COFF/only-section.test
|
||||
new file mode 100644
|
||||
index 00000000000..42492ed80ff
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/only-section.test
|
||||
@@ -0,0 +1,21 @@
|
||||
+RUN: yaml2obj %p/Inputs/only-keep-sections.yaml > %t.in.exe
|
||||
+
|
||||
+RUN: llvm-objcopy --only-section .debug_discardable %t.in.exe %t.out.exe
|
||||
+RUN: llvm-objdump --section-headers -t %t.out.exe | FileCheck %s --check-prefixes=SECTIONS,SECTIONS-DEBUG,SYMBOLS,SYMBOLS-DEBUG
|
||||
+
|
||||
+Adding another section stripping option makes it return the intersection of
|
||||
+kept sections - in this case keeping only .text.
|
||||
+
|
||||
+RUN: llvm-objcopy --only-section .debug_discardable --only-section .text --strip-debug %t.in.exe %t.combination.exe
|
||||
+RUN: llvm-objdump --section-headers -t %t.combination.exe | FileCheck %s --check-prefixes=SECTIONS,SECTIONS-TEXT,SYMBOLS,SYMBOLS-TEXT
|
||||
+
|
||||
+SECTIONS: Sections:
|
||||
+SECTIONS-NEXT: Idx Name
|
||||
+SECTIONS-DEBUG-NEXT: .debug_discardable
|
||||
+SECTIONS-TEXT-NEXT: .text
|
||||
+SECTIONS-EMPTY:
|
||||
+
|
||||
+SYMBOLS: SYMBOL TABLE:
|
||||
+SYMBOLS-DEBUG-NEXT: debug_discardable_sym
|
||||
+SYMBOLS-TEXT-NEXT: main
|
||||
+SYMBOLS-EMPTY:
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index 60afbf7bb54..99929d10a1f 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -33,6 +33,12 @@ static bool isDebugSection(const Section &Sec) {
|
||||
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
// Perform the actual section removals.
|
||||
Obj.removeSections([&Config](const Section &Sec) {
|
||||
+ // Contrary to --only-keep-debug, --only-section fully removes sections that
|
||||
+ // aren't mentioned.
|
||||
+ if (!Config.OnlySection.empty() &&
|
||||
+ !is_contained(Config.OnlySection, Sec.Name))
|
||||
+ return true;
|
||||
+
|
||||
if (Config.StripDebug || Config.StripAll || Config.StripAllGNU ||
|
||||
Config.DiscardAll || Config.StripUnneeded) {
|
||||
if (isDebugSection(Sec) &&
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,160 @@
|
||||
From 2b6e1b7585d6bd997ea4e4233c904a6d2c11ad33 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Sat, 19 Jan 2019 19:42:41 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Implement --strip-debug
|
||||
|
||||
Also remove sections similarly for --strip-all, --discard-all,
|
||||
--strip-unneeded.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D56839
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351661 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
test/tools/llvm-objcopy/COFF/strip-debug.test | 109 ++++++++++++++++++
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 11 ++
|
||||
2 files changed, 120 insertions(+)
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/strip-debug.test
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/strip-debug.test b/llvm/test/tools/llvm-objcopy/COFF/strip-debug.test
|
||||
new file mode 100644
|
||||
index 00000000000..97fa96aac70
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/strip-debug.test
|
||||
@@ -0,0 +1,109 @@
|
||||
+# RUN: yaml2obj %s > %t.in.o
|
||||
+#
|
||||
+# RUN: llvm-objdump --section-headers %t.in.o | FileCheck %s --check-prefixes=SECTIONS,SECTIONS-PRE
|
||||
+# RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-PRE
|
||||
+#
|
||||
+# RUN: llvm-objcopy --strip-debug %t.in.o %t.out.o
|
||||
+# RUN: llvm-objdump --section-headers %t.out.o | FileCheck %s --check-prefixes=SECTIONS
|
||||
+# RUN: llvm-objdump -t %t.out.o | FileCheck %s --check-prefixes=SYMBOLS
|
||||
+#
|
||||
+# Test that --strip-all, --strip-all-gnu, --discard-all and --strip-unneeded,
|
||||
+# plus llvm-strip without arguments all produce a similiar set of sections
|
||||
+# (while they remove symbols differently).
|
||||
+#
|
||||
+# RUN: llvm-objcopy --strip-all %t.in.o %t.strip-all.o
|
||||
+# RUN: llvm-objdump --section-headers %t.strip-all.o | FileCheck %s --check-prefixes=SECTIONS
|
||||
+#
|
||||
+# RUN: llvm-objcopy --strip-all-gnu %t.in.o %t.strip-all-gnu.o
|
||||
+# RUN: llvm-objdump --section-headers %t.strip-all-gnu.o | FileCheck %s --check-prefixes=SECTIONS
|
||||
+#
|
||||
+# RUN: llvm-objcopy --discard-all %t.in.o %t.discard-all.o
|
||||
+# RUN: llvm-objdump --section-headers %t.discard-all.o | FileCheck %s --check-prefixes=SECTIONS
|
||||
+#
|
||||
+# RUN: llvm-objcopy --discard-all %t.in.o %t.strip-unneeded.o
|
||||
+# RUN: llvm-objdump --section-headers %t.strip-unneeded.o | FileCheck %s --check-prefixes=SECTIONS
|
||||
+#
|
||||
+# SECTIONS: Sections:
|
||||
+# SECTIONS-NEXT: Idx Name
|
||||
+# SECTIONS-NEXT: 0 .text
|
||||
+# SECTIONS-NEXT: 1 .data
|
||||
+# SECTIONS-NEXT: 2 .bss
|
||||
+# SECTIONS-NEXT: 3 .xdata
|
||||
+# SECTIONS-NEXT: 4 .reloc
|
||||
+# SECTIONS-PRE-NEXT: 5 .debug_discardable
|
||||
+# SECTIONS-NEXT: {{.*}} .debug_undiscardable
|
||||
+# SECTIONS-NEXT: {{.*}} .llvm_addrsig
|
||||
+# SECTIONS-EMPTY:
|
||||
+#
|
||||
+# Test that --strip-debug doesn't remove e.g. unreferenced local symbols.
|
||||
+#
|
||||
+# SYMBOLS: SYMBOL TABLE:
|
||||
+# SYMBOLS-NEXT: external
|
||||
+# SYMBOLS-NEXT: local_unreferenced
|
||||
+# SYMBOLS-PRE-NEXT: debug_discardable_sym
|
||||
+# SYMBOLS-NEXT: debug_undiscardable_sym
|
||||
+# SYMBOLS-EMPTY:
|
||||
+
|
||||
+--- !COFF
|
||||
+header:
|
||||
+ Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
+ Characteristics: [ ]
|
||||
+sections:
|
||||
+ - Name: .text
|
||||
+ Characteristics: [ ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+ - Name: .data
|
||||
+ Characteristics: [ ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+ - Name: .bss
|
||||
+ Characteristics: [ ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+ - Name: .xdata
|
||||
+ Characteristics: [ ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+ - Name: .reloc
|
||||
+ Characteristics: [ IMAGE_SCN_MEM_DISCARDABLE ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+ - Name: .debug_discardable
|
||||
+ Characteristics: [ IMAGE_SCN_MEM_DISCARDABLE ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+ - Name: .debug_undiscardable
|
||||
+ Characteristics: [ ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+ - Name: .llvm_addrsig
|
||||
+ Characteristics: [ IMAGE_SCN_LNK_REMOVE ]
|
||||
+ Alignment: 4
|
||||
+ SectionData: 00000000
|
||||
+symbols:
|
||||
+ - Name: external
|
||||
+ Value: 0
|
||||
+ SectionNumber: 1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+ - Name: local_unreferenced
|
||||
+ Value: 0
|
||||
+ SectionNumber: 1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
+ - Name: debug_discardable_sym
|
||||
+ Value: 0
|
||||
+ SectionNumber: 6
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+ - Name: debug_undiscardable_sym
|
||||
+ Value: 0
|
||||
+ SectionNumber: 7
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+...
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index dd2e4829218..13d8efde37c 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -26,9 +26,20 @@ namespace coff {
|
||||
using namespace object;
|
||||
using namespace COFF;
|
||||
|
||||
+static bool isDebugSection(const Section &Sec) {
|
||||
+ return Sec.Name.startswith(".debug");
|
||||
+}
|
||||
+
|
||||
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
// Perform the actual section removals.
|
||||
Obj.removeSections([&Config](const Section &Sec) {
|
||||
+ if (Config.StripDebug || Config.StripAll || Config.StripAllGNU ||
|
||||
+ Config.DiscardAll || Config.StripUnneeded) {
|
||||
+ if (isDebugSection(Sec) &&
|
||||
+ (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
if (is_contained(Config.ToRemove, Sec.Name))
|
||||
return true;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,27 @@
|
||||
From a495c9ae6fb3367e6b59d8d245273ed3669754f0 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Sat, 19 Jan 2019 19:42:23 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Remove a superfluous namespace
|
||||
qualification. NFC.
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351658 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index ceebf600b3a..437dccbd3d5 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -78,7 +78,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
}
|
||||
|
||||
void executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
- object::COFFObjectFile &In, Buffer &Out) {
|
||||
+ COFFObjectFile &In, Buffer &Out) {
|
||||
COFFReader Reader(In);
|
||||
Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
|
||||
if (!ObjOrErr)
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,224 @@
|
||||
From d37f67c7311cd371d9ff1afd398bc92f309e6baf Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Tue, 22 Jan 2019 10:58:09 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] [COFF] Update symbol indices in weak externals
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D57006
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351800 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../llvm-objcopy/COFF/weak-external.test | 49 +++++++++++++++++++
|
||||
tools/llvm-objcopy/COFF/Object.h | 2 +
|
||||
tools/llvm-objcopy/COFF/Reader.cpp | 24 ++++++++-
|
||||
tools/llvm-objcopy/COFF/Reader.h | 2 +-
|
||||
tools/llvm-objcopy/COFF/Writer.cpp | 16 +++++-
|
||||
tools/llvm-objcopy/COFF/Writer.h | 2 +-
|
||||
6 files changed, 89 insertions(+), 6 deletions(-)
|
||||
create mode 100644 test/tools/llvm-objcopy/COFF/weak-external.test
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/weak-external.test b/llvm/test/tools/llvm-objcopy/COFF/weak-external.test
|
||||
new file mode 100644
|
||||
index 00000000000..d36a53b4eb1
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/weak-external.test
|
||||
@@ -0,0 +1,49 @@
|
||||
+# RUN: yaml2obj %s > %t.in.o
|
||||
+
|
||||
+# RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-PRE
|
||||
+
|
||||
+# RUN: llvm-objcopy -N func %t.in.o %t.out.o
|
||||
+# RUN: llvm-objdump -t %t.out.o | FileCheck %s --check-prefixes=SYMBOLS,SYMBOLS-POST
|
||||
+
|
||||
+# RUN: not llvm-objcopy -N .weak.foobar.file1 %t.in.o %t.err.o 2>&1 | FileCheck %s --check-prefix=ERROR
|
||||
+
|
||||
+# SYMBOLS: SYMBOL TABLE:
|
||||
+# SYMBOLS-PRE-NEXT: func
|
||||
+# SYMBOLS-NEXT: .weak.foobar.file1
|
||||
+# SYMBOLS-NEXT: foobar
|
||||
+# SYMBOLS-PRE-NEXT: AUX indx 1
|
||||
+# SYMBOLS-POST-NEXT: AUX indx 0
|
||||
+# SYMBOLS-EMPTY:
|
||||
+
|
||||
+# ERROR: Symbol 'foobar' is missing its weak target
|
||||
+
|
||||
+--- !COFF
|
||||
+header:
|
||||
+ Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
+ Characteristics: [ ]
|
||||
+sections:
|
||||
+ - Name: .text
|
||||
+ Characteristics: [ ]
|
||||
+symbols:
|
||||
+ - Name: func
|
||||
+ Value: 0
|
||||
+ SectionNumber: 1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+ - Name: .weak.foobar.file1
|
||||
+ Value: 1
|
||||
+ SectionNumber: 1
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
+ - Name: foobar
|
||||
+ Value: 0
|
||||
+ SectionNumber: 0
|
||||
+ SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
+ StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL
|
||||
+ WeakExternal:
|
||||
+ TagIndex: 1
|
||||
+ Characteristics: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY
|
||||
+...
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
index 8e200369f0b..0630f9c5ff8 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.h
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
+#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
@@ -47,6 +48,7 @@ struct Symbol {
|
||||
std::vector<uint8_t> AuxData;
|
||||
ssize_t TargetSectionId;
|
||||
ssize_t AssociativeComdatTargetSectionId = 0;
|
||||
+ Optional<size_t> WeakTargetSymbolId;
|
||||
size_t UniqueId;
|
||||
size_t RawIndex;
|
||||
bool Referenced;
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
index 20ff32a59dc..2446277cc2b 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
@@ -121,12 +121,18 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
|
||||
// For section definitions, check if it is comdat associative, and if
|
||||
// it is, find the target section unique id.
|
||||
const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
|
||||
+ const coff_aux_weak_external *WE = SymRef.getWeakExternal();
|
||||
if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
|
||||
int32_t Index = SD->getNumber(IsBigObj);
|
||||
if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
|
||||
return createStringError(object_error::parse_failed,
|
||||
"Unexpected associative section index");
|
||||
Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
|
||||
+ } else if (WE) {
|
||||
+ // This is a raw symbol index for now, but store it in the Symbol
|
||||
+ // until we've added them to the Object, which assigns the final
|
||||
+ // unique ids.
|
||||
+ Sym.WeakTargetSymbolId = WE->TagIndex;
|
||||
}
|
||||
I += 1 + SymRef.getNumberOfAuxSymbols();
|
||||
}
|
||||
@@ -134,13 +140,27 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
-Error COFFReader::setRelocTargets(Object &Obj) const {
|
||||
+Error COFFReader::setSymbolTargets(Object &Obj) const {
|
||||
std::vector<const Symbol *> RawSymbolTable;
|
||||
for (const Symbol &Sym : Obj.getSymbols()) {
|
||||
RawSymbolTable.push_back(&Sym);
|
||||
for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
|
||||
RawSymbolTable.push_back(nullptr);
|
||||
}
|
||||
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
|
||||
+ // Convert WeakTargetSymbolId from the original raw symbol index to
|
||||
+ // a proper unique id.
|
||||
+ if (Sym.WeakTargetSymbolId) {
|
||||
+ if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Weak external reference out of range");
|
||||
+ const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
|
||||
+ if (Target == nullptr)
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Invalid SymbolTableIndex");
|
||||
+ Sym.WeakTargetSymbolId = Target->UniqueId;
|
||||
+ }
|
||||
+ }
|
||||
for (Section &Sec : Obj.getMutableSections()) {
|
||||
for (Relocation &R : Sec.Relocs) {
|
||||
if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
|
||||
@@ -184,7 +204,7 @@ Expected<std::unique_ptr<Object>> COFFReader::create() const {
|
||||
return std::move(E);
|
||||
if (Error E = readSymbols(*Obj, IsBigObj))
|
||||
return std::move(E);
|
||||
- if (Error E = setRelocTargets(*Obj))
|
||||
+ if (Error E = setSymbolTargets(*Obj))
|
||||
return std::move(E);
|
||||
|
||||
return std::move(Obj);
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.h b/llvm/tools/llvm-objcopy/COFF/Reader.h
|
||||
index 4493705e73c..ec15369db0b 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Reader.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Reader.h
|
||||
@@ -28,7 +28,7 @@ class COFFReader {
|
||||
Error readExecutableHeaders(Object &Obj) const;
|
||||
Error readSections(Object &Obj) const;
|
||||
Error readSymbols(Object &Obj, bool IsBigObj) const;
|
||||
- Error setRelocTargets(Object &Obj) const;
|
||||
+ Error setSymbolTargets(Object &Obj) const;
|
||||
|
||||
public:
|
||||
explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {}
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
index 0321f94a896..4f57131d5ab 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
@@ -38,7 +38,7 @@ Error COFFWriter::finalizeRelocTargets() {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
-Error COFFWriter::finalizeSectionNumbers() {
|
||||
+Error COFFWriter::finalizeSymbolContents() {
|
||||
for (Symbol &Sym : Obj.getMutableSymbols()) {
|
||||
if (Sym.TargetSectionId <= 0) {
|
||||
// Undefined, or a special kind of symbol. These negative values
|
||||
@@ -75,6 +75,18 @@ Error COFFWriter::finalizeSectionNumbers() {
|
||||
SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16);
|
||||
}
|
||||
}
|
||||
+ // Check that we actually have got AuxData to match the weak symbol target
|
||||
+ // we want to set. Only >= 1 would be required, but only == 1 makes sense.
|
||||
+ if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) {
|
||||
+ coff_aux_weak_external *WE =
|
||||
+ reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData.data());
|
||||
+ const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId);
|
||||
+ if (Target == nullptr)
|
||||
+ return createStringError(object_error::invalid_symbol_index,
|
||||
+ "Symbol '%s' is missing its weak target",
|
||||
+ Sym.Name.str().c_str());
|
||||
+ WE->TagIndex = Target->RawIndex;
|
||||
+ }
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
@@ -137,7 +149,7 @@ std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
|
||||
Error COFFWriter::finalize(bool IsBigObj) {
|
||||
if (Error E = finalizeRelocTargets())
|
||||
return E;
|
||||
- if (Error E = finalizeSectionNumbers())
|
||||
+ if (Error E = finalizeSymbolContents())
|
||||
return E;
|
||||
|
||||
size_t SizeOfHeaders = 0;
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.h b/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
index a967a103df9..9b1cfa91d00 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.h
|
||||
@@ -31,7 +31,7 @@ class COFFWriter {
|
||||
StringTableBuilder StrTabBuilder;
|
||||
|
||||
Error finalizeRelocTargets();
|
||||
- Error finalizeSectionNumbers();
|
||||
+ Error finalizeSymbolContents();
|
||||
void layoutSections();
|
||||
size_t finalizeStringTable();
|
||||
template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,242 @@
|
||||
From d3b89a1637cddee1c61e59257cfe92227ead29e5 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Storsjo <martin@martin.st>
|
||||
Date: Tue, 22 Jan 2019 10:57:59 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] Consistently use createStringError instead of
|
||||
make_error<StringError>
|
||||
|
||||
This was requested in the review of D57006.
|
||||
|
||||
Also add missing quotes around symbol names in error messages.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D57014
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351799 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../llvm-objcopy/COFF/remove-section.test | 2 +-
|
||||
tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 8 ++---
|
||||
tools/llvm-objcopy/COFF/Object.cpp | 5 ++-
|
||||
tools/llvm-objcopy/COFF/Reader.cpp | 24 +++++++-------
|
||||
tools/llvm-objcopy/COFF/Writer.cpp | 33 +++++++++----------
|
||||
tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 10 +++---
|
||||
6 files changed, 40 insertions(+), 42 deletions(-)
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/COFF/remove-section.test b/llvm/test/tools/llvm-objcopy/COFF/remove-section.test
|
||||
index b3dfb0b98cb..6dc8f6a6c2e 100644
|
||||
--- a/test/tools/llvm-objcopy/COFF/remove-section.test
|
||||
+++ b/llvm/test/tools/llvm-objcopy/COFF/remove-section.test
|
||||
@@ -96,7 +96,7 @@
|
||||
# Removing the .comdat section fails, since the .text section has relocations
|
||||
# against it.
|
||||
#
|
||||
-# ERROR-RELOC: Relocation target foo ({{.*}}) not found
|
||||
+# ERROR-RELOC: Relocation target 'foo' ({{.*}}) not found
|
||||
#
|
||||
#
|
||||
# Removing the .comdat section and .text (with a relocation against .comdat)
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
index 99929d10a1f..8d8f53d13d8 100644
|
||||
--- a/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
|
||||
@@ -84,10 +84,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
// Explicitly removing a referenced symbol is an error.
|
||||
if (Sym.Referenced)
|
||||
reportError(Config.OutputFilename,
|
||||
- make_error<StringError>(
|
||||
- "not stripping symbol '" + Sym.Name +
|
||||
- "' because it is named in a relocation.",
|
||||
- llvm::errc::invalid_argument));
|
||||
+ createStringError(llvm::errc::invalid_argument,
|
||||
+ "not stripping symbol '%s' because it is "
|
||||
+ "named in a relocation.",
|
||||
+ Sym.Name.str().c_str()));
|
||||
return true;
|
||||
}
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Object.cpp b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
index fc87d9e574d..83435dffa98 100644
|
||||
--- a/tools/llvm-objcopy/COFF/Object.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Object.cpp
|
||||
@@ -56,9 +56,8 @@ Error Object::markSymbols() {
|
||||
for (const Relocation &R : Sec.Relocs) {
|
||||
auto It = SymbolMap.find(R.Target);
|
||||
if (It == SymbolMap.end())
|
||||
- return make_error<StringError>("Relocation target " + Twine(R.Target) +
|
||||
- " not found",
|
||||
- object_error::invalid_symbol_index);
|
||||
+ return createStringError(object_error::invalid_symbol_index,
|
||||
+ "Relocation target %zu not found", R.Target);
|
||||
It->second->Referenced = true;
|
||||
}
|
||||
}
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
index c8abe2913a2..20ff32a59dc 100644
|
||||
--- a/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
|
||||
@@ -77,8 +77,8 @@ Error COFFReader::readSections(Object &Obj) const {
|
||||
if (auto EC = COFFObj.getSectionName(Sec, S.Name))
|
||||
return errorCodeToError(EC);
|
||||
if (Sec->hasExtendedRelocations())
|
||||
- return make_error<StringError>("Extended relocations not supported yet",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Extended relocations not supported yet");
|
||||
}
|
||||
Obj.addSections(Sections);
|
||||
return Error::success();
|
||||
@@ -116,16 +116,16 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
|
||||
Sections.size())
|
||||
Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
|
||||
else
|
||||
- return make_error<StringError>("Section number out of range",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Section number out of range");
|
||||
// For section definitions, check if it is comdat associative, and if
|
||||
// it is, find the target section unique id.
|
||||
const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
|
||||
if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
|
||||
int32_t Index = SD->getNumber(IsBigObj);
|
||||
if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
|
||||
- return make_error<StringError>("Unexpected associative section index",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Unexpected associative section index");
|
||||
Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
|
||||
}
|
||||
I += 1 + SymRef.getNumberOfAuxSymbols();
|
||||
@@ -144,12 +144,12 @@ Error COFFReader::setRelocTargets(Object &Obj) const {
|
||||
for (Section &Sec : Obj.getMutableSections()) {
|
||||
for (Relocation &R : Sec.Relocs) {
|
||||
if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
|
||||
- return make_error<StringError>("SymbolTableIndex out of range",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "SymbolTableIndex out of range");
|
||||
const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
|
||||
if (Sym == nullptr)
|
||||
- return make_error<StringError>("Invalid SymbolTableIndex",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Invalid SymbolTableIndex");
|
||||
R.Target = Sym->UniqueId;
|
||||
R.TargetName = Sym->Name;
|
||||
}
|
||||
@@ -169,8 +169,8 @@ Expected<std::unique_ptr<Object>> COFFReader::create() const {
|
||||
Obj->CoffFileHeader = *CFH;
|
||||
} else {
|
||||
if (!CBFH)
|
||||
- return make_error<StringError>("No COFF file header returned",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "No COFF file header returned");
|
||||
// Only copying the few fields from the bigobj header that we need
|
||||
// and won't recreate in the end.
|
||||
Obj->CoffFileHeader.Machine = CBFH->Machine;
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
index 9fb7812672b..0321f94a896 100644
|
||||
--- a/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
@@ -29,10 +29,9 @@ Error COFFWriter::finalizeRelocTargets() {
|
||||
for (Relocation &R : Sec.Relocs) {
|
||||
const Symbol *Sym = Obj.findSymbol(R.Target);
|
||||
if (Sym == nullptr)
|
||||
- return make_error<StringError>("Relocation target " + R.TargetName +
|
||||
- " (" + Twine(R.Target) +
|
||||
- ") not found",
|
||||
- object_error::invalid_symbol_index);
|
||||
+ return createStringError(object_error::invalid_symbol_index,
|
||||
+ "Relocation target '%s' (%zu) not found",
|
||||
+ R.TargetName.str().c_str(), R.Target);
|
||||
R.Reloc.SymbolTableIndex = Sym->RawIndex;
|
||||
}
|
||||
}
|
||||
@@ -48,9 +47,9 @@ Error COFFWriter::finalizeSectionNumbers() {
|
||||
} else {
|
||||
const Section *Sec = Obj.findSection(Sym.TargetSectionId);
|
||||
if (Sec == nullptr)
|
||||
- return make_error<StringError>("Symbol " + Sym.Name +
|
||||
- " points to a removed section",
|
||||
- object_error::invalid_symbol_index);
|
||||
+ return createStringError(object_error::invalid_symbol_index,
|
||||
+ "Symbol '%s' points to a removed section",
|
||||
+ Sym.Name.str().c_str());
|
||||
Sym.Sym.SectionNumber = Sec->Index;
|
||||
|
||||
if (Sym.Sym.NumberOfAuxSymbols == 1 &&
|
||||
@@ -65,9 +64,10 @@ Error COFFWriter::finalizeSectionNumbers() {
|
||||
} else {
|
||||
Sec = Obj.findSection(Sym.AssociativeComdatTargetSectionId);
|
||||
if (Sec == nullptr)
|
||||
- return make_error<StringError>(
|
||||
- "Symbol " + Sym.Name + " is associative to a removed section",
|
||||
- object_error::invalid_symbol_index);
|
||||
+ return createStringError(
|
||||
+ object_error::invalid_symbol_index,
|
||||
+ "Symbol '%s' is associative to a removed section",
|
||||
+ Sym.Name.str().c_str());
|
||||
SDSectionNumber = Sec->Index;
|
||||
}
|
||||
// Update the section definition with the new section number.
|
||||
@@ -343,9 +343,8 @@ Error COFFWriter::patchDebugDirectory() {
|
||||
S.Header.VirtualAddress + S.Header.SizeOfRawData) {
|
||||
if (Dir->RelativeVirtualAddress + Dir->Size >
|
||||
S.Header.VirtualAddress + S.Header.SizeOfRawData)
|
||||
- return make_error<StringError>(
|
||||
- "Debug directory extends past end of section",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Debug directory extends past end of section");
|
||||
|
||||
size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
|
||||
uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
|
||||
@@ -361,15 +360,15 @@ Error COFFWriter::patchDebugDirectory() {
|
||||
return Error::success();
|
||||
}
|
||||
}
|
||||
- return make_error<StringError>("Debug directory not found",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Debug directory not found");
|
||||
}
|
||||
|
||||
Error COFFWriter::write() {
|
||||
bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16;
|
||||
if (IsBigObj && Obj.IsPE)
|
||||
- return make_error<StringError>("Too many sections for executable",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed,
|
||||
+ "Too many sections for executable");
|
||||
return write(IsBigObj);
|
||||
}
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
|
||||
index db0cd76ced4..a2996395c1f 100644
|
||||
--- a/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
|
||||
@@ -185,9 +185,10 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
|
||||
for (auto &Sec : Obj.sections()) {
|
||||
if (Sec.Name == SecName) {
|
||||
if (Sec.OriginalData.empty())
|
||||
- return make_error<StringError>("Can't dump section \"" + SecName +
|
||||
- "\": it has no contents",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(
|
||||
+ object_error::parse_failed,
|
||||
+ "Can't dump section \"%s\": it has no contents",
|
||||
+ SecName.str().c_str());
|
||||
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
||||
FileOutputBuffer::create(Filename, Sec.OriginalData.size());
|
||||
if (!BufferOrErr)
|
||||
@@ -200,8 +201,7 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
|
||||
return Error::success();
|
||||
}
|
||||
}
|
||||
- return make_error<StringError>("Section not found",
|
||||
- object_error::parse_failed);
|
||||
+ return createStringError(object_error::parse_failed, "Section not found");
|
||||
}
|
||||
|
||||
static bool isCompressed(const SectionBase &Section) {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,330 @@
|
||||
From 8cf7aa39d7c9461e2d765f6d4fa7e0925571695f Mon Sep 17 00:00:00 2001
|
||||
From: Jordan Rupprecht <rupprecht@google.com>
|
||||
Date: Tue, 22 Jan 2019 23:49:16 +0000
|
||||
Subject: [PATCH] [llvm-objcopy] Return Error from Buffer::allocate(),
|
||||
[ELF]Writer::finalize(), and [ELF]Writer::commit()
|
||||
|
||||
Summary:
|
||||
This patch changes a few methods to return Error instead of manually calling error/reportError to abort. This will make it easier to extract into a library.
|
||||
|
||||
Note that error() takes just a string (this patch also adds an overload that takes an Error), while reportError() takes string + [error/code]. To help unify things, use FileError to associate a given filename with an error. Note that this takes some special care (for now), e.g. calling reportError(FileName, <something that could be FileError>) will duplicate the filename. The goal is to eventually remove reportError() and have every error associated with a file to be a FileError, and just one error handling block at the tool level.
|
||||
|
||||
This change was suggested in D56806. I took it a little further than suggested, but completely fixing llvm-objcopy will take a couple more patches. If this approach looks good, I'll commit this and apply similar patche(s) for the rest.
|
||||
|
||||
This change is NFC in terms of non-error related code, although the error message changes in one context.
|
||||
|
||||
Reviewers: alexshap, jhenderson, jakehehrlich, mstorsjo, espindola
|
||||
|
||||
Reviewed By: alexshap, jhenderson
|
||||
|
||||
Subscribers: llvm-commits, emaste, arichardson
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D56930
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351896 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
.../ELF/fail-no-output-directory.test | 2 +-
|
||||
tools/llvm-objcopy/Buffer.cpp | 20 ++++++++++++-----
|
||||
tools/llvm-objcopy/Buffer.h | 6 ++---
|
||||
tools/llvm-objcopy/COFF/Writer.cpp | 3 ++-
|
||||
tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 18 ++++++++++-----
|
||||
tools/llvm-objcopy/ELF/Object.cpp | 22 ++++++++++---------
|
||||
tools/llvm-objcopy/ELF/Object.h | 12 +++++-----
|
||||
tools/llvm-objcopy/llvm-objcopy.cpp | 15 +++++++++++--
|
||||
tools/llvm-objcopy/llvm-objcopy.h | 1 +
|
||||
9 files changed, 64 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/llvm/test/tools/llvm-objcopy/ELF/fail-no-output-directory.test b/llvm/test/tools/llvm-objcopy/ELF/fail-no-output-directory.test
|
||||
index f66b2e09fce..732046fa925 100644
|
||||
--- a/llvm/test/tools/llvm-objcopy/ELF/fail-no-output-directory.test
|
||||
+++ b/llvm/test/tools/llvm-objcopy/ELF/fail-no-output-directory.test
|
||||
@@ -1,6 +1,6 @@
|
||||
# RUN: yaml2obj %s > %t
|
||||
# RUN: not llvm-objcopy %t no/such/dir 2>&1 | FileCheck %s
|
||||
-# CHECK: failed to open no/such/dir:
|
||||
+# CHECK: error: 'no/such/dir': No such file or directory
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
diff --git a/llvm/tools/llvm-objcopy/Buffer.cpp b/llvm/tools/llvm-objcopy/Buffer.cpp
|
||||
index 2da03dee1af..1789097f276 100644
|
||||
--- a/llvm/tools/llvm-objcopy/Buffer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/Buffer.cpp
|
||||
@@ -17,23 +17,31 @@ namespace objcopy {
|
||||
|
||||
Buffer::~Buffer() {}
|
||||
|
||||
-void FileBuffer::allocate(size_t Size) {
|
||||
+Error FileBuffer::allocate(size_t Size) {
|
||||
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
||||
FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
|
||||
- handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) {
|
||||
- error("failed to open " + getName() + ": " + E.message());
|
||||
- });
|
||||
+ // FileOutputBuffer::create() returns an Error that is just a wrapper around
|
||||
+ // std::error_code. Wrap it in FileError to include the actual filename.
|
||||
+ if (!BufferOrErr)
|
||||
+ return createFileError(getName(), BufferOrErr.takeError());
|
||||
Buf = std::move(*BufferOrErr);
|
||||
+ return Error::success();
|
||||
}
|
||||
|
||||
-Error FileBuffer::commit() { return Buf->commit(); }
|
||||
+Error FileBuffer::commit() {
|
||||
+ Error Err = Buf->commit();
|
||||
+ // FileOutputBuffer::commit() returns an Error that is just a wrapper around
|
||||
+ // std::error_code. Wrap it in FileError to include the actual filename.
|
||||
+ return Err ? createFileError(getName(), std::move(Err)) : std::move(Err);
|
||||
+}
|
||||
|
||||
uint8_t *FileBuffer::getBufferStart() {
|
||||
return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
||||
}
|
||||
|
||||
-void MemBuffer::allocate(size_t Size) {
|
||||
+Error MemBuffer::allocate(size_t Size) {
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
|
||||
+ return Error::success();
|
||||
}
|
||||
|
||||
Error MemBuffer::commit() { return Error::success(); }
|
||||
diff --git a/llvm/tools/llvm-objcopy/Buffer.h b/llvm/tools/llvm-objcopy/Buffer.h
|
||||
index 482777fe05c..40670accac2 100644
|
||||
--- a/llvm/tools/llvm-objcopy/Buffer.h
|
||||
+++ b/llvm/tools/llvm-objcopy/Buffer.h
|
||||
@@ -27,7 +27,7 @@ class Buffer {
|
||||
|
||||
public:
|
||||
virtual ~Buffer();
|
||||
- virtual void allocate(size_t Size) = 0;
|
||||
+ virtual Error allocate(size_t Size) = 0;
|
||||
virtual uint8_t *getBufferStart() = 0;
|
||||
virtual Error commit() = 0;
|
||||
|
||||
@@ -39,7 +39,7 @@ class FileBuffer : public Buffer {
|
||||
std::unique_ptr<FileOutputBuffer> Buf;
|
||||
|
||||
public:
|
||||
- void allocate(size_t Size) override;
|
||||
+ Error allocate(size_t Size) override;
|
||||
uint8_t *getBufferStart() override;
|
||||
Error commit() override;
|
||||
|
||||
@@ -50,7 +50,7 @@ class MemBuffer : public Buffer {
|
||||
std::unique_ptr<WritableMemoryBuffer> Buf;
|
||||
|
||||
public:
|
||||
- void allocate(size_t Size) override;
|
||||
+ Error allocate(size_t Size) override;
|
||||
uint8_t *getBufferStart() override;
|
||||
Error commit() override;
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
index 4f57131d5ab..db3589bb119 100644
|
||||
--- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
|
||||
@@ -324,7 +324,8 @@ Error COFFWriter::write(bool IsBigObj) {
|
||||
if (Error E = finalize(IsBigObj))
|
||||
return E;
|
||||
|
||||
- Buf.allocate(FileSize);
|
||||
+ if (Error E = Buf.allocate(FileSize))
|
||||
+ return E;
|
||||
|
||||
writeHeaders(IsBigObj);
|
||||
writeSections();
|
||||
diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
|
||||
index a2996395c1f..2a52f1f9951 100644
|
||||
--- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
|
||||
@@ -176,8 +176,10 @@ static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
|
||||
DWOFile->Machine = Config.OutputArch.getValue().EMachine;
|
||||
FileBuffer FB(File);
|
||||
auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
|
||||
- Writer->finalize();
|
||||
- Writer->write();
|
||||
+ if (Error E = Writer->finalize())
|
||||
+ error(std::move(E));
|
||||
+ if (Error E = Writer->write())
|
||||
+ error(std::move(E));
|
||||
}
|
||||
|
||||
static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
|
||||
@@ -542,8 +544,10 @@ void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
|
||||
handleArgs(Config, *Obj, Reader, OutputElfType);
|
||||
std::unique_ptr<Writer> Writer =
|
||||
createWriter(Config, *Obj, Out, OutputElfType);
|
||||
- Writer->finalize();
|
||||
- Writer->write();
|
||||
+ if (Error E = Writer->finalize())
|
||||
+ error(std::move(E));
|
||||
+ if (Error E = Writer->write())
|
||||
+ error(std::move(E));
|
||||
}
|
||||
|
||||
void executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
@@ -570,8 +574,10 @@ void executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
handleArgs(Config, *Obj, Reader, OutputElfType);
|
||||
std::unique_ptr<Writer> Writer =
|
||||
createWriter(Config, *Obj, Out, OutputElfType);
|
||||
- Writer->finalize();
|
||||
- Writer->write();
|
||||
+ if (Error E = Writer->finalize())
|
||||
+ error(std::move(E));
|
||||
+ if (Error E = Writer->write())
|
||||
+ error(std::move(E));
|
||||
if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) {
|
||||
linkToBuildIdDir(Config, Config.OutputFilename,
|
||||
Config.BuildIdLinkOutput.getValue(), BuildIdBytes);
|
||||
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp
|
||||
index fecb752a39f..ef5dc5d7951 100644
|
||||
--- a/llvm/tools/llvm-objcopy/ELF/Object.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp
|
||||
@@ -1488,17 +1488,16 @@ template <class ELFT> size_t ELFWriter<ELFT>::totalSize() const {
|
||||
NullSectionSize;
|
||||
}
|
||||
|
||||
-template <class ELFT> void ELFWriter<ELFT>::write() {
|
||||
+template <class ELFT> Error ELFWriter<ELFT>::write() {
|
||||
writeEhdr();
|
||||
writePhdrs();
|
||||
writeSectionData();
|
||||
if (WriteSectionHeaders)
|
||||
writeShdrs();
|
||||
- if (auto E = Buf.commit())
|
||||
- reportError(Buf.getName(), errorToErrorCode(std::move(E)));
|
||||
+ return Buf.commit();
|
||||
}
|
||||
|
||||
-template <class ELFT> void ELFWriter<ELFT>::finalize() {
|
||||
+template <class ELFT> Error ELFWriter<ELFT>::finalize() {
|
||||
// It could happen that SectionNames has been removed and yet the user wants
|
||||
// a section header table output. We need to throw an error if a user tries
|
||||
// to do that.
|
||||
@@ -1582,21 +1581,22 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
|
||||
Section.finalize();
|
||||
}
|
||||
|
||||
- Buf.allocate(totalSize());
|
||||
+ if (Error E = Buf.allocate(totalSize()))
|
||||
+ return E;
|
||||
SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(Buf);
|
||||
+ return Error::success();
|
||||
}
|
||||
|
||||
-void BinaryWriter::write() {
|
||||
+Error BinaryWriter::write() {
|
||||
for (auto &Section : Obj.sections()) {
|
||||
if ((Section.Flags & SHF_ALLOC) == 0)
|
||||
continue;
|
||||
Section.accept(*SecWriter);
|
||||
}
|
||||
- if (auto E = Buf.commit())
|
||||
- reportError(Buf.getName(), errorToErrorCode(std::move(E)));
|
||||
+ return Buf.commit();
|
||||
}
|
||||
|
||||
-void BinaryWriter::finalize() {
|
||||
+Error BinaryWriter::finalize() {
|
||||
// TODO: Create a filter range to construct OrderedSegments from so that this
|
||||
// code can be deduped with assignOffsets above. This should also solve the
|
||||
// todo below for LayoutSections.
|
||||
@@ -1675,8 +1675,10 @@ void BinaryWriter::finalize() {
|
||||
TotalSize = std::max(TotalSize, Section->Offset + Section->Size);
|
||||
}
|
||||
|
||||
- Buf.allocate(TotalSize);
|
||||
+ if (Error E = Buf.allocate(TotalSize))
|
||||
+ return E;
|
||||
SecWriter = llvm::make_unique<BinarySectionWriter>(Buf);
|
||||
+ return Error::success();
|
||||
}
|
||||
|
||||
template class ELFBuilder<ELF64LE>;
|
||||
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h
|
||||
index 0dcb0d888bc..9e2b64be9dc 100644
|
||||
--- a/llvm/tools/llvm-objcopy/ELF/Object.h
|
||||
+++ b/llvm/tools/llvm-objcopy/ELF/Object.h
|
||||
@@ -193,8 +193,8 @@ protected:
|
||||
|
||||
public:
|
||||
virtual ~Writer();
|
||||
- virtual void finalize() = 0;
|
||||
- virtual void write() = 0;
|
||||
+ virtual Error finalize() = 0;
|
||||
+ virtual Error write() = 0;
|
||||
|
||||
Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
|
||||
};
|
||||
@@ -226,8 +226,8 @@ public:
|
||||
virtual ~ELFWriter() {}
|
||||
bool WriteSectionHeaders = true;
|
||||
|
||||
- void finalize() override;
|
||||
- void write() override;
|
||||
+ Error finalize() override;
|
||||
+ Error write() override;
|
||||
ELFWriter(Object &Obj, Buffer &Buf, bool WSH)
|
||||
: Writer(Obj, Buf), WriteSectionHeaders(WSH) {}
|
||||
};
|
||||
@@ -240,8 +240,8 @@ private:
|
||||
|
||||
public:
|
||||
~BinaryWriter() {}
|
||||
- void finalize() override;
|
||||
- void write() override;
|
||||
+ Error finalize() override;
|
||||
+ Error write() override;
|
||||
BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
|
||||
};
|
||||
|
||||
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
|
||||
index d27395f2ae0..75d513546b7 100644
|
||||
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
|
||||
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
|
||||
@@ -56,6 +56,16 @@ LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+LLVM_ATTRIBUTE_NORETURN void error(Error E) {
|
||||
+ assert(E);
|
||||
+ std::string Buf;
|
||||
+ raw_string_ostream OS(Buf);
|
||||
+ logAllUnhandledErrors(std::move(E), OS);
|
||||
+ OS.flush();
|
||||
+ WithColor::error(errs(), ToolName) << Buf;
|
||||
+ exit(1);
|
||||
+}
|
||||
+
|
||||
LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
|
||||
assert(EC);
|
||||
WithColor::error(errs(), ToolName)
|
||||
@@ -100,10 +110,11 @@ static Error deepWriteArchive(StringRef ArcName,
|
||||
// NewArchiveMember still requires them even though writeArchive does not
|
||||
// write them on disk.
|
||||
FileBuffer FB(Member.MemberName);
|
||||
- FB.allocate(Member.Buf->getBufferSize());
|
||||
+ if (Error E = FB.allocate(Member.Buf->getBufferSize()))
|
||||
+ return E;
|
||||
std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
|
||||
FB.getBufferStart());
|
||||
- if (auto E = FB.commit())
|
||||
+ if (Error E = FB.commit())
|
||||
return E;
|
||||
}
|
||||
return Error::success();
|
||||
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.h b/llvm/tools/llvm-objcopy/llvm-objcopy.h
|
||||
index 46d8339576c..18a789ca1f8 100644
|
||||
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.h
|
||||
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.h
|
||||
@@ -19,6 +19,7 @@ namespace llvm {
|
||||
namespace objcopy {
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN extern void error(Twine Message);
|
||||
+LLVM_ATTRIBUTE_NORETURN extern void error(Error E);
|
||||
LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File, Error E);
|
||||
LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File,
|
||||
std::error_code EC);
|
||||
--
|
||||
2.17.1
|
||||
|
112
build/build-clang/r355141-arm64-cfg.patch
Normal file
112
build/build-clang/r355141-arm64-cfg.patch
Normal file
@ -0,0 +1,112 @@
|
||||
[COFF] Add address-taken import thunks to the fid table
|
||||
|
||||
https://bugs.llvm.org/show_bug.cgi?id=39799
|
||||
https://reviews.llvm.org/D58739
|
||||
|
||||
--- a/lld/COFF/Writer.cpp
|
||||
+++ b/lld/COFF/Writer.cpp
|
||||
@@ -1390,19 +1390,47 @@
|
||||
// symbol in an executable section.
|
||||
static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms,
|
||||
Symbol *S) {
|
||||
- auto *D = dyn_cast_or_null<DefinedCOFF>(S);
|
||||
-
|
||||
- // Ignore undefined symbols and references to non-functions (e.g. globals and
|
||||
- // labels).
|
||||
- if (!D ||
|
||||
- D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
|
||||
+ if (!S)
|
||||
return;
|
||||
|
||||
- // Mark the symbol as address taken if it's in an executable section.
|
||||
- Chunk *RefChunk = D->getChunk();
|
||||
- OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
|
||||
- if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
|
||||
- addSymbolToRVASet(AddressTakenSyms, D);
|
||||
+ switch (S->kind()) {
|
||||
+ case Symbol::DefinedLocalImportKind:
|
||||
+ case Symbol::DefinedImportDataKind:
|
||||
+ // Defines an __imp_ pointer, so it is data, so it is ignored.
|
||||
+ break;
|
||||
+ case Symbol::DefinedCommonKind:
|
||||
+ // Common is always data, so it is ignored.
|
||||
+ break;
|
||||
+ case Symbol::DefinedAbsoluteKind:
|
||||
+ case Symbol::DefinedSyntheticKind:
|
||||
+ // Absolute is never code, synthetic generally isn't and usually isn't
|
||||
+ // determinable.
|
||||
+ break;
|
||||
+ case Symbol::LazyKind:
|
||||
+ case Symbol::UndefinedKind:
|
||||
+ // Undefined symbols resolve to zero, so they don't have an RVA. Lazy
|
||||
+ // symbols shouldn't have relocations.
|
||||
+ break;
|
||||
+
|
||||
+ case Symbol::DefinedImportThunkKind:
|
||||
+ // Thunks are always code, include them.
|
||||
+ addSymbolToRVASet(AddressTakenSyms, cast<Defined>(S));
|
||||
+ break;
|
||||
+
|
||||
+ case Symbol::DefinedRegularKind: {
|
||||
+ // This is a regular, defined, symbol from a COFF file. Mark the symbol as
|
||||
+ // address taken if the symbol type is function and it's in an executable
|
||||
+ // section.
|
||||
+ auto *D = cast<DefinedRegular>(S);
|
||||
+ if (D->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {
|
||||
+ Chunk *RefChunk = D->getChunk();
|
||||
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
|
||||
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
|
||||
+ addSymbolToRVASet(AddressTakenSyms, D);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
// Visit all relocations from all section contributions of this object file and
|
||||
--- a/lld/test/COFF/guardcf-thunk.s
|
||||
+++ b/lld/test/COFF/guardcf-thunk.s
|
||||
@@ -0,0 +1,43 @@
|
||||
+# REQUIRES: x86
|
||||
+
|
||||
+# Make a DLL that exports exportfn1.
|
||||
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /implib:%t.lib
|
||||
+
|
||||
+# Make an obj that takes the address of that exported function.
|
||||
+# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t2.obj
|
||||
+# RUN: lld-link -entry:main -guard:cf %t2.obj %t.lib -nodefaultlib -out:%t.exe
|
||||
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s
|
||||
+
|
||||
+# Check that the gfids table contains *exactly* two entries, one for exportfn1
|
||||
+# and one for main.
|
||||
+# CHECK: GuardFidTable [
|
||||
+# CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}}
|
||||
+# CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}}
|
||||
+# CHECK-NEXT: ]
|
||||
+
|
||||
+
|
||||
+ .def @feat.00;
|
||||
+ .scl 3;
|
||||
+ .type 0;
|
||||
+ .endef
|
||||
+ .globl @feat.00
|
||||
+@feat.00 = 0x001
|
||||
+
|
||||
+ .section .text,"rx"
|
||||
+ .def main; .scl 2; .type 32; .endef
|
||||
+ .global main
|
||||
+main:
|
||||
+ leaq exportfn1(%rip), %rax
|
||||
+ retq
|
||||
+
|
||||
+ .section .rdata,"dr"
|
||||
+.globl _load_config_used
|
||||
+_load_config_used:
|
||||
+ .long 256
|
||||
+ .fill 124, 1, 0
|
||||
+ .quad __guard_fids_table
|
||||
+ .quad __guard_fids_count
|
||||
+ .long __guard_flags
|
||||
+ .fill 128, 1, 0
|
||||
+
|
@ -1666,9 +1666,10 @@ def security_hardening_cflags(hardening_flag, asan, optimize, c_compiler, target
|
||||
js_ldflags.append("-Wl,--dynamicbase")
|
||||
|
||||
# Control Flow Guard (CFG) ----------------------------
|
||||
# See Bug 1525588 for why this doesn't work on Windows ARM
|
||||
# On aarch64, this is enabled only with explicit --enable-hardening
|
||||
# (roughly: automation) due to a dependency on a patched clang-cl.
|
||||
if c_compiler.type == 'clang-cl' and c_compiler.version >= '8' and \
|
||||
target.cpu != 'aarch64':
|
||||
(target.cpu != 'aarch64' or hardening_flag):
|
||||
flags.append("-guard:cf")
|
||||
js_flags.append("-guard:cf")
|
||||
# nolongjmp is needed because clang doesn't emit the CFG tables of
|
||||
|
@ -19,8 +19,8 @@ syn = { features = ["clone-impls", "default", "derive", "extra-traits", "full",
|
||||
log = { features = ["release_max_level_info", "release_max_level_warn", "std"], version = "0.4.6" }
|
||||
serde = { features = ["default", "rc", "serde_derive", "std"], version = "1.0.66" }
|
||||
serde_derive = { features = ["default", "deserialize_in_place"], version = "1.0.66" }
|
||||
quote = { features = ["default", "proc-macro"], version = "0.5.2" }
|
||||
proc-macro2 = { features = ["default", "proc-macro"], version = "0.3.5" }
|
||||
quote = { features = ["default", "proc-macro"], version = "0.6.11" }
|
||||
proc-macro2 = { features = ["default", "proc-macro"], version = "0.4.27" }
|
||||
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3.6"
|
||||
|
@ -18,7 +18,7 @@ function execOut(...args) {
|
||||
let out;
|
||||
let err;
|
||||
try {
|
||||
out = execFileSync(...args);
|
||||
out = execFileSync(...args, { silent: true });
|
||||
} catch (e) {
|
||||
out = e.stdout;
|
||||
err = e.stderr;
|
||||
@ -26,8 +26,7 @@ function execOut(...args) {
|
||||
return { out: out.toString(), err: err && err.toString() };
|
||||
}
|
||||
|
||||
function logErrors(tool, text, regexp) {
|
||||
const errors = text.match(regexp) || [];
|
||||
function logErrors(tool, errors) {
|
||||
for (const error of errors) {
|
||||
console.log(`TEST-UNEXPECTED-FAIL ${tool} | ${error}`);
|
||||
}
|
||||
@ -64,23 +63,37 @@ function eslint() {
|
||||
logStart("Eslint");
|
||||
const { out } = execOut("yarn", ["lint:js"]);
|
||||
console.log(out);
|
||||
const errors = logErrors("eslint", out, / {2}error {2}(.*)/g);
|
||||
const errors = logErrors("eslint", out.match(/ {2}error {2}(.*)/g) || []);
|
||||
|
||||
return errors.length == 0;
|
||||
}
|
||||
|
||||
function jest() {
|
||||
logStart("Jest");
|
||||
const { out, err } = execOut("yarn", ["test"]);
|
||||
console.log(err);
|
||||
const errors = logErrors("jest", err || "", / {4}✕(.*)/g);
|
||||
return errors.length == 0;
|
||||
const { out } = execOut("yarn", ["test-ci"]);
|
||||
// Remove the non-JSON logs mixed with the JSON output by yarn.
|
||||
const jsonOut = out.substring(out.indexOf("{"), out.lastIndexOf("}") + 1);
|
||||
const results = JSON.parse(jsonOut);
|
||||
|
||||
const failed = results.numFailedTests == 0;
|
||||
|
||||
// The individual failing tests are in jammed into the same message string :/
|
||||
const errors = [].concat(
|
||||
...results.testResults.map(r =>
|
||||
r.message.split("\n").filter(l => l.includes("●"))
|
||||
)
|
||||
);
|
||||
|
||||
logErrors("jest", errors);
|
||||
return failed;
|
||||
}
|
||||
|
||||
function stylelint() {
|
||||
logStart("Stylelint");
|
||||
const { out } = execOut("yarn", ["lint:css"]);
|
||||
console.log(out);
|
||||
const errors = logErrors("stylelint", out, / {2}✖(.*)/g);
|
||||
const errors = logErrors("stylelint", out.match(/ {2}✖(.*)/g) || []);
|
||||
|
||||
return errors.length == 0;
|
||||
}
|
||||
|
||||
@ -91,8 +104,7 @@ function jsxAccessibility() {
|
||||
console.log(out);
|
||||
const errors = logErrors(
|
||||
"eslint (jsx accessibility)",
|
||||
out,
|
||||
/ {2}error {2}(.*)/g
|
||||
out.match(/ {2}error {2}(.*)/g) || []
|
||||
);
|
||||
return errors.length == 0;
|
||||
}
|
||||
@ -100,8 +112,8 @@ function jsxAccessibility() {
|
||||
function lintMd() {
|
||||
logStart("Remark");
|
||||
|
||||
const { out, err } = execOut("yarn", ["lint:md"]);
|
||||
const errors = logErrors("remark", err || "", /warning(.+)/g);
|
||||
const { err } = execOut("yarn", ["lint:md"]);
|
||||
const errors = logErrors("remark", (err || "").match(/warning(.+)/g) || []);
|
||||
return errors.length == 0;
|
||||
}
|
||||
|
||||
@ -127,7 +139,8 @@ console.log({
|
||||
jestPassed,
|
||||
styleLintPassed,
|
||||
jsxAccessibilityPassed,
|
||||
remarkPassed
|
||||
remarkPassed,
|
||||
});
|
||||
|
||||
process.exitCode = success ? 0 : 1;
|
||||
console.log("CODE", process.exitCode);
|
||||
|
@ -30,6 +30,7 @@
|
||||
"mochih": "yarn mochi -- --headless --",
|
||||
"mochici": "mochii --mc ./firefox --ci --default-test-path devtools/client/debugger --headless --",
|
||||
"test": "TZ=Africa/Nairobi jest",
|
||||
"test-ci": "TZ=Africa/Nairobi jest --json",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "yarn test --coverage",
|
||||
"test:all": "yarn test; yarn lint; yarn flow",
|
||||
|
@ -102,7 +102,7 @@ exports[`ObjectInspector - dimTopLevelWindow renders sub-level window 1`] = `
|
||||
role="treeitem"
|
||||
>
|
||||
<span
|
||||
className="tree-indent"
|
||||
className="tree-indent tree-last-indent"
|
||||
>
|
||||
|
||||
</span>
|
||||
@ -254,7 +254,7 @@ exports[`ObjectInspector - dimTopLevelWindow renders window as expected when dim
|
||||
role="treeitem"
|
||||
>
|
||||
<span
|
||||
className="tree-indent"
|
||||
className="tree-indent tree-last-indent"
|
||||
>
|
||||
|
||||
</span>
|
||||
|
@ -47,11 +47,10 @@ describe("network request", () => {
|
||||
it("timed out fetch", async () => {
|
||||
global.fetch.mockImplementation(async () => {});
|
||||
|
||||
try {
|
||||
await networkRequest("foo");
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line jest/valid-expect-in-promise
|
||||
networkRequest("foo").catch(e => {
|
||||
expect(e.message).toEqual("Connect timeout error");
|
||||
}
|
||||
});
|
||||
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
@ -119,32 +119,4 @@ describe("worker utils", () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("test a task completing when the worker has shutdown", async () => {
|
||||
const dispatcher = new WorkerDispatcher();
|
||||
const postMessageMock = jest.fn();
|
||||
const addEventListenerMock = jest.fn();
|
||||
const terminateMock = jest.fn();
|
||||
|
||||
global.Worker = jest.fn(() => {
|
||||
return {
|
||||
postMessage: postMessageMock,
|
||||
addEventListener: addEventListenerMock,
|
||||
terminate: terminateMock,
|
||||
};
|
||||
});
|
||||
|
||||
dispatcher.start();
|
||||
const task = dispatcher.task("foo");
|
||||
|
||||
try {
|
||||
await task("bar");
|
||||
} catch (e) {
|
||||
expect(e).toEqual("Oops, The worker has shutdown!");
|
||||
}
|
||||
|
||||
const listener = addEventListenerMock.mock.calls[0][1];
|
||||
dispatcher.stop();
|
||||
listener({ data: { id: 1 } });
|
||||
});
|
||||
});
|
||||
|
@ -4,29 +4,88 @@
|
||||
|
||||
// @flow
|
||||
|
||||
import { uniq, remove } from "lodash";
|
||||
|
||||
import { asyncStore } from "../utils/prefs";
|
||||
|
||||
import {
|
||||
getActiveEventListeners,
|
||||
getEventListenerExpanded,
|
||||
} from "../selectors";
|
||||
|
||||
import type { ThunkArgs } from "./types";
|
||||
import type { EventListenerBreakpoints } from "../types";
|
||||
|
||||
export function addEventListeners(events: EventListenerBreakpoints) {
|
||||
return async ({ dispatch, client }: ThunkArgs) => {
|
||||
await dispatch({
|
||||
type: "ADD_EVENT_LISTENERS",
|
||||
events,
|
||||
});
|
||||
const newList = await asyncStore.eventListenerBreakpoints;
|
||||
client.setEventListenerBreakpoints(newList);
|
||||
async function updateBreakpoints(dispatch, client, newEvents: string[]) {
|
||||
dispatch({ type: "UPDATE_EVENT_LISTENERS", active: newEvents });
|
||||
|
||||
const current = await asyncStore.eventListenerBreakpoints;
|
||||
asyncStore.eventListenerBreakpoints = {
|
||||
...current,
|
||||
active: newEvents,
|
||||
};
|
||||
|
||||
client.setEventListenerBreakpoints(newEvents);
|
||||
}
|
||||
|
||||
async function updateExpanded(dispatch, newExpanded: string[]) {
|
||||
dispatch({
|
||||
type: "UPDATE_EVENT_LISTENER_EXPANDED",
|
||||
expanded: newExpanded,
|
||||
});
|
||||
|
||||
const current = await asyncStore.eventListenerBreakpoints;
|
||||
asyncStore.eventListenerBreakpoints = {
|
||||
...current,
|
||||
expanded: newExpanded,
|
||||
};
|
||||
}
|
||||
|
||||
export function removeEventListeners(events: EventListenerBreakpoints) {
|
||||
return async ({ dispatch, client }: ThunkArgs) => {
|
||||
await dispatch({
|
||||
type: "REMOVE_EVENT_LISTENERS",
|
||||
events,
|
||||
});
|
||||
const newList = await asyncStore.eventListenerBreakpoints;
|
||||
client.setEventListenerBreakpoints(newList);
|
||||
export function addEventListenerBreakpoints(eventsToAdd: string[]) {
|
||||
return async ({ dispatch, client, getState }: ThunkArgs) => {
|
||||
const activeListenerBreakpoints = await getActiveEventListeners(getState());
|
||||
|
||||
const newEvents = uniq([...eventsToAdd, ...activeListenerBreakpoints]);
|
||||
|
||||
updateBreakpoints(dispatch, client, newEvents);
|
||||
};
|
||||
}
|
||||
|
||||
export function removeEventListenerBreakpoints(eventsToRemove: string[]) {
|
||||
return async ({ dispatch, client, getState }: ThunkArgs) => {
|
||||
const activeListenerBreakpoints = await getActiveEventListeners(getState());
|
||||
|
||||
const newEvents = remove(
|
||||
activeListenerBreakpoints,
|
||||
event => !eventsToRemove.includes(event)
|
||||
);
|
||||
|
||||
updateBreakpoints(dispatch, client, newEvents);
|
||||
};
|
||||
}
|
||||
|
||||
export function addEventListenerExpanded(category: string) {
|
||||
return async ({ dispatch, getState }: ThunkArgs) => {
|
||||
const expanded = await getEventListenerExpanded(getState());
|
||||
|
||||
const newExpanded = uniq([...expanded, category]);
|
||||
|
||||
await updateExpanded(dispatch, newExpanded);
|
||||
};
|
||||
}
|
||||
|
||||
export function removeEventListenerExpanded(category: string) {
|
||||
return async ({ dispatch, getState }: ThunkArgs) => {
|
||||
const expanded = await getEventListenerExpanded(getState());
|
||||
|
||||
const newExpanded = expanded.filter(expand => expand != category);
|
||||
|
||||
updateExpanded(dispatch, newExpanded);
|
||||
};
|
||||
}
|
||||
|
||||
export function getEventListenerBreakpointTypes() {
|
||||
return async ({ dispatch, client }: ThunkArgs) => {
|
||||
const categories = await client.getEventListenerBreakpointTypes();
|
||||
dispatch({ type: "RECEIVE_EVENT_LISTENER_TYPES", categories });
|
||||
};
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
|
||||
import { makeWhyNormal } from "../../../utils/test-mockup";
|
||||
|
||||
import * as parser from "../../../workers/parser/index";
|
||||
import { parserWorker } from "../../../test/tests-setup";
|
||||
|
||||
const { isStepping } = selectors;
|
||||
|
||||
@ -147,7 +147,7 @@ describe("pause", () => {
|
||||
await dispatch(actions.newGeneratedSource(makeSource("foo1")));
|
||||
await dispatch(actions.paused(mockPauseInfo));
|
||||
const cx = selectors.getThreadContext(getState());
|
||||
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
|
||||
const getNextStepSpy = jest.spyOn(parserWorker, "getNextStep");
|
||||
dispatch(actions.stepOver(cx));
|
||||
expect(getNextStepSpy).not.toHaveBeenCalled();
|
||||
expect(isStepping(getState(), "FakeThread")).toBeTruthy();
|
||||
@ -166,7 +166,7 @@ describe("pause", () => {
|
||||
|
||||
await dispatch(actions.paused(mockPauseInfo));
|
||||
const cx = selectors.getThreadContext(getState());
|
||||
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
|
||||
const getNextStepSpy = jest.spyOn(parserWorker, "getNextStep");
|
||||
dispatch(actions.stepOver(cx));
|
||||
expect(getNextStepSpy).toHaveBeenCalled();
|
||||
getNextStepSpy.mockRestore();
|
||||
@ -188,7 +188,7 @@ describe("pause", () => {
|
||||
|
||||
await dispatch(actions.paused(mockPauseInfo));
|
||||
const cx = selectors.getThreadContext(getState());
|
||||
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
|
||||
const getNextStepSpy = jest.spyOn(parserWorker, "getNextStep");
|
||||
dispatch(actions.stepOver(cx));
|
||||
expect(getNextStepSpy).toHaveBeenCalled();
|
||||
getNextStepSpy.mockRestore();
|
||||
|
@ -124,27 +124,6 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`project text search should search a specific source 2`] = `
|
||||
Array [
|
||||
Object {
|
||||
"filepath": "http://localhost:8000/examples/bar",
|
||||
"matches": Array [
|
||||
Object {
|
||||
"column": 9,
|
||||
"line": 1,
|
||||
"match": "bla",
|
||||
"matchIndex": 9,
|
||||
"sourceId": "bar",
|
||||
"type": "MATCH",
|
||||
"value": "function bla(x, y) {",
|
||||
},
|
||||
],
|
||||
"sourceId": "bar",
|
||||
"type": "RESULT",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`project text search should search all the loaded sources based on the query 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
|
@ -159,6 +159,30 @@ export type {
|
||||
|
||||
export type { panelPositionType } from "./UIAction";
|
||||
|
||||
export type { ASTAction } from "./ASTAction";
|
||||
|
||||
type ActiveEventListener = string;
|
||||
type EventListenerEvent = { name: string, id: ActiveEventListener };
|
||||
type EventListenerCategory = { name: string, events: EventListenerEvent[] };
|
||||
|
||||
export type EventListenerActiveList = ActiveEventListener[];
|
||||
export type EventListenerCategoryList = EventListenerCategory[];
|
||||
export type EventListenerExpandedList = string[];
|
||||
|
||||
export type EventListenerAction =
|
||||
| {|
|
||||
+type: "UPDATE_EVENT_LISTENERS",
|
||||
+active: EventListenerActiveList,
|
||||
|}
|
||||
| {|
|
||||
+type: "RECEIVE_EVENT_LISTENER_TYPES",
|
||||
+categories: EventListenerCategoryList,
|
||||
|}
|
||||
| {|
|
||||
+type: "UPDATE_EVENT_LISTENER_EXPANDED",
|
||||
+expanded: EventListenerExpandedList,
|
||||
|};
|
||||
|
||||
/**
|
||||
* Actions: Source, Breakpoint, and Navigation
|
||||
*
|
||||
@ -180,4 +204,5 @@ export type Action =
|
||||
| FileTextSearchAction
|
||||
| ProjectTextSearchAction
|
||||
| DebuggeeAction
|
||||
| SourceTreeAction;
|
||||
| SourceTreeAction
|
||||
| EventListenerAction;
|
||||
|
@ -47,6 +47,9 @@ export async function onConnect(connection: any, actions: Object) {
|
||||
skipBreakpoints: prefs.skipPausing,
|
||||
});
|
||||
|
||||
// Retrieve possible event listener breakpoints
|
||||
actions.getEventListenerBreakpointTypes();
|
||||
|
||||
// In Firefox, we need to initially request all of the sources. This
|
||||
// usually fires off individual `newSource` notifications as the
|
||||
// debugger finds them, but there may be existing sources already in
|
||||
|
@ -16,7 +16,6 @@ import type {
|
||||
BreakpointLocation,
|
||||
BreakpointOptions,
|
||||
PendingLocation,
|
||||
EventListenerBreakpoints,
|
||||
Frame,
|
||||
FrameId,
|
||||
GeneratedSourceData,
|
||||
@ -36,6 +35,8 @@ import type {
|
||||
SourcesPacket,
|
||||
} from "./types";
|
||||
|
||||
import type { EventListenerCategoryList } from "../../actions/types";
|
||||
|
||||
let workerClients: Object;
|
||||
let threadClient: ThreadClient;
|
||||
let tabTarget: TabTarget;
|
||||
@ -361,8 +362,17 @@ function interrupt(thread: string): Promise<*> {
|
||||
return lookupThreadClient(thread).interrupt();
|
||||
}
|
||||
|
||||
function setEventListenerBreakpoints(eventTypes: EventListenerBreakpoints) {
|
||||
// TODO: Figure out what sendpoint we want to hit
|
||||
async function setEventListenerBreakpoints(ids: string[]) {
|
||||
await threadClient.setActiveEventBreakpoints(ids);
|
||||
await forEachWorkerThread(thread => thread.setActiveEventBreakpoints(ids));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
async function getEventListenerBreakpointTypes(): Promise<
|
||||
EventListenerCategoryList
|
||||
> {
|
||||
const { value } = await threadClient.getAvailableEventBreakpoints();
|
||||
return value;
|
||||
}
|
||||
|
||||
function pauseGrip(thread: string, func: Function): ObjectClient {
|
||||
@ -525,6 +535,7 @@ const clientCommands = {
|
||||
sendPacket,
|
||||
setSkipPausing,
|
||||
setEventListenerBreakpoints,
|
||||
getEventListenerBreakpointTypes,
|
||||
waitForWorkers,
|
||||
detachWorkers,
|
||||
hasWasmSupport,
|
||||
|
@ -25,6 +25,8 @@ import type {
|
||||
Range,
|
||||
} from "../../types";
|
||||
|
||||
import type { EventListenerCategoryList } from "../../actions/types";
|
||||
|
||||
type URL = string;
|
||||
|
||||
/**
|
||||
@ -369,7 +371,10 @@ export type ThreadClient = {
|
||||
actor: ActorId,
|
||||
request: (payload: Object) => Promise<*>,
|
||||
url: string,
|
||||
setEventListenerBreakpoints: (string[]) => void,
|
||||
setActiveEventBreakpoints: (string[]) => void,
|
||||
getAvailableEventBreakpoints: () => Promise<{|
|
||||
value: EventListenerCategoryList,
|
||||
|}>,
|
||||
skipBreakpoints: boolean => Promise<{| skip: boolean |}>,
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
bootstrapStore,
|
||||
bootstrapWorkers,
|
||||
} from "../utils/bootstrap";
|
||||
|
||||
import { initialBreakpointsState } from "../reducers/breakpoints";
|
||||
|
||||
import type { Panel } from "./firefox/types";
|
||||
@ -47,7 +48,12 @@ async function loadInitialState() {
|
||||
|
||||
const breakpoints = initialBreakpointsState(xhrBreakpoints);
|
||||
|
||||
return { pendingBreakpoints, tabs, breakpoints, eventListenerBreakpoints };
|
||||
return {
|
||||
pendingBreakpoints,
|
||||
tabs,
|
||||
breakpoints,
|
||||
eventListenerBreakpoints,
|
||||
};
|
||||
}
|
||||
|
||||
function getClient(connection: any) {
|
||||
|
@ -9,141 +9,121 @@ import classnames from "classnames";
|
||||
|
||||
import { connect } from "../../utils/connect";
|
||||
import actions from "../../actions";
|
||||
import { getActiveEventListeners } from "../../selectors";
|
||||
import {
|
||||
getActiveEventListeners,
|
||||
getEventListenerBreakpointTypes,
|
||||
getEventListenerExpanded,
|
||||
} from "../../selectors";
|
||||
|
||||
import AccessibleImage from "../shared/AccessibleImage";
|
||||
|
||||
import type { EventListenerBreakpoints } from "../../types";
|
||||
import type {
|
||||
EventListenerActiveList,
|
||||
EventListenerCategoryList,
|
||||
EventListenerExpandedList,
|
||||
} from "../../actions/types";
|
||||
|
||||
import "./EventListeners.css";
|
||||
|
||||
const CATEGORIES = {
|
||||
Mouse: ["click", "mouseover", "dblclick"],
|
||||
Keyboard: ["keyup", "keydown"],
|
||||
};
|
||||
|
||||
type Props = {
|
||||
addEventListeners: typeof actions.addEventListeners,
|
||||
removeEventListeners: typeof actions.removeEventListeners,
|
||||
activeEventListeners: EventListenerBreakpoints,
|
||||
categories: EventListenerCategoryList,
|
||||
expandedCategories: EventListenerExpandedList,
|
||||
activeEventListeners: EventListenerActiveList,
|
||||
addEventListeners: typeof actions.addEventListenerBreakpoints,
|
||||
removeEventListeners: typeof actions.removeEventListenerBreakpoints,
|
||||
addEventListenerExpanded: typeof actions.addEventListenerExpanded,
|
||||
removeEventListenerExpanded: typeof actions.removeEventListenerExpanded,
|
||||
};
|
||||
|
||||
type State = {
|
||||
expandedCategories: string[],
|
||||
};
|
||||
|
||||
function getKey(category: string, eventType: string) {
|
||||
return `${category}:${eventType}`;
|
||||
}
|
||||
|
||||
class EventListeners extends Component<Props, State> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
expandedCategories: [],
|
||||
};
|
||||
}
|
||||
|
||||
onCategoryToggle(category, event) {
|
||||
const { expandedCategories } = this.state;
|
||||
class EventListeners extends Component<Props> {
|
||||
onCategoryToggle(category) {
|
||||
const {
|
||||
expandedCategories,
|
||||
removeEventListenerExpanded,
|
||||
addEventListenerExpanded,
|
||||
} = this.props;
|
||||
|
||||
if (expandedCategories.includes(category)) {
|
||||
this.setState({
|
||||
expandedCategories: expandedCategories.filter(
|
||||
eventCategory => eventCategory !== category
|
||||
),
|
||||
});
|
||||
removeEventListenerExpanded(category);
|
||||
} else {
|
||||
this.setState({
|
||||
expandedCategories: [...expandedCategories, category],
|
||||
});
|
||||
addEventListenerExpanded(category);
|
||||
}
|
||||
}
|
||||
|
||||
onCategoryClick(category, isChecked) {
|
||||
const { addEventListeners, removeEventListeners } = this.props;
|
||||
const events = CATEGORIES[category].map(eventType =>
|
||||
getKey(category, eventType)
|
||||
);
|
||||
const eventsIds = category.events.map(event => event.id);
|
||||
|
||||
if (isChecked) {
|
||||
addEventListeners(events);
|
||||
addEventListeners(eventsIds);
|
||||
} else {
|
||||
removeEventListeners(events);
|
||||
removeEventListeners(eventsIds);
|
||||
}
|
||||
}
|
||||
|
||||
onEventTypeClick(eventType, isChecked) {
|
||||
onEventTypeClick(eventId, isChecked) {
|
||||
const { addEventListeners, removeEventListeners } = this.props;
|
||||
if (isChecked) {
|
||||
addEventListeners([eventType]);
|
||||
addEventListeners([eventId]);
|
||||
} else {
|
||||
removeEventListeners([eventType]);
|
||||
removeEventListeners([eventId]);
|
||||
}
|
||||
}
|
||||
|
||||
renderCategoryHeading(category) {
|
||||
const { expandedCategories } = this.state;
|
||||
const { activeEventListeners } = this.props;
|
||||
const { activeEventListeners, expandedCategories } = this.props;
|
||||
const { events } = category;
|
||||
|
||||
const eventTypes = CATEGORIES[category];
|
||||
|
||||
const expanded = expandedCategories.includes(category);
|
||||
const checked = eventTypes.every(eventType =>
|
||||
activeEventListeners.includes(getKey(category, eventType))
|
||||
);
|
||||
const expanded = expandedCategories.includes(category.name);
|
||||
const checked = events.every(({ id }) => activeEventListeners.includes(id));
|
||||
const indeterminate =
|
||||
!checked &&
|
||||
eventTypes.some(eventType =>
|
||||
activeEventListeners.includes(getKey(category, eventType))
|
||||
);
|
||||
!checked && events.some(({ id }) => activeEventListeners.includes(id));
|
||||
|
||||
return (
|
||||
<div className="event-listener-header">
|
||||
<button
|
||||
className="event-listener-expand"
|
||||
onClick={e => this.onCategoryToggle(category, e)}
|
||||
onClick={() => this.onCategoryToggle(category.name)}
|
||||
>
|
||||
<AccessibleImage className={classnames("arrow", { expanded })} />
|
||||
</button>
|
||||
<label className="event-listener-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
value={category}
|
||||
value={category.name}
|
||||
onChange={e => this.onCategoryClick(category, e.target.checked)}
|
||||
checked={checked}
|
||||
ref={el => el && (el.indeterminate = indeterminate)}
|
||||
/>
|
||||
<span className="event-listener-category">{category}</span>
|
||||
<span className="event-listener-category">{category.name}</span>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderCategoryListing(category) {
|
||||
const { activeEventListeners } = this.props;
|
||||
const { expandedCategories } = this.state;
|
||||
const { activeEventListeners, expandedCategories } = this.props;
|
||||
|
||||
const expanded = expandedCategories.includes(category);
|
||||
const expanded = expandedCategories.includes(category.name);
|
||||
if (!expanded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{CATEGORIES[category].map(eventType => {
|
||||
const key = getKey(category, eventType);
|
||||
{category.events.map(event => {
|
||||
return (
|
||||
<li className="event-listener-event" key={key}>
|
||||
<li className="event-listener-event" key={event.id}>
|
||||
<label className="event-listener-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
value={key}
|
||||
onChange={e => this.onEventTypeClick(key, e.target.checked)}
|
||||
checked={activeEventListeners.includes(key)}
|
||||
value={event.id}
|
||||
onChange={e =>
|
||||
this.onEventTypeClick(event.id, e.target.checked)
|
||||
}
|
||||
checked={activeEventListeners.includes(event.id)}
|
||||
/>
|
||||
<span className="event-listener-name">{eventType}</span>
|
||||
<span className="event-listener-name">{event.name}</span>
|
||||
</label>
|
||||
</li>
|
||||
);
|
||||
@ -153,12 +133,14 @@ class EventListeners extends Component<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { categories } = this.props;
|
||||
|
||||
return (
|
||||
<div className="event-listeners-content">
|
||||
<ul className="event-listeners-list">
|
||||
{Object.keys(CATEGORIES).map(category => {
|
||||
{categories.map((category, index) => {
|
||||
return (
|
||||
<li className="event-listener-group" key={category}>
|
||||
<li className="event-listener-group" key={index}>
|
||||
{this.renderCategoryHeading(category)}
|
||||
{this.renderCategoryListing(category)}
|
||||
</li>
|
||||
@ -170,14 +152,20 @@ class EventListeners extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
activeEventListeners: getActiveEventListeners(state),
|
||||
});
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
activeEventListeners: getActiveEventListeners(state),
|
||||
categories: getEventListenerBreakpointTypes(state),
|
||||
expandedCategories: getEventListenerExpanded(state),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
addEventListeners: actions.addEventListeners,
|
||||
removeEventListeners: actions.removeEventListeners,
|
||||
addEventListeners: actions.addEventListenerBreakpoints,
|
||||
removeEventListeners: actions.removeEventListenerBreakpoints,
|
||||
addEventListenerExpanded: actions.addEventListenerExpanded,
|
||||
removeEventListenerExpanded: actions.removeEventListenerExpanded,
|
||||
}
|
||||
)(EventListeners);
|
||||
|
@ -0,0 +1,82 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
// @flow
|
||||
|
||||
import React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
import EventListeners from "../EventListeners";
|
||||
|
||||
function getCategories() {
|
||||
return [
|
||||
{
|
||||
name: "Category 1",
|
||||
events: [
|
||||
{ name: "Subcategory 1", id: "category1.subcategory1" },
|
||||
{ name: "Subcategory 2", id: "category1.subcategory2" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Category 2",
|
||||
events: [
|
||||
{ name: "Subcategory 3", id: "category2.subcategory1" },
|
||||
{ name: "Subcategory 4", id: "category2.subcategory2" },
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function generateDefaults(overrides = {}) {
|
||||
const defaults = {
|
||||
activeEventListeners: [],
|
||||
expandedCategories: [],
|
||||
categories: [],
|
||||
};
|
||||
|
||||
return { ...defaults, ...overrides };
|
||||
}
|
||||
|
||||
function render(overrides = {}) {
|
||||
const props = generateDefaults(overrides);
|
||||
// $FlowIgnore
|
||||
const component = shallow(<EventListeners.WrappedComponent {...props} />);
|
||||
return { component, props };
|
||||
}
|
||||
|
||||
describe("EventListeners", () => {
|
||||
it("should render", async () => {
|
||||
const { component } = render();
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render categories appropriately", async () => {
|
||||
const props = {
|
||||
...generateDefaults(),
|
||||
categories: getCategories(),
|
||||
};
|
||||
const { component } = render(props);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render expanded categories appropriately", async () => {
|
||||
const props = {
|
||||
...generateDefaults(),
|
||||
categories: getCategories(),
|
||||
expandedCategories: ["Category 2"],
|
||||
};
|
||||
const { component } = render(props);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render checked subcategories appropriately", async () => {
|
||||
const props = {
|
||||
...generateDefaults(),
|
||||
categories: getCategories(),
|
||||
activeEventListeners: ["category1.subcategory2"],
|
||||
expandedCategories: ["Category 1"],
|
||||
};
|
||||
const { component } = render(props);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -0,0 +1,320 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`EventListeners should render 1`] = `
|
||||
<div
|
||||
className="event-listeners-content"
|
||||
>
|
||||
<ul
|
||||
className="event-listeners-list"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`EventListeners should render categories appropriately 1`] = `
|
||||
<div
|
||||
className="event-listeners-content"
|
||||
>
|
||||
<ul
|
||||
className="event-listeners-list"
|
||||
>
|
||||
<li
|
||||
className="event-listener-group"
|
||||
key="0"
|
||||
>
|
||||
<div
|
||||
className="event-listener-header"
|
||||
>
|
||||
<button
|
||||
className="event-listener-expand"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<AccessibleImage
|
||||
className="arrow"
|
||||
/>
|
||||
</button>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="Category 1"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-category"
|
||||
>
|
||||
Category 1
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
className="event-listener-group"
|
||||
key="1"
|
||||
>
|
||||
<div
|
||||
className="event-listener-header"
|
||||
>
|
||||
<button
|
||||
className="event-listener-expand"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<AccessibleImage
|
||||
className="arrow"
|
||||
/>
|
||||
</button>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="Category 2"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-category"
|
||||
>
|
||||
Category 2
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`EventListeners should render checked subcategories appropriately 1`] = `
|
||||
<div
|
||||
className="event-listeners-content"
|
||||
>
|
||||
<ul
|
||||
className="event-listeners-list"
|
||||
>
|
||||
<li
|
||||
className="event-listener-group"
|
||||
key="0"
|
||||
>
|
||||
<div
|
||||
className="event-listener-header"
|
||||
>
|
||||
<button
|
||||
className="event-listener-expand"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<AccessibleImage
|
||||
className="arrow expanded"
|
||||
/>
|
||||
</button>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="Category 1"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-category"
|
||||
>
|
||||
Category 1
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
className="event-listener-event"
|
||||
key="category1.subcategory1"
|
||||
>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="category1.subcategory1"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-name"
|
||||
>
|
||||
Subcategory 1
|
||||
</span>
|
||||
</label>
|
||||
</li>
|
||||
<li
|
||||
className="event-listener-event"
|
||||
key="category1.subcategory2"
|
||||
>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="category1.subcategory2"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-name"
|
||||
>
|
||||
Subcategory 2
|
||||
</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li
|
||||
className="event-listener-group"
|
||||
key="1"
|
||||
>
|
||||
<div
|
||||
className="event-listener-header"
|
||||
>
|
||||
<button
|
||||
className="event-listener-expand"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<AccessibleImage
|
||||
className="arrow"
|
||||
/>
|
||||
</button>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="Category 2"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-category"
|
||||
>
|
||||
Category 2
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`EventListeners should render expanded categories appropriately 1`] = `
|
||||
<div
|
||||
className="event-listeners-content"
|
||||
>
|
||||
<ul
|
||||
className="event-listeners-list"
|
||||
>
|
||||
<li
|
||||
className="event-listener-group"
|
||||
key="0"
|
||||
>
|
||||
<div
|
||||
className="event-listener-header"
|
||||
>
|
||||
<button
|
||||
className="event-listener-expand"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<AccessibleImage
|
||||
className="arrow"
|
||||
/>
|
||||
</button>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="Category 1"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-category"
|
||||
>
|
||||
Category 1
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
className="event-listener-group"
|
||||
key="1"
|
||||
>
|
||||
<div
|
||||
className="event-listener-header"
|
||||
>
|
||||
<button
|
||||
className="event-listener-expand"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<AccessibleImage
|
||||
className="arrow expanded"
|
||||
/>
|
||||
</button>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="Category 2"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-category"
|
||||
>
|
||||
Category 2
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
className="event-listener-event"
|
||||
key="category2.subcategory1"
|
||||
>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="category2.subcategory1"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-name"
|
||||
>
|
||||
Subcategory 3
|
||||
</span>
|
||||
</label>
|
||||
</li>
|
||||
<li
|
||||
className="event-listener-event"
|
||||
key="category2.subcategory2"
|
||||
>
|
||||
<label
|
||||
className="event-listener-label"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
value="category2.subcategory2"
|
||||
/>
|
||||
<span
|
||||
className="event-listener-name"
|
||||
>
|
||||
Subcategory 4
|
||||
</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
@ -59,10 +59,6 @@ describe("Popover", () => {
|
||||
</Popover>
|
||||
);
|
||||
|
||||
const div = document.createElement("div");
|
||||
|
||||
const event = { currentTarget: div };
|
||||
|
||||
beforeEach(() => {
|
||||
onMouseLeave.mockClear();
|
||||
onKeyDown.mockClear();
|
||||
@ -72,31 +68,6 @@ describe("Popover", () => {
|
||||
|
||||
it("render (tooltip)", () => expect(tooltip).toMatchSnapshot());
|
||||
|
||||
it("calls mouseLeave", () => {
|
||||
popover.find(".popover").simulate("mouseleave", event);
|
||||
expect(onMouseLeave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls mouseLeave (tooltip)", () => {
|
||||
tooltip.find(".tooltip").simulate("mouseleave", event);
|
||||
expect(onMouseLeave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("no mouse leave on bracket or gap", () => {
|
||||
popover.find(".bracket-arrow").simulate("mouseleave", event);
|
||||
expect(onMouseLeave).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls keyDown", () => {
|
||||
popover.find(".popover").simulate("keydown", { key: "Escape" });
|
||||
expect(onKeyDown).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls keyDown (tooltip)", () => {
|
||||
tooltip.find(".tooltip").simulate("keydown", { key: "Escape" });
|
||||
expect(onKeyDown).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("mount popover", () => {
|
||||
const mountedPopover = mount(
|
||||
<Popover
|
||||
|
@ -26,8 +26,6 @@ exports[`Popover mount popover 1`] = `
|
||||
>
|
||||
<div
|
||||
className="popover orientation-right"
|
||||
onKeyDown={[MockFunction]}
|
||||
onMouseLeave={[MockFunction]}
|
||||
style={
|
||||
Object {
|
||||
"left": 505,
|
||||
@ -88,8 +86,6 @@ exports[`Popover mount tooltip 1`] = `
|
||||
>
|
||||
<div
|
||||
className="tooltip"
|
||||
onKeyDown={[MockFunction]}
|
||||
onMouseLeave={[MockFunction]}
|
||||
style={
|
||||
Object {
|
||||
"left": -8,
|
||||
@ -111,8 +107,6 @@ exports[`Popover mount tooltip 1`] = `
|
||||
exports[`Popover render (tooltip) 1`] = `
|
||||
<div
|
||||
className="tooltip"
|
||||
onKeyDown={[MockFunction]}
|
||||
onMouseLeave={[MockFunction]}
|
||||
style={
|
||||
Object {
|
||||
"left": 0,
|
||||
@ -156,8 +150,6 @@ exports[`Popover render 1`] = `
|
||||
>
|
||||
<div
|
||||
className="popover orientation-right"
|
||||
onKeyDown={[MockFunction]}
|
||||
onMouseLeave={[MockFunction]}
|
||||
style={
|
||||
Object {
|
||||
"left": 505,
|
||||
|
@ -337,7 +337,7 @@ exports[`ProjectSearch found search results 1`] = `
|
||||
role="treeitem"
|
||||
>
|
||||
<span
|
||||
className="tree-indent"
|
||||
className="tree-indent tree-last-indent"
|
||||
>
|
||||
|
||||
</span>
|
||||
@ -405,7 +405,7 @@ exports[`ProjectSearch found search results 1`] = `
|
||||
role="treeitem"
|
||||
>
|
||||
<span
|
||||
className="tree-indent"
|
||||
className="tree-indent tree-last-indent"
|
||||
>
|
||||
|
||||
</span>
|
||||
@ -473,7 +473,7 @@ exports[`ProjectSearch found search results 1`] = `
|
||||
role="treeitem"
|
||||
>
|
||||
<span
|
||||
className="tree-indent"
|
||||
className="tree-indent tree-last-indent"
|
||||
>
|
||||
|
||||
</span>
|
||||
@ -613,7 +613,7 @@ exports[`ProjectSearch found search results 1`] = `
|
||||
role="treeitem"
|
||||
>
|
||||
<span
|
||||
className="tree-indent"
|
||||
className="tree-indent tree-last-indent"
|
||||
>
|
||||
|
||||
</span>
|
||||
@ -681,7 +681,7 @@ exports[`ProjectSearch found search results 1`] = `
|
||||
role="treeitem"
|
||||
>
|
||||
<span
|
||||
className="tree-indent"
|
||||
className="tree-indent tree-last-indent"
|
||||
>
|
||||
|
||||
</span>
|
||||
|
@ -4,45 +4,61 @@
|
||||
|
||||
// @flow
|
||||
|
||||
import { uniq } from "lodash";
|
||||
import type { State } from "./types";
|
||||
import type {
|
||||
EventListenerAction,
|
||||
EventListenerActiveList,
|
||||
EventListenerCategoryList,
|
||||
EventListenerExpandedList,
|
||||
} from "../actions/types";
|
||||
|
||||
import { asyncStore } from "../utils/prefs";
|
||||
import type { EventListenerBreakpoints } from "../types";
|
||||
export type EventListenersState = {
|
||||
active: EventListenerActiveList,
|
||||
categories: EventListenerCategoryList,
|
||||
expanded: EventListenerExpandedList,
|
||||
};
|
||||
|
||||
type OuterState = { eventListenerBreakpoints: EventListenerBreakpoints };
|
||||
export function initialEventListenerState(): EventListenersState {
|
||||
return {
|
||||
active: [],
|
||||
categories: [],
|
||||
expanded: [],
|
||||
};
|
||||
}
|
||||
|
||||
function update(state: EventListenerBreakpoints = [], action: any) {
|
||||
function update(
|
||||
state: EventListenersState = initialEventListenerState(),
|
||||
action: EventListenerAction
|
||||
) {
|
||||
switch (action.type) {
|
||||
case "ADD_EVENT_LISTENERS":
|
||||
return updateEventTypes("add", state, action.events);
|
||||
case "UPDATE_EVENT_LISTENERS":
|
||||
return { ...state, active: action.active };
|
||||
|
||||
case "REMOVE_EVENT_LISTENERS":
|
||||
return updateEventTypes("remove", state, action.events);
|
||||
case "RECEIVE_EVENT_LISTENER_TYPES":
|
||||
return { ...state, categories: action.categories };
|
||||
|
||||
case "UPDATE_EVENT_LISTENER_EXPANDED":
|
||||
return { ...state, expanded: action.expanded };
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function updateEventTypes(
|
||||
addOrRemove: string,
|
||||
currentEvents: EventListenerBreakpoints,
|
||||
events: EventListenerBreakpoints
|
||||
): EventListenerBreakpoints {
|
||||
let newEventListeners;
|
||||
|
||||
if (addOrRemove === "add") {
|
||||
newEventListeners = uniq([...currentEvents, ...events]);
|
||||
} else {
|
||||
newEventListeners = currentEvents.filter(event => !events.includes(event));
|
||||
}
|
||||
|
||||
asyncStore.eventListenerBreakpoints = newEventListeners;
|
||||
return newEventListeners;
|
||||
export function getActiveEventListeners(state: State): EventListenerActiveList {
|
||||
return state.eventListenerBreakpoints.active;
|
||||
}
|
||||
|
||||
export function getActiveEventListeners(state: OuterState) {
|
||||
return state.eventListenerBreakpoints;
|
||||
export function getEventListenerBreakpointTypes(
|
||||
state: State
|
||||
): EventListenerCategoryList {
|
||||
return state.eventListenerBreakpoints.categories;
|
||||
}
|
||||
|
||||
export function getEventListenerExpanded(
|
||||
state: State
|
||||
): EventListenerExpandedList {
|
||||
return state.eventListenerBreakpoints.expanded;
|
||||
}
|
||||
|
||||
export default update;
|
||||
|
@ -24,11 +24,13 @@ import type { SourceActorsState } from "./source-actors";
|
||||
import type { TabList } from "./tabs";
|
||||
import type { UIState } from "./ui";
|
||||
import type { QuickOpenState } from "./quick-open";
|
||||
import type { EventListenersState } from "./event-listeners";
|
||||
|
||||
export type State = {
|
||||
ast: ASTState,
|
||||
breakpoints: BreakpointsState,
|
||||
expressions: Record<ExpressionState>,
|
||||
eventListenerBreakpoints: EventListenersState,
|
||||
debuggee: DebuggeeState,
|
||||
fileSearch: Record<FileSearchState>,
|
||||
pause: PauseState,
|
||||
|
@ -64,6 +64,7 @@ function formatException(reason, p) {
|
||||
}
|
||||
|
||||
export const parserWorker = new ParserDispatcher();
|
||||
export const evaluationsParser = new ParserDispatcher();
|
||||
|
||||
beforeAll(() => {
|
||||
startSourceMapWorker(
|
||||
@ -74,6 +75,7 @@ beforeAll(() => {
|
||||
path.join(rootPath, "src/workers/pretty-print/worker.js")
|
||||
);
|
||||
parserWorker.start(path.join(rootPath, "src/workers/parser/worker.js"));
|
||||
evaluationsParser.start(path.join(rootPath, "src/workers/parser/worker.js"));
|
||||
startSearchWorker(path.join(rootPath, "src/workers/search/worker.js"));
|
||||
process.on("unhandledRejection", formatException);
|
||||
});
|
||||
@ -82,6 +84,7 @@ afterAll(() => {
|
||||
stopSourceMapWorker();
|
||||
stopPrettyPrintWorker();
|
||||
parserWorker.stop();
|
||||
evaluationsParser.stop();
|
||||
stopSearchWorker();
|
||||
process.removeListener("unhandledRejection", formatException);
|
||||
});
|
||||
@ -90,6 +93,7 @@ afterEach(() => {});
|
||||
|
||||
beforeEach(async () => {
|
||||
parserWorker.clear();
|
||||
evaluationsParser.clear();
|
||||
clearHistory();
|
||||
clearDocuments();
|
||||
prefs.projectDirectoryRoot = "";
|
||||
|
@ -12,7 +12,7 @@ import { asyncStoreHelper } from "./asyncStoreHelper";
|
||||
// Schema version to bump when the async store format has changed incompatibly
|
||||
// and old stores should be cleared. This needs to match the prefs schema
|
||||
// version in devtools/client/preferences/debugger.js.
|
||||
const prefsSchemaVersion = "1.0.9";
|
||||
const prefsSchemaVersion = "1.0.10";
|
||||
const pref = Services.pref;
|
||||
|
||||
if (isDevelopment()) {
|
||||
@ -134,7 +134,7 @@ export const asyncStore = asyncStoreHelper("debugger", {
|
||||
pendingBreakpoints: ["pending-breakpoints", {}],
|
||||
tabs: ["tabs", []],
|
||||
xhrBreakpoints: ["xhr-breakpoints", []],
|
||||
eventListenerBreakpoints: ["event-listener-breakpoints", []],
|
||||
eventListenerBreakpoints: ["event-listener-breakpoints", undefined],
|
||||
});
|
||||
|
||||
export function verifyPrefSchema() {
|
||||
@ -143,6 +143,7 @@ export function verifyPrefSchema() {
|
||||
asyncStore.pendingBreakpoints = {};
|
||||
asyncStore.tabs = [];
|
||||
asyncStore.xhrBreakpoints = [];
|
||||
asyncStore.eventListenerBreakpoints = undefined;
|
||||
prefs.debuggerPrefsSchemaVersion = prefsSchemaVersion;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import reducers from "../reducers";
|
||||
import actions from "../actions";
|
||||
import * as selectors from "../selectors";
|
||||
import { getHistory } from "../test/utils/history";
|
||||
import { parserWorker } from "../test/tests-setup";
|
||||
import { parserWorker, evaluationsParser } from "../test/tests-setup";
|
||||
import configureStore from "../actions/utils/create-store";
|
||||
import sourceQueue from "../utils/source-queue";
|
||||
import type { Source, OriginalSourceData, GeneratedSourceData } from "../types";
|
||||
@ -44,6 +44,7 @@ function createStore(client: any, initialState: any = {}, sourceMapsMock: any) {
|
||||
client,
|
||||
sourceMaps: sourceMapsMock !== undefined ? sourceMapsMock : sourceMaps,
|
||||
parser: parserWorker,
|
||||
evaluationsParser,
|
||||
};
|
||||
},
|
||||
})(combineReducers(reducers), initialState);
|
||||
|
@ -39,14 +39,14 @@ exports.MarkerDOMUtils = {
|
||||
buildTitle: function(doc, marker) {
|
||||
const blueprint = MarkerBlueprintUtils.getBlueprintFor(marker);
|
||||
|
||||
const hbox = doc.createElement("hbox");
|
||||
const hbox = doc.createXULElement("hbox");
|
||||
hbox.setAttribute("align", "center");
|
||||
|
||||
const bullet = doc.createElement("hbox");
|
||||
const bullet = doc.createXULElement("hbox");
|
||||
bullet.className = `marker-details-bullet marker-color-${blueprint.colorName}`;
|
||||
|
||||
const title = MarkerBlueprintUtils.getMarkerLabel(marker);
|
||||
const label = doc.createElement("label");
|
||||
const label = doc.createXULElement("label");
|
||||
label.className = "marker-details-type";
|
||||
label.setAttribute("value", title);
|
||||
|
||||
@ -87,15 +87,15 @@ exports.MarkerDOMUtils = {
|
||||
* @return Node
|
||||
*/
|
||||
buildNameValueLabel: function(doc, field, value) {
|
||||
const hbox = doc.createElement("hbox");
|
||||
const hbox = doc.createXULElement("hbox");
|
||||
hbox.className = "marker-details-labelcontainer";
|
||||
|
||||
const nameLabel = doc.createElement("label");
|
||||
const nameLabel = doc.createXULElement("label");
|
||||
nameLabel.className = "plain marker-details-name-label";
|
||||
nameLabel.setAttribute("value", field);
|
||||
hbox.appendChild(nameLabel);
|
||||
|
||||
const valueLabel = doc.createElement("label");
|
||||
const valueLabel = doc.createXULElement("label");
|
||||
valueLabel.className = "plain marker-details-value-label";
|
||||
valueLabel.setAttribute("value", value);
|
||||
hbox.appendChild(valueLabel);
|
||||
@ -119,7 +119,7 @@ exports.MarkerDOMUtils = {
|
||||
container.className = "marker-details-stack";
|
||||
container.setAttribute("type", type);
|
||||
|
||||
const nameLabel = doc.createElement("label");
|
||||
const nameLabel = doc.createXULElement("label");
|
||||
nameLabel.className = "plain marker-details-name-label";
|
||||
nameLabel.setAttribute("value", L10N.getStr(`marker.field.${type}`));
|
||||
container.appendChild(nameLabel);
|
||||
@ -144,8 +144,8 @@ exports.MarkerDOMUtils = {
|
||||
// cause is in this frame and should be displayed.
|
||||
if (wasAsyncParent) {
|
||||
const asyncStr = L10N.getFormatStr("marker.field.asyncStack", frame.asyncCause);
|
||||
const asyncBox = doc.createElement("hbox");
|
||||
const asyncLabel = doc.createElement("label");
|
||||
const asyncBox = doc.createXULElement("hbox");
|
||||
const asyncLabel = doc.createXULElement("label");
|
||||
asyncLabel.className = "devtools-monospace";
|
||||
asyncLabel.setAttribute("value", asyncStr);
|
||||
asyncBox.appendChild(asyncLabel);
|
||||
@ -153,28 +153,28 @@ exports.MarkerDOMUtils = {
|
||||
wasAsyncParent = false;
|
||||
}
|
||||
|
||||
const hbox = doc.createElement("hbox");
|
||||
const hbox = doc.createXULElement("hbox");
|
||||
|
||||
if (displayName) {
|
||||
const functionLabel = doc.createElement("label");
|
||||
const functionLabel = doc.createXULElement("label");
|
||||
functionLabel.className = "devtools-monospace";
|
||||
functionLabel.setAttribute("value", displayName);
|
||||
hbox.appendChild(functionLabel);
|
||||
}
|
||||
|
||||
if (url) {
|
||||
const linkNode = doc.createElement("a");
|
||||
const linkNode = doc.createXULElement("a");
|
||||
linkNode.className = "waterfall-marker-location devtools-source-link";
|
||||
linkNode.href = url;
|
||||
linkNode.draggable = false;
|
||||
linkNode.setAttribute("title", url);
|
||||
|
||||
const urlLabel = doc.createElement("label");
|
||||
const urlLabel = doc.createXULElement("label");
|
||||
urlLabel.className = "filename";
|
||||
urlLabel.setAttribute("value", getSourceNames(url).short);
|
||||
linkNode.appendChild(urlLabel);
|
||||
|
||||
const lineLabel = doc.createElement("label");
|
||||
const lineLabel = doc.createXULElement("label");
|
||||
lineLabel.className = "line-number";
|
||||
lineLabel.setAttribute("value", `:${line}`);
|
||||
linkNode.appendChild(lineLabel);
|
||||
@ -191,7 +191,7 @@ exports.MarkerDOMUtils = {
|
||||
}
|
||||
|
||||
if (!displayName && !url) {
|
||||
const unknownLabel = doc.createElement("label");
|
||||
const unknownLabel = doc.createXULElement("label");
|
||||
unknownLabel.setAttribute("value", L10N.getStr("marker.value.unknownFrame"));
|
||||
hbox.appendChild(unknownLabel);
|
||||
}
|
||||
@ -221,10 +221,10 @@ exports.MarkerDOMUtils = {
|
||||
const elements = [];
|
||||
|
||||
if (options.allocations && shouldShowAllocationsTrigger(marker)) {
|
||||
const hbox = doc.createElement("hbox");
|
||||
const hbox = doc.createXULElement("hbox");
|
||||
hbox.className = "marker-details-customcontainer";
|
||||
|
||||
const label = doc.createElement("label");
|
||||
const label = doc.createXULElement("label");
|
||||
label.className = "custom-button";
|
||||
label.setAttribute("value", "Show allocation triggers");
|
||||
label.setAttribute("type", "show-allocations");
|
||||
|
@ -199,7 +199,7 @@ CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
this.level));
|
||||
}
|
||||
|
||||
const targetNode = document.createElement("hbox");
|
||||
const targetNode = document.createXULElement("hbox");
|
||||
targetNode.className = "call-tree-item";
|
||||
targetNode.setAttribute("origin", frameInfo.isContent ? "content" : "chrome");
|
||||
targetNode.setAttribute("category", frameInfo.categoryData.abbrev || "");
|
||||
@ -243,7 +243,7 @@ CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
* Invoked by `_displaySelf`.
|
||||
*/
|
||||
_createCell: function(doc, value, type) {
|
||||
const cell = doc.createElement("description");
|
||||
const cell = doc.createXULElement("description");
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", type);
|
||||
cell.setAttribute("crop", "end");
|
||||
@ -253,7 +253,7 @@ CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
},
|
||||
|
||||
_createFunctionCell: function(doc, arrowNode, frameName, frameInfo, frameLevel) {
|
||||
const cell = doc.createElement("hbox");
|
||||
const cell = doc.createXULElement("hbox");
|
||||
cell.className = "call-tree-cell";
|
||||
cell.style.marginInlineStart = (frameLevel * CALL_TREE_INDENTATION) + "px";
|
||||
cell.setAttribute("type", "function");
|
||||
@ -262,7 +262,7 @@ CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
// Render optimization hint if this frame has opt data.
|
||||
if (this.root.showOptimizationHint && frameInfo.hasOptimizations &&
|
||||
!frameInfo.isMetaCategory) {
|
||||
const icon = doc.createElement("description");
|
||||
const icon = doc.createXULElement("description");
|
||||
icon.setAttribute("tooltiptext", VIEW_OPTIMIZATIONS_TOOLTIP);
|
||||
icon.className = "opt-icon";
|
||||
cell.appendChild(icon);
|
||||
@ -271,7 +271,7 @@ CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
// Don't render a name label node if there's no function name. A different
|
||||
// location label node will be rendered instead.
|
||||
if (frameName) {
|
||||
const nameNode = doc.createElement("description");
|
||||
const nameNode = doc.createXULElement("description");
|
||||
nameNode.className = "plain call-tree-name";
|
||||
nameNode.textContent = frameName;
|
||||
cell.appendChild(nameNode);
|
||||
@ -304,7 +304,7 @@ CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
|
||||
_appendFunctionDetailsCells: function(doc, cell, frameInfo) {
|
||||
if (frameInfo.fileName) {
|
||||
const urlNode = doc.createElement("description");
|
||||
const urlNode = doc.createXULElement("description");
|
||||
urlNode.className = "plain call-tree-url";
|
||||
urlNode.textContent = frameInfo.fileName;
|
||||
urlNode.setAttribute("tooltiptext", URL_LABEL_TOOLTIP + " → " + frameInfo.url);
|
||||
@ -313,28 +313,28 @@ CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
}
|
||||
|
||||
if (frameInfo.line) {
|
||||
const lineNode = doc.createElement("description");
|
||||
const lineNode = doc.createXULElement("description");
|
||||
lineNode.className = "plain call-tree-line";
|
||||
lineNode.textContent = ":" + frameInfo.line;
|
||||
cell.appendChild(lineNode);
|
||||
}
|
||||
|
||||
if (frameInfo.column) {
|
||||
const columnNode = doc.createElement("description");
|
||||
const columnNode = doc.createXULElement("description");
|
||||
columnNode.className = "plain call-tree-column";
|
||||
columnNode.textContent = ":" + frameInfo.column;
|
||||
cell.appendChild(columnNode);
|
||||
}
|
||||
|
||||
if (frameInfo.host) {
|
||||
const hostNode = doc.createElement("description");
|
||||
const hostNode = doc.createXULElement("description");
|
||||
hostNode.className = "plain call-tree-host";
|
||||
hostNode.textContent = frameInfo.host;
|
||||
cell.appendChild(hostNode);
|
||||
}
|
||||
|
||||
if (frameInfo.categoryData.label) {
|
||||
const categoryNode = doc.createElement("description");
|
||||
const categoryNode = doc.createXULElement("description");
|
||||
categoryNode.className = "plain call-tree-category";
|
||||
categoryNode.style.color = frameInfo.categoryData.color;
|
||||
categoryNode.textContent = frameInfo.categoryData.label;
|
||||
|
@ -20,7 +20,7 @@ pref("devtools.debugger.workers", false);
|
||||
|
||||
// The default Debugger UI settings
|
||||
// This schema version needs to match that in devtools/client/debugger/src/utils/prefs.js.
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.9");
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.10");
|
||||
pref("devtools.debugger.ui.panes-workers-and-sources-width", 200);
|
||||
pref("devtools.debugger.ui.panes-instruments-width", 300);
|
||||
pref("devtools.debugger.ui.panes-visible-on-startup", false);
|
||||
@ -46,7 +46,6 @@ pref("devtools.debugger.tabsBlackBoxed", "[]");
|
||||
pref("devtools.debugger.pending-selected-location", "{}");
|
||||
pref("devtools.debugger.pending-breakpoints", "{}");
|
||||
pref("devtools.debugger.expressions", "[]");
|
||||
pref("devtools.debugger.event-listener-breakpoints", "[]");
|
||||
pref("devtools.debugger.file-search-case-sensitive", false);
|
||||
pref("devtools.debugger.file-search-whole-word", false);
|
||||
pref("devtools.debugger.file-search-regex-match", false);
|
||||
|
@ -37,7 +37,7 @@ this.EXPORTED_SYMBOLS = ["AbstractTreeItem"];
|
||||
*
|
||||
* MyCustomTreeItem.prototype = extend(AbstractTreeItem.prototype, {
|
||||
* _displaySelf: function(document, arrowNode) {
|
||||
* let node = document.createElement("hbox");
|
||||
* let node = document.createXULElement("hbox");
|
||||
* ...
|
||||
* // Append the provided arrow node wherever you want.
|
||||
* node.appendChild(arrowNode);
|
||||
@ -443,7 +443,7 @@ AbstractTreeItem.prototype = {
|
||||
|
||||
const document = this.document;
|
||||
|
||||
const arrowNode = this._arrowNode = document.createElement("hbox");
|
||||
const arrowNode = this._arrowNode = document.createXULElement("hbox");
|
||||
arrowNode.className = "arrow theme-twisty";
|
||||
arrowNode.addEventListener("mousedown", this._onArrowClick);
|
||||
|
||||
|
@ -38,6 +38,8 @@ const PREF_SIDEBAR_WIDTH = "devtools.styleeditor.mediaSidebarWidth";
|
||||
const PREF_NAV_WIDTH = "devtools.styleeditor.navSidebarWidth";
|
||||
const PREF_ORIG_SOURCES = "devtools.source-map.client-service.enabled";
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
/**
|
||||
* StyleEditorUI is controls and builds the UI of the Style Editor, including
|
||||
* maintaining a list of editors for each stylesheet on a debuggee.
|
||||
@ -897,12 +899,12 @@ StyleEditorUI.prototype = {
|
||||
}
|
||||
inSource = true;
|
||||
|
||||
const div = this._panelDoc.createElement("div");
|
||||
const div = this._panelDoc.createElementNS(HTML_NS, "div");
|
||||
div.className = "media-rule-label";
|
||||
div.addEventListener("click",
|
||||
this._jumpToLocation.bind(this, location));
|
||||
|
||||
const cond = this._panelDoc.createElement("div");
|
||||
const cond = this._panelDoc.createElementNS(HTML_NS, "div");
|
||||
cond.className = "media-rule-condition";
|
||||
if (!rule.matches) {
|
||||
cond.classList.add("media-condition-unmatched");
|
||||
@ -914,7 +916,7 @@ StyleEditorUI.prototype = {
|
||||
}
|
||||
div.appendChild(cond);
|
||||
|
||||
const link = this._panelDoc.createElement("div");
|
||||
const link = this._panelDoc.createElementNS(HTML_NS, "div");
|
||||
link.className = "media-rule-line theme-link";
|
||||
if (location.line != -1) {
|
||||
link.textContent = ":" + location.line;
|
||||
@ -950,7 +952,7 @@ StyleEditorUI.prototype = {
|
||||
);
|
||||
element.appendChild(node);
|
||||
|
||||
const link = this._panelDoc.createElement("a");
|
||||
const link = this._panelDoc.createElementNS(HTML_NS, "a");
|
||||
link.href = "#";
|
||||
link.className = "media-responsive-mode-toggle";
|
||||
link.textContent = rawText.substring(match.index, matchEnd);
|
||||
|
@ -37,14 +37,14 @@ function getTemplatesJSON() {
|
||||
const templatelistNode = document.querySelector("#templatelist");
|
||||
templatelistNode.innerHTML = "";
|
||||
for (const template of list) {
|
||||
const richlistitemNode = document.createElement("richlistitem");
|
||||
const imageNode = document.createElement("image");
|
||||
const richlistitemNode = document.createXULElement("richlistitem");
|
||||
const imageNode = document.createXULElement("image");
|
||||
imageNode.setAttribute("src", template.icon);
|
||||
const labelNode = document.createElement("label");
|
||||
const labelNode = document.createXULElement("label");
|
||||
labelNode.setAttribute("value", template.name);
|
||||
const descriptionNode = document.createElement("description");
|
||||
const descriptionNode = document.createXULElement("description");
|
||||
descriptionNode.textContent = template.description;
|
||||
const vboxNode = document.createElement("vbox");
|
||||
const vboxNode = document.createXULElement("vbox");
|
||||
vboxNode.setAttribute("flex", "1");
|
||||
richlistitemNode.appendChild(imageNode);
|
||||
vboxNode.appendChild(labelNode);
|
||||
|
@ -14,6 +14,37 @@ This will run all DAMP tests, you can filter by test name with:
|
||||
```
|
||||
This command will run all tests which contains "console" in their name.
|
||||
|
||||
### Command line options
|
||||
|
||||
#### Running tests only once
|
||||
|
||||
```bash
|
||||
./mach talos-test --activeTests damp --cycles 1 --tppagecycles 1
|
||||
```
|
||||
`--cycles` will limit the number of Firefox restart to only one, while
|
||||
`--tppagecycles` will limit the number of test re-run in each firefox start to one.
|
||||
This is often helpful when debugging one particular subtest.
|
||||
|
||||
#### Taking screenshots
|
||||
|
||||
```bash
|
||||
DEBUG_DEVTOOLS_SCREENSHOTS=1 ./mach talos-test --activeTests damp
|
||||
```
|
||||
When passing `DEBUG_DEVTOOLS_SCREENSHOTS` env variable, screenshots will be taken after each subtest
|
||||
was run. The screenshot will be opened in new tabs and their title
|
||||
includes the subtest label. Firefox won't automatically close so that you can view the screenshots.
|
||||
|
||||
#### Recording a profile
|
||||
|
||||
```bash
|
||||
./mach talos-test --activeTests damp --geckoProfile --geckoProfileEntries 100000000
|
||||
```
|
||||
This will automatically record the tests and open the profile. You may use the following command in order
|
||||
to focus on just one subtest run:
|
||||
```bash
|
||||
./mach talos-test --activeTests damp --subtests custom.webconsole --cycles 1 --tppagecycles 1 --geckoProfile --geckoProfileEntries 100000000
|
||||
```
|
||||
|
||||
## How to run it on try?
|
||||
|
||||
```bash
|
||||
@ -107,7 +138,7 @@ The [main script](http://searchfox.org/mozilla-central/source/testing/talos/talo
|
||||
## How to see the performance trends?
|
||||
|
||||
You can find the dedicated performance dashboard for DevTools at http://firefox-dev.tools/performance-dashboard. You will find links to trend charts for various tools:
|
||||
* [Inspector dashboard](firefox-dev.tools/performance-dashboard/tools/inspector.html?days=60&filterstddev=true)
|
||||
* [Inspector dashboard](http://firefox-dev.tools/performance-dashboard/tools/inspector.html?days=60&filterstddev=true)
|
||||
* [Console dashboard](http://firefox-dev.tools/performance-dashboard/tools/console.html?days=60&filterstddev=true)
|
||||
* [Netmonitor dashboard](http://firefox-dev.tools/performance-dashboard/tools/netmonitor.html?days=60&filterstddev=true)
|
||||
* [Debugger dashboard](http://firefox-dev.tools/performance-dashboard/tools/debugger.html?days=60&filterstddev=true)
|
||||
|
@ -90,6 +90,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
|
||||
"justify-content",
|
||||
"justify-items",
|
||||
"justify-self",
|
||||
"line-break",
|
||||
"list-style-image",
|
||||
"list-style-position",
|
||||
"list-style-type",
|
||||
@ -310,6 +311,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
|
||||
"-moz-outline-radius-bottomright",
|
||||
"-moz-outline-radius-topleft",
|
||||
"-moz-outline-radius-topright",
|
||||
"offset-distance",
|
||||
"padding-bottom",
|
||||
"padding-left",
|
||||
"padding-right",
|
||||
|
@ -3093,6 +3093,7 @@ exports.CSS_PROPERTIES = {
|
||||
"scale",
|
||||
"translate",
|
||||
"offset-path",
|
||||
"offset-distance",
|
||||
"scroll-behavior",
|
||||
"scroll-snap-align",
|
||||
"scroll-snap-type",
|
||||
@ -3183,6 +3184,7 @@ exports.CSS_PROPERTIES = {
|
||||
"text-emphasis-position",
|
||||
"text-emphasis-color",
|
||||
"-moz-tab-size",
|
||||
"line-break",
|
||||
"-webkit-text-fill-color",
|
||||
"-webkit-text-stroke-color",
|
||||
"-webkit-text-stroke-width",
|
||||
@ -7323,6 +7325,24 @@ exports.CSS_PROPERTIES = {
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"line-break": {
|
||||
"isInherited": true,
|
||||
"subproperties": [
|
||||
"line-break"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"anywhere",
|
||||
"auto",
|
||||
"inherit",
|
||||
"initial",
|
||||
"loose",
|
||||
"normal",
|
||||
"revert",
|
||||
"strict",
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"line-height": {
|
||||
"isInherited": true,
|
||||
"subproperties": [
|
||||
@ -8232,6 +8252,19 @@ exports.CSS_PROPERTIES = {
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"offset-distance": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
"offset-distance"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"inherit",
|
||||
"initial",
|
||||
"revert",
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"offset-path": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
@ -10598,6 +10631,10 @@ exports.PREFERENCES = [
|
||||
"translate",
|
||||
"layout.css.individual-transform.enabled"
|
||||
],
|
||||
[
|
||||
"offset-distance",
|
||||
"layout.css.motion-path.enabled"
|
||||
],
|
||||
[
|
||||
"scroll-snap-points-x",
|
||||
"layout.css.scroll-snap.enabled"
|
||||
|
@ -124,7 +124,7 @@ CssProperties.prototype = {
|
||||
isValidOnClient(name, value, doc) {
|
||||
let dummyElement = this._dummyElements.get(doc);
|
||||
if (!dummyElement) {
|
||||
dummyElement = doc.createElement("div");
|
||||
dummyElement = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
this._dummyElements.set(doc, dummyElement);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
// Tests that the markup localization works properly.
|
||||
|
||||
const { localizeMarkup, LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
add_task(async function() {
|
||||
info("Check that the strings used for this test are still valid");
|
||||
@ -19,38 +20,38 @@ add_task(async function() {
|
||||
ok(str1 && str2 && str3, "If this failed, strings should be updated in the test");
|
||||
|
||||
info("Create the test markup");
|
||||
const div = document.createElement("div");
|
||||
const div = document.createElementNS(HTML_NS, "div");
|
||||
div.setAttribute("data-localization-bundle",
|
||||
"devtools/client/locales/startup.properties");
|
||||
const div0 = document.createElement("div");
|
||||
const div0 = document.createElementNS(HTML_NS, "div");
|
||||
div0.setAttribute("id", "d0");
|
||||
div0.setAttribute("data-localization", "content=inspector.someInvalidKey");
|
||||
div.appendChild(div0);
|
||||
const div1 = document.createElement("div");
|
||||
const div1 = document.createElementNS(HTML_NS, "div");
|
||||
div1.setAttribute("id", "d1");
|
||||
div1.setAttribute("data-localization", "content=inspector.label");
|
||||
div.appendChild(div1);
|
||||
div1.append("Text will disappear");
|
||||
const div2 = document.createElement("div");
|
||||
const div2 = document.createElementNS(HTML_NS, "div");
|
||||
div2.setAttribute("id", "d2");
|
||||
div2.setAttribute("data-localization",
|
||||
"content=inspector.label;title=inspector.accesskey");
|
||||
div.appendChild(div2);
|
||||
const div3 = document.createElement("div");
|
||||
const div3 = document.createElementNS(HTML_NS, "div");
|
||||
div3.setAttribute("id", "d3");
|
||||
div3.setAttribute("data-localization",
|
||||
"content=inspector.label;title=inspector.accesskey");
|
||||
div.appendChild(div3);
|
||||
const div4 = document.createElement("div");
|
||||
const div4 = document.createElementNS(HTML_NS, "div");
|
||||
div4.setAttribute("id", "d4");
|
||||
div4.setAttribute("data-localization", "aria-label=inspector.label");
|
||||
div.appendChild(div4);
|
||||
div4.append("Some content");
|
||||
const toolboxDiv = document.createElement("div");
|
||||
const toolboxDiv = document.createElementNS(HTML_NS, "div");
|
||||
toolboxDiv.setAttribute("data-localization-bundle",
|
||||
"devtools/client/locales/toolbox.properties");
|
||||
div.appendChild(toolboxDiv);
|
||||
const div5 = document.createElement("div");
|
||||
const div5 = document.createElementNS(HTML_NS, "div");
|
||||
div5.setAttribute("id", "d5");
|
||||
div5.setAttribute("data-localization", "content=toolbox.defaultTitle");
|
||||
toolboxDiv.appendChild(div5);
|
||||
|
@ -20,7 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=453650
|
||||
nextTest();
|
||||
|
||||
function* runTests() {
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframe = document.createXULElement("iframe");
|
||||
iframe.style.width = "300px";
|
||||
iframe.style.height = "300px";
|
||||
iframe.setAttribute("src", "data:text/html,<h1 id='h'>hello</h1>");
|
||||
|
@ -38,7 +38,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=846906
|
||||
var document = webNavigation.document;
|
||||
ok(document, "Should be able to get document");
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframe = document.createXULElement("iframe");
|
||||
ok(iframe, "Should be able to create iframe");
|
||||
|
||||
iframe.onload = function () {
|
||||
|
@ -38,7 +38,7 @@ var gFrame;
|
||||
// matters when these tests fail (produces better error messages).
|
||||
var tests = [
|
||||
function testInheritFromParent(cb) {
|
||||
gFrame = document.createElement("iframe");
|
||||
gFrame = document.createXULElement("iframe");
|
||||
loadListener(gFrame, function () {
|
||||
is(window.inheritedFromParent, true, "load in type=content iframe inherited principal of same type parent");
|
||||
cb();
|
||||
@ -63,7 +63,7 @@ var tests = [
|
||||
'<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>';
|
||||
let newWin = window.openDialog(xulWinURL, "chrome_window", "chrome");
|
||||
loadListener(newWin, function () {
|
||||
let frame = newWin.document.createElement("iframe");
|
||||
let frame = newWin.document.createXULElement("iframe");
|
||||
frame.setAttribute("type", "content");
|
||||
frame.setAttribute("src", "javascript:'1';");
|
||||
loadListener(frame, function () {
|
||||
|
@ -11910,7 +11910,6 @@ void Document::SetContentTypeInternal(const nsACString& aType) {
|
||||
|
||||
mCachedEncoder = nullptr;
|
||||
mContentType = aType;
|
||||
mContentTypeForWriteCalls = aType;
|
||||
}
|
||||
|
||||
nsILoadContext* Document::GetLoadContext() const { return mDocumentContainer; }
|
||||
|
@ -4419,10 +4419,6 @@ class Document : public nsINode,
|
||||
nsCString mContentType;
|
||||
|
||||
protected:
|
||||
// For document.write() we may need a different content type than
|
||||
// mContentType.
|
||||
nsCString mContentTypeForWriteCalls;
|
||||
|
||||
// The document's security info
|
||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
|
||||
|
@ -304,6 +304,46 @@ bool TabGroup::IsBackground() const {
|
||||
return mForegroundCount == 0;
|
||||
}
|
||||
|
||||
nsresult TabGroup::QueuePostMessageEvent(
|
||||
already_AddRefed<nsIRunnable>&& aRunnable) {
|
||||
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
|
||||
if (!mPostMessageEventQueue) {
|
||||
nsCOMPtr<nsISerialEventTarget> target = GetMainThreadSerialEventTarget();
|
||||
mPostMessageEventQueue = ThrottledEventQueue::Create(
|
||||
target, "PostMessage Queue",
|
||||
nsIRunnablePriority::PRIORITY_DEFERRED_TIMERS);
|
||||
nsresult rv = mPostMessageEventQueue->SetIsPaused(false);
|
||||
MOZ_ALWAYS_SUCCEEDS(rv);
|
||||
}
|
||||
|
||||
// Ensure the queue is enabled
|
||||
if (mPostMessageEventQueue->IsPaused()) {
|
||||
nsresult rv = mPostMessageEventQueue->SetIsPaused(false);
|
||||
MOZ_ALWAYS_SUCCEEDS(rv);
|
||||
}
|
||||
|
||||
if (mPostMessageEventQueue) {
|
||||
mPostMessageEventQueue->Dispatch(std::move(aRunnable),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void TabGroup::FlushPostMessageEvents() {
|
||||
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
|
||||
if (mPostMessageEventQueue) {
|
||||
nsresult rv = mPostMessageEventQueue->SetIsPaused(true);
|
||||
MOZ_ALWAYS_SUCCEEDS(rv);
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
while ((event = mPostMessageEventQueue->GetEvent())) {
|
||||
Dispatch(TaskCategory::Other, event.forget());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TabGroup::Count(bool aActiveOnly) const {
|
||||
if (!aActiveOnly) {
|
||||
return mDocGroups.Count();
|
||||
|
@ -23,6 +23,7 @@ class nsPIDOMWindowOuter;
|
||||
|
||||
namespace mozilla {
|
||||
class AbstractThread;
|
||||
class ThrottledEventQueue;
|
||||
namespace dom {
|
||||
class Document;
|
||||
class BrowserChild;
|
||||
@ -143,6 +144,10 @@ class TabGroup final : public SchedulerGroup,
|
||||
// can be throttled.
|
||||
static bool HasOnlyThrottableTabs();
|
||||
|
||||
nsresult QueuePostMessageEvent(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
|
||||
void FlushPostMessageEvents();
|
||||
|
||||
private:
|
||||
virtual AbstractThread* AbstractMainThreadForImpl(
|
||||
TaskCategory aCategory) override;
|
||||
@ -166,6 +171,10 @@ class TabGroup final : public SchedulerGroup,
|
||||
uint32_t mForegroundCount;
|
||||
|
||||
static LinkedList<TabGroup>* sTabGroups;
|
||||
|
||||
// A queue to store postMessage events during page load, the queue will be
|
||||
// flushed once the page is loaded
|
||||
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -2482,6 +2482,18 @@ void nsPIDOMWindowInner::SetAudioCapture(bool aCapture) {
|
||||
}
|
||||
|
||||
void nsPIDOMWindowInner::SetActiveLoadingState(bool aIsLoading) {
|
||||
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
|
||||
if (!aIsLoading) {
|
||||
Document* doc = GetExtantDoc();
|
||||
if (doc) {
|
||||
if (doc->IsTopLevelContentDocument()) {
|
||||
mozilla::dom::TabGroup* tabGroup = doc->GetDocGroup()->GetTabGroup();
|
||||
tabGroup->FlushPostMessageEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!nsGlobalWindowInner::Cast(this)->IsChromeWindow()) {
|
||||
mTimeoutManager->SetLoading(aIsLoading);
|
||||
}
|
||||
|
@ -6057,6 +6057,19 @@ void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
|
||||
return;
|
||||
}
|
||||
|
||||
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
|
||||
if (mDoc) {
|
||||
Document* doc = mDoc->GetTopLevelContentDocument();
|
||||
if (doc && doc->GetReadyStateEnum() < Document::READYSTATE_COMPLETE) {
|
||||
// As long as the top level is loading, we can dispatch events to the
|
||||
// queue because the queue will be flushed eventually
|
||||
mozilla::dom::TabGroup* tabGroup = TabGroup();
|
||||
aError = tabGroup->QueuePostMessageEvent(event.forget());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aError = Dispatch(TaskCategory::Other, event.forget());
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/Modules.h" // JS::CompileModule, JS::GetModuleScript, JS::Module{Instantiate,Evaluate}
|
||||
#include "js/OffThreadScriptCompilation.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "nsIScriptContext.h"
|
||||
|
@ -11,16 +11,20 @@
|
||||
#include "nsHyphenator.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/intl/LineBreaker.h"
|
||||
#include "mozilla/intl/MozLocale.h"
|
||||
|
||||
using mozilla::intl::LineBreaker;
|
||||
using mozilla::intl::Locale;
|
||||
|
||||
nsLineBreaker::nsLineBreaker()
|
||||
: mCurrentWordLanguage(nullptr),
|
||||
mCurrentWordContainsMixedLang(false),
|
||||
mCurrentWordContainsComplexChar(false),
|
||||
mScriptIsChineseOrJapanese(false),
|
||||
mAfterBreakableSpace(false),
|
||||
mBreakHere(false),
|
||||
mWordBreak(LineBreaker::kWordBreak_Normal) {}
|
||||
mWordBreak(LineBreaker::WordBreak::Normal),
|
||||
mStrictness(LineBreaker::Strictness::Auto) {}
|
||||
|
||||
nsLineBreaker::~nsLineBreaker() {
|
||||
NS_ASSERTION(mCurrentWord.Length() == 0,
|
||||
@ -57,21 +61,28 @@ static void SetupCapitalization(const char16_t* aWord, uint32_t aLength,
|
||||
nsresult nsLineBreaker::FlushCurrentWord() {
|
||||
uint32_t length = mCurrentWord.Length();
|
||||
AutoTArray<uint8_t, 4000> breakState;
|
||||
if (!breakState.AppendElements(length)) return NS_ERROR_OUT_OF_MEMORY;
|
||||
if (!breakState.AppendElements(length)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsTArray<bool> capitalizationState;
|
||||
|
||||
if (!mCurrentWordContainsComplexChar) {
|
||||
if (mStrictness == LineBreaker::Strictness::Anywhere) {
|
||||
memset(breakState.Elements(),
|
||||
gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL,
|
||||
length * sizeof(uint8_t));
|
||||
} else if (!mCurrentWordContainsComplexChar) {
|
||||
// For break-strict set everything internal to "break", otherwise
|
||||
// to "no break"!
|
||||
memset(breakState.Elements(),
|
||||
mWordBreak == LineBreaker::kWordBreak_BreakAll
|
||||
mWordBreak == LineBreaker::WordBreak::BreakAll
|
||||
? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
|
||||
: gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE,
|
||||
length * sizeof(uint8_t));
|
||||
} else {
|
||||
nsContentUtils::LineBreaker()->GetJISx4051Breaks(
|
||||
mCurrentWord.Elements(), length, mWordBreak, breakState.Elements());
|
||||
mCurrentWord.Elements(), length, mWordBreak, mStrictness,
|
||||
mScriptIsChineseOrJapanese, breakState.Elements());
|
||||
}
|
||||
|
||||
bool autoHyphenate = mCurrentWordLanguage && !mCurrentWordContainsMixedLang;
|
||||
@ -225,7 +236,8 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
|
||||
if (aSink && !noBreaksNeeded) {
|
||||
breakState[offset] =
|
||||
mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
|
||||
(mWordBreak == LineBreaker::kWordBreak_BreakAll)
|
||||
mWordBreak == LineBreaker::WordBreak::BreakAll ||
|
||||
mStrictness == LineBreaker::Strictness::Anywhere
|
||||
? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
|
||||
: gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
|
||||
}
|
||||
@ -240,8 +252,8 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
|
||||
// set it to false
|
||||
uint8_t currentStart = breakState[wordStart];
|
||||
nsContentUtils::LineBreaker()->GetJISx4051Breaks(
|
||||
aText + wordStart, offset - wordStart, mWordBreak,
|
||||
breakState.Elements() + wordStart);
|
||||
aText + wordStart, offset - wordStart, mWordBreak, mStrictness,
|
||||
mScriptIsChineseOrJapanese, breakState.Elements() + wordStart);
|
||||
breakState[wordStart] = currentStart;
|
||||
}
|
||||
if (hyphenator) {
|
||||
@ -383,7 +395,8 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
|
||||
// will be set by nsILineBreaker, we don't consider CJK at this point.
|
||||
breakState[offset] =
|
||||
mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
|
||||
(mWordBreak == LineBreaker::kWordBreak_BreakAll)
|
||||
mWordBreak == LineBreaker::WordBreak::BreakAll ||
|
||||
mStrictness == LineBreaker::Strictness::Anywhere
|
||||
? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
|
||||
: gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
|
||||
}
|
||||
@ -397,8 +410,8 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
|
||||
// set it to false
|
||||
uint8_t currentStart = breakState[wordStart];
|
||||
nsContentUtils::LineBreaker()->GetJISx4051Breaks(
|
||||
aText + wordStart, offset - wordStart, mWordBreak,
|
||||
breakState.Elements() + wordStart);
|
||||
aText + wordStart, offset - wordStart, mWordBreak, mStrictness,
|
||||
mScriptIsChineseOrJapanese, breakState.Elements() + wordStart);
|
||||
breakState[wordStart] = currentStart;
|
||||
}
|
||||
wordHasComplexChar = false;
|
||||
@ -439,7 +452,18 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
|
||||
void nsLineBreaker::UpdateCurrentWordLanguage(nsAtom* aHyphenationLanguage) {
|
||||
if (mCurrentWordLanguage && mCurrentWordLanguage != aHyphenationLanguage) {
|
||||
mCurrentWordContainsMixedLang = true;
|
||||
mScriptIsChineseOrJapanese = false;
|
||||
} else {
|
||||
if (aHyphenationLanguage && !mCurrentWordLanguage) {
|
||||
Locale loc = Locale(nsAtomCString(aHyphenationLanguage));
|
||||
if (loc.GetScript().IsEmpty()) {
|
||||
loc.AddLikelySubtags();
|
||||
}
|
||||
const nsCString& script = loc.GetScript();
|
||||
mScriptIsChineseOrJapanese =
|
||||
script.EqualsLiteral("Hans") || script.EqualsLiteral("Hant") ||
|
||||
script.EqualsLiteral("Jpan") || script.EqualsLiteral("Hrkt");
|
||||
}
|
||||
mCurrentWordLanguage = aHyphenationLanguage;
|
||||
}
|
||||
}
|
||||
|
@ -175,9 +175,9 @@ class nsLineBreaker {
|
||||
|
||||
/*
|
||||
* Set word-break mode for linebreaker. This is set by word-break property.
|
||||
* @param aMode is LineBreaker::kWordBreak_* value.
|
||||
* @param aMode is LineBreaker::WordBreak::* value.
|
||||
*/
|
||||
void SetWordBreak(uint8_t aMode) {
|
||||
void SetWordBreak(mozilla::intl::LineBreaker::WordBreak aMode) {
|
||||
// If current word is non-empty and mode is changing, flush the breaker.
|
||||
if (aMode != mWordBreak && !mCurrentWord.IsEmpty()) {
|
||||
nsresult rv = FlushCurrentWord();
|
||||
@ -187,13 +187,32 @@ class nsLineBreaker {
|
||||
// If previous mode was break-all, we should allow a break here.
|
||||
// XXX (jfkthame) css-text spec seems unclear on this, raised question in
|
||||
// https://github.com/w3c/csswg-drafts/issues/3897
|
||||
if (mWordBreak == mozilla::intl::LineBreaker::kWordBreak_BreakAll) {
|
||||
if (mWordBreak == mozilla::intl::LineBreaker::WordBreak::BreakAll) {
|
||||
mBreakHere = true;
|
||||
}
|
||||
}
|
||||
mWordBreak = aMode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set line-break rule strictness mode for linebreaker. This is set by the
|
||||
* line-break property.
|
||||
* @param aMode is LineBreaker::Strictness::* value.
|
||||
*/
|
||||
void SetStrictness(mozilla::intl::LineBreaker::Strictness aMode) {
|
||||
if (aMode != mStrictness && !mCurrentWord.IsEmpty()) {
|
||||
nsresult rv = FlushCurrentWord();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("FlushCurrentWord failed, line-breaks may be wrong");
|
||||
}
|
||||
// If previous mode was anywhere, we should allow a break here.
|
||||
if (mStrictness == mozilla::intl::LineBreaker::Strictness::Anywhere) {
|
||||
mBreakHere = true;
|
||||
}
|
||||
}
|
||||
mStrictness = aMode;
|
||||
}
|
||||
|
||||
private:
|
||||
// This is a list of text sources that make up the "current word" (i.e.,
|
||||
// run of text which does not contain any whitespace). All the mLengths
|
||||
@ -232,6 +251,7 @@ class nsLineBreaker {
|
||||
nsAtom* mCurrentWordLanguage;
|
||||
bool mCurrentWordContainsMixedLang;
|
||||
bool mCurrentWordContainsComplexChar;
|
||||
bool mScriptIsChineseOrJapanese;
|
||||
|
||||
// True if the previous character was breakable whitespace
|
||||
bool mAfterBreakableSpace;
|
||||
@ -239,7 +259,9 @@ class nsLineBreaker {
|
||||
// a run of breakable whitespace ends here
|
||||
bool mBreakHere;
|
||||
// line break mode by "word-break" style
|
||||
uint8_t mWordBreak;
|
||||
mozilla::intl::LineBreaker::WordBreak mWordBreak;
|
||||
// strictness of break rules, from line-break property
|
||||
mozilla::intl::LineBreaker::Strictness mStrictness;
|
||||
};
|
||||
|
||||
#endif /*NSLINEBREAKER_H_*/
|
||||
|
@ -173,7 +173,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682
|
||||
messageManager.removeDelayedFrameScript(toBeRemovedScript);
|
||||
|
||||
var oldValue = globalListenerCallCount;
|
||||
var b = document.createElement("browser");
|
||||
var b = document.createXULElement("browser");
|
||||
b.setAttribute("type", "content");
|
||||
document.documentElement.appendChild(b);
|
||||
is(globalListenerCallCount, oldValue + 1,
|
||||
|
@ -45,7 +45,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=990812
|
||||
}
|
||||
});
|
||||
|
||||
var browser = document.createElement("browser");
|
||||
var browser = document.createXULElement("browser");
|
||||
browser.setAttribute("messagemanagergroup", "test");
|
||||
browser.setAttribute("src", "about:mozilla");
|
||||
browser.setAttribute("type", "content");
|
||||
|
@ -39,7 +39,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=990812
|
||||
}
|
||||
});
|
||||
|
||||
var browser = document.createElement("browser");
|
||||
var browser = document.createXULElement("browser");
|
||||
browser.setAttribute("messagemanagergroup", "test");
|
||||
browser.setAttribute("src", "about:mozilla");
|
||||
browser.setAttribute("type", "content");
|
||||
|
@ -45,7 +45,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=120684
|
||||
is(list[1], undefined);
|
||||
|
||||
// Removing element which isn't in the list shouldn't do anything.
|
||||
list.remove(document.createElement("foo"));
|
||||
list.remove(document.createXULElement("foo"));
|
||||
is(list.length, 1, "Length should be 1.");
|
||||
is(list[0], document.documentElement);
|
||||
|
||||
@ -53,9 +53,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=120684
|
||||
is(list.length, 0, "Length should be 0.");
|
||||
is(list[0], undefined);
|
||||
|
||||
var e1 = document.createElement("foo");
|
||||
var e2 = document.createElement("foo");
|
||||
var e3 = document.createElement("foo");
|
||||
var e1 = document.createXULElement("foo");
|
||||
var e2 = document.createXULElement("foo");
|
||||
var e3 = document.createXULElement("foo");
|
||||
|
||||
list.append(e1);
|
||||
list.append(e2);
|
||||
|
@ -40,7 +40,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=683852
|
||||
is(box.contains(anon), false, "Element should not contain anonymous element in it!");
|
||||
is(anon.contains(anon), true, "Anonymous element should contain itself.")
|
||||
is(document.documentElement.contains(box), true, "Element should contain element in it!");
|
||||
is(document.contains(document.createElement("foo")), false, "Document shouldn't contain element which is't in the document");
|
||||
is(document.contains(document.createXULElement("foo")), false, "Document shouldn't contain element which is't in the document");
|
||||
is(document.contains(document.createTextNode("foo")), false, "Document shouldn't contain text node which is't in the document");
|
||||
|
||||
var link = document.getElementById("link");
|
||||
|
@ -141,7 +141,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
let frame = document.createElement("iframe");
|
||||
let frame = document.createXULElement("iframe");
|
||||
frame.onload = function() {
|
||||
obs.addObserver(observer, TOPIC);
|
||||
// Create dummy DOMRequestHelper specific to checkWindowDestruction()
|
||||
|
2
dom/cache/Connection.cpp
vendored
2
dom/cache/Connection.cpp
vendored
@ -82,7 +82,7 @@ Connection::CreateAsyncStatement(const nsACString&,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Connection::ExecuteAsync(mozIStorageBaseStatement**, uint32_t,
|
||||
Connection::ExecuteAsync(const nsTArray<RefPtr<mozIStorageBaseStatement>>&,
|
||||
mozIStorageStatementCallback*,
|
||||
mozIStoragePendingStatement**) {
|
||||
// async methods are not supported
|
||||
|
@ -43,7 +43,7 @@ var test = function (isContent) {
|
||||
// The following code creates a new div for each event in eventDefs,
|
||||
// attaches a listener to listen for the event, and then generates
|
||||
// a fake event at the center of the div.
|
||||
let div = document.createElement("div");
|
||||
let div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
div.style.width = "10px";
|
||||
div.style.height = "10px";
|
||||
div.style.backgroundColor = "red";
|
||||
|
7
dom/html/crashtests/1550524.html
Normal file
7
dom/html/crashtests/1550524.html
Normal file
@ -0,0 +1,7 @@
|
||||
<iframe></iframe>
|
||||
<script>
|
||||
var doc = frames[0].document;
|
||||
doc.open();
|
||||
doc.open();
|
||||
doc.close();
|
||||
</script>
|
13
dom/html/crashtests/1550881-1.html
Normal file
13
dom/html/crashtests/1550881-1.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<iframe srcdoc="<iframe></iframe>"></iframe>
|
||||
<script>
|
||||
onload = function() {
|
||||
parent = frames[0];
|
||||
child = parent[0];
|
||||
child.onunload = function() {
|
||||
parent.document.open();
|
||||
}
|
||||
parent.document.open();
|
||||
parent.document.write("Hello");
|
||||
}
|
||||
</script>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user