diff --git a/kdump-lib.sh b/kdump-lib.sh
index 1c68e6a..88fea64 100755
--- a/kdump-lib.sh
+++ b/kdump-lib.sh
@@ -977,3 +977,74 @@ get_all_kdump_crypt_dev()
         [[ -n "$_crypt" ]] && echo $_crypt
     done
 }
+
+check_vmlinux()
+{
+    # Use readelf to check if it's a valid ELF
+    readelf -h $1 &>/dev/null || return 1
+}
+
+get_vmlinux_size()
+{
+    local size=0
+
+    while read _type _offset _virtaddr _physaddr _fsize _msize _flg _aln; do
+        size=$(( $size + $_msize ))
+    done <<< $(readelf -l -W $1 | grep "^  LOAD" 2>/dev/stderr)
+
+    echo $size
+}
+
+try_decompress()
+{
+    # The obscure use of the "tr" filter is to work around older versions of
+    # "grep" that report the byte offset of the line instead of the pattern.
+
+    # Try to find the header ($1) and decompress from here
+    for pos in `tr "$1\n$2" "\n$2=" < "$4" | grep -abo "^$2"`
+    do
+        if ! type -P $3 > /dev/null; then
+            ddebug "Signiature detected but '$3' is missing, skip this decompressor"
+            break
+        fi
+
+        pos=${pos%%:*}
+        tail -c+$pos "$img" | $3 > $5 2> /dev/null
+        if check_vmlinux $5; then
+            ddebug "Kernel is extracted with '$3'"
+            return 0
+        fi
+    done
+
+    return 1
+}
+
+# Borrowed from linux/scripts/extract-vmlinux
+get_kernel_size()
+{
+    # Prepare temp files:
+    local img=$1 tmp=$(mktemp /tmp/vmlinux-XXX)
+    trap "rm -f $tmp" 0
+
+    # Try to check if it's a vmlinux already
+    check_vmlinux $img && get_vmlinux_size $img && return 0
+
+    # That didn't work, so retry after decompression.
+    try_decompress '\037\213\010' xy    gunzip    $img $tmp || \
+    try_decompress '\3757zXZ\000' abcde unxz      $img $tmp || \
+    try_decompress 'BZh'          xy    bunzip2   $img $tmp || \
+    try_decompress '\135\0\0\0'   xxx   unlzma    $img $tmp || \
+    try_decompress '\211\114\132' xy    'lzop -d' $img $tmp || \
+    try_decompress '\002!L\030'   xxx   'lz4 -d'  $img $tmp || \
+    try_decompress '(\265/\375'   xxx   unzstd    $img $tmp
+
+    # Finally check for uncompressed images or objects:
+    [[ $? -eq 0 ]] && get_vmlinux_size $tmp && return 0
+
+    # Fallback to use iomem
+    local _size=0
+    for _seg in $(cat /proc/iomem  | grep -E "Kernel (code|rodata|data|bss)" | cut -d ":" -f 1); do
+	    _size=$(( $_size + 0x${_seg#*-} - 0x${_seg%-*} ))
+    done
+    echo $_size
+}
diff --git a/kdumpctl b/kdumpctl
index 24f5cf7..37d8c51 100755
--- a/kdumpctl
+++ b/kdumpctl
@@ -1214,6 +1214,97 @@ rebuild() {
 	return $?
 }
 
+do_estimate() {
+	local kdump_mods
+	local -A large_mods
+	local baseline
+	local kernel_size mod_size initrd_size baseline_size runtime_size reserved_size estimated_size recommanded_size
+	local size_mb=$(( 1024 * 1024 ))
+
+	setup_initrd
+	if [ ! -f "$TARGET_INITRD" ]; then
+		derror "kdumpctl estimate: kdump initramfs is not built yet."
+		exit 1
+	fi
+
+	kdump_mods="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/hostonly-kernel-modules.txt | tr '\n' ' ')"
+	baseline=$(kdump_get_arch_recommend_size)
+	if [[ "${baseline: -1}" == "M" ]]; then
+		baseline=${baseline%M}
+	elif [[ "${baseline: -1}" == "G" ]]; then
+		baseline=$(( ${baseline%G} * 1024 ))
+	elif [[ "${baseline: -1}" == "T" ]]; then
+		baseline=$(( ${baseline%Y} * 1048576 ))
+	fi
+
+	# The default value when using crashkernel=auto
+	baseline_size=$((baseline * size_mb))
+	# Current reserved crashkernel size
+	reserved_size=$(cat /sys/kernel/kexec_crash_size)
+	# A pre-estimated value for userspace usage and kernel
+	# runtime allocation, 64M should good for most cases
+	runtime_size=$((64 * size_mb))
+	# Kernel image size
+	kernel_size=$(get_kernel_size "$KDUMP_KERNEL")
+	# Kdump initramfs size
+	initrd_size=$(du -b "$TARGET_INITRD" | awk '{print $1}')
+	# Kernel modules static size after loaded
+	mod_size=0
+	while read -r _name _size _; do
+		if [[ ! " $kdump_mods " == *" $_name "* ]]; then
+			continue
+		fi
+		mod_size=$((mod_size + _size))
+
+		# Mark module with static size larger than 2M as large module
+		if [[ $((_size / size_mb)) -ge 1 ]]; then
+			large_mods[$_name]=$_size
+		fi
+	done <<< "$(< /proc/modules)"
+
+	# Extra memory usage required for LUKS2 decryption
+	crypt_size=0
+	for _dev in $(get_all_kdump_crypt_dev); do
+		_crypt_info=$(cryptsetup luksDump "/dev/block/$_dev")
+		[[ $(echo "$_crypt_info" | sed -n "s/^Version:\s*\(.*\)/\1/p" ) == "2" ]] || continue
+		for _mem in $(echo "$_crypt_info" | sed -n "s/\sMemory:\s*\(.*\)/\1/p" | sort -n ); do
+			crypt_size=$((crypt_size + _mem * 1024))
+			break
+		done
+	done
+	[[ $crypt_size -ne 0 ]] && echo -e "Encrypted kdump target requires extra memory, assuming using the keyslot with minimun memory requirement\n"
+
+	estimated_size=$((kernel_size + mod_size + initrd_size + runtime_size + crypt_size))
+	if [[ $baseline_size -gt $estimated_size ]]; then
+		recommanded_size=$baseline_size
+	else
+		recommanded_size=$estimated_size
+	fi
+
+	echo "Reserved crashkernel:    $((reserved_size / size_mb))M"
+	echo "Recommanded crashkernel: $((recommanded_size / size_mb))M"
+	echo
+	echo "Kernel image size:   $((kernel_size / size_mb))M"
+	echo "Kernel modules size: $((mod_size / size_mb))M"
+	echo "Initramfs size:      $((initrd_size / size_mb))M"
+	echo "Runtime reservation: $((runtime_size / size_mb))M"
+	[[ $crypt_size -ne 0 ]] && \
+	echo "LUKS required size:  $((crypt_size / size_mb))M"
+	echo -n "Large modules:"
+	if [[ "${#large_mods[@]}" -eq 0 ]]; then
+		echo " <none>"
+	else
+		echo ""
+		for _mod in "${!large_mods[@]}"; do
+			echo "    $_mod: ${large_mods[$_mod]}"
+		done
+	fi
+
+	if [[ $reserved_size -lt $recommanded_size ]]; then
+		echo "WARNING: Current crashkernel size is lower than recommanded size $((recommanded_size / size_mb))M."
+	fi
+}
+
 if [ ! -f "$KDUMP_CONFIG_FILE" ]; then
 	derror "Error: No kdump config file found!"
 	exit 1
@@ -1269,8 +1360,11 @@ main ()
 	  showmem)
 		show_reserved_mem
 		;;
+	  estimate)
+		do_estimate
+		;;
 	  *)
-		dinfo $"Usage: $0 {start|stop|status|restart|reload|rebuild|propagate|showmem}"
+		dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem}"
 		exit 1
 	esac
 }
diff --git a/kdumpctl.8 b/kdumpctl.8
index ae97af7..a32a972 100644
--- a/kdumpctl.8
+++ b/kdumpctl.8
@@ -44,6 +44,11 @@ impossible to use password authentication during kdump.
 .TP
 .I showmem
 Prints the size of reserved memory for crash kernel in megabytes.
+.TP
+.I estimate
+Estimate a suitable crashkernel value for current machine. This is a
+best-effort estimate. It will print a recommanded crashkernel value
+based on current kdump setup, and list some details of memory usage.
 
 .SH "SEE ALSO"
 .BR kdump.conf (5),