Skip to content

Commit 599d8d7

Browse files
committed
[Backtracing][Linux] Fix crash handler for musl.
Musl's `clone()` wrapper returns `EINVAL` if you try to use `CLONE_THREAD`, which seems a bit wrong (certainly it is in this particular application, since we *really* don't care whether the thread is a valid C library thread at this point). Also properly support ELF images that are built with a base address other than zero (this typically isn't an issue for dynamically linked programs, as they will be relocated at runtime anyway, but for statically linked binaries it's very common to set the base address to a non-zero value). rdar://154282813
1 parent e69c5d6 commit 599d8d7

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

stdlib/public/Backtracing/Elf.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,8 @@ struct ElfSymbolTable<SomeElfTraits: ElfTraits>: ElfSymbolTableProtocol {
875875
continue
876876
}
877877

878-
// Ignore anything undefined
879-
if symbol.st_shndx == SHN_UNDEF {
878+
// Ignore anything undefined or absolute
879+
if symbol.st_shndx == SHN_UNDEF || symbol.st_shndx == SHN_ABS {
880880
continue
881881
}
882882

@@ -1029,11 +1029,21 @@ class ElfImage<SomeImageSource: ImageSource,
10291029

10301030
var phdrs: [Traits.Phdr] = []
10311031
var phAddr = Source.Address(header.e_phoff)
1032+
var minAddr: Traits.Address? = nil
10321033
for _ in 0..<header.e_phnum {
10331034
let phdr = maybeSwap(try source.fetch(from: phAddr, as: Traits.Phdr.self))
10341035
phdrs.append(phdr)
10351036
phAddr += Source.Address(header.e_phentsize)
1037+
1038+
if phdr.p_type == .PT_LOAD {
1039+
if let oldMinAddr = minAddr {
1040+
minAddr = min(oldMinAddr, phdr.p_vaddr)
1041+
} else {
1042+
minAddr = phdr.p_vaddr
1043+
}
1044+
}
10361045
}
1046+
imageBase = Source.Address(exactly: minAddr ?? 0)!
10371047
programHeaders = phdrs
10381048

10391049
if source.isMappedImage {

stdlib/public/Backtracing/SymbolicatedBacktrace.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,27 +496,33 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
496496
where: { address >= $0.baseAddress
497497
&& address < $0.endOfText }
498498
) {
499-
let relativeAddress = address - FileImageSource.Address(theImages[imageNdx].baseAddress)
500499
var symbol: Symbol = Symbol(imageIndex: imageNdx,
501500
imageName: theImages[imageNdx].name,
502501
rawName: "<unknown>",
503502
offset: 0,
504503
sourceLocation: nil)
505504
var elf32Image = elf32Cache[imageNdx]
506505
var elf64Image = elf64Cache[imageNdx]
506+
var imageBase = FileImageSource.Address(0)
507507

508508
if elf32Image == nil && elf64Image == nil {
509509
if let source = try? FileImageSource(path: theImages[imageNdx].path) {
510510
if let elfImage = try? Elf32Image(source: source) {
511511
elf32Image = elfImage
512512
elf32Cache[imageNdx] = elfImage
513+
imageBase = elfImage.imageBase
513514
} else if let elfImage = try? Elf64Image(source: source) {
514515
elf64Image = elfImage
515516
elf64Cache[imageNdx] = elfImage
517+
imageBase = elfImage.imageBase
516518
}
517519
}
518520
}
519521

522+
let relativeAddress = FileImageSource.Address(
523+
address - theImages[imageNdx].baseAddress
524+
) + imageBase
525+
520526
if let theSymbol = elf32Image?.lookupSymbol(address: relativeAddress) {
521527
var location: SourceLocation?
522528

stdlib/public/runtime/CrashHandlerLinux.cpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@
4949
#include <string.h>
5050
#include <unistd.h>
5151

52+
#define DEBUG_MEMSERVER 0
53+
54+
#if DEBUG_MEMSERVER
55+
#include <stdio.h>
56+
#define memserver_error(x) perror(x)
57+
#else
58+
#define memserver_error(x)
59+
#endif
60+
5261
#include "swift/Runtime/Backtrace.h"
5362

5463
#include <cstring>
@@ -86,8 +95,8 @@ ssize_t safe_read(int fd, void *buf, size_t len) {
8695
ssize_t ret;
8796
do {
8897
ret = read(fd, buf, len);
89-
} while (ret < 0 && errno == EINTR);
90-
if (ret < 0)
98+
} while (ret <= 0 && errno == EINTR);
99+
if (ret <= 0)
91100
return ret;
92101
total += ret;
93102
ptr += ret;
@@ -106,8 +115,8 @@ ssize_t safe_write(int fd, const void *buf, size_t len) {
106115
ssize_t ret;
107116
do {
108117
ret = write(fd, buf, len);
109-
} while (ret < 0 && errno == EINTR);
110-
if (ret < 0)
118+
} while (ret <= 0 && errno == EINTR);
119+
if (ret <= 0)
111120
return ret;
112121
total += ret;
113122
ptr += ret;
@@ -657,20 +666,28 @@ memserver_start()
657666
int fds[2];
658667

659668
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
660-
if (ret < 0)
669+
if (ret < 0) {
670+
memserver_error("memserver_start: socketpair failed");
661671
return ret;
672+
}
662673

663674
memserver_fd = fds[0];
664675
ret = clone(memserver_entry, memserver_stack + sizeof(memserver_stack),
665676
#if MEMSERVER_USE_PROCESS
666677
0,
667678
#else
668-
CLONE_THREAD | CLONE_VM | CLONE_FILES
669-
| CLONE_FS | CLONE_IO | CLONE_SIGHAND,
679+
#ifndef __musl__
680+
// Can't use CLONE_THREAD on musl because the clone() function
681+
// there returns EINVAL if we do.
682+
CLONE_THREAD | CLONE_SIGHAND |
683+
#endif
684+
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_IO,
670685
#endif
671686
NULL);
672-
if (ret < 0)
687+
if (ret < 0) {
688+
memserver_error("memserver_start: clone failed");
673689
return ret;
690+
}
674691

675692
#if MEMSERVER_USE_PROCESS
676693
memserver_pid = ret;
@@ -718,7 +735,7 @@ memserver_entry(void *dummy __attribute__((unused))) {
718735
int fd = memserver_fd;
719736
int result = 1;
720737

721-
#if MEMSERVER_USE_PROCESS
738+
#if MEMSERVER_USE_PROCESS || defined(__musl__)
722739
prctl(PR_SET_NAME, "[backtrace]");
723740
#endif
724741

@@ -743,8 +760,10 @@ memserver_entry(void *dummy __attribute__((unused))) {
743760
ssize_t ret;
744761

745762
ret = safe_read(fd, &req, sizeof(req));
746-
if (ret != sizeof(req))
763+
if (ret != sizeof(req)) {
764+
memserver_error("memserver: terminating because safe_read() returned wrong size");
747765
break;
766+
}
748767

749768
uint64_t addr = req.addr;
750769
uint64_t bytes = req.len;
@@ -761,15 +780,19 @@ memserver_entry(void *dummy __attribute__((unused))) {
761780
resp.len = ret;
762781

763782
ret = safe_write(fd, &resp, sizeof(resp));
764-
if (ret != sizeof(resp))
783+
if (ret != sizeof(resp)) {
784+
memserver_error("memserver: terminating because safe_write() failed");
765785
goto fail;
786+
}
766787

767788
if (resp.len < 0)
768789
break;
769790

770791
ret = safe_write(fd, memserver_buffer, resp.len);
771-
if (ret != resp.len)
792+
if (ret != resp.len) {
793+
memserver_error("memserver: terminating because safe_write() failed (2)");
772794
goto fail;
795+
}
773796

774797
addr += resp.len;
775798
bytes -= resp.len;

0 commit comments

Comments
 (0)