-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAl4u6tsACgkQONu9yGCS aT693A//TExeDRnNnf+2v4TJorylyRr17BMxk/Ie2L5E6d2n/RWodsrOThAPU9tx 5alNUkXCT8Jd31BUVnUoPoAQ4zSymSVi++XEf05wDeO0tQ982IESGaLmu9EC1uMF nnM5y4IdRYmFI1Zji4h5vRJckoYUlB6Mdg4BgMr4Q1KX7RkZYfe6bjs7DwM/uyMx jVXdFaQBD1H6F5W6A+GmgUZ36g9uNqzcBxxWwv5URj+q816NdI4bsxIJMF0v0WC+ S54fmpS07QWIYKKsQBUepeSgEF4ECESOE2VoF1ICcnfakdPnDBmNgyPJPSrLmVf+ itRUxoH1MewaOvoJrv+xsGBPmM29LcKH2oBmj5DR2Xstp7ACPs+OtXJEU9dUTDN4 NhaSts5fIp0f4Y5mMn508pDUwYDAWDt99ZJWdx6aK/TRyUsHBgpxBQDt37BE3U5W PCBnObNe2b2KDAsVXLjX5iDYoA0+usFreveMo8uEP+ohfh0ANvJlRkzedYw7NquI ZCcT+I1P9q8aa0528tR332VLrQeYg+kG6LVi2kAabmRA/VtEsT0w90MY/eo2vuTU WlPmbs2yerv2HTm050e6MOgBZfPh7wP/FpbjsSXufj7EDywlfxF+1hXdwfrpPJeN fN3g0kepeUp7+kLzO40FLam/z5ndjAUhyN2SBaPzGsXjMkZdETk= =zvlh -----END PGP SIGNATURE----- Merge 4.19.99 into android-4.19 Changes in 4.19.99 Revert "efi: Fix debugobjects warning on 'efi_rts_work'" xfs: Sanity check flags of Q_XQUOTARM call i2c: stm32f7: rework slave_id allocation i2c: i2c-stm32f7: fix 10-bits check in slave free id search loop mfd: intel-lpss: Add default I2C device properties for Gemini Lake SUNRPC: Fix svcauth_gss_proxy_init() powerpc/pseries: Enable support for ibm,drc-info property powerpc/archrandom: fix arch_get_random_seed_int() tipc: update mon's self addr when node addr generated tipc: fix wrong timeout input for tipc_wait_for_cond() mt7601u: fix bbp version check in mt7601u_wait_bbp_ready crypto: sun4i-ss - fix big endian issues perf map: No need to adjust the long name of modules soc: aspeed: Fix snoop_file_poll()'s return type watchdog: sprd: Fix the incorrect pointer getting from driver data ipmi: Fix memory leak in __ipmi_bmc_register drm/sti: do not remove the drm_bridge that was never added ARM: dts: at91: nattis: set the PRLUD and HIPOW signals low ARM: dts: at91: nattis: make the SD-card slot work ixgbe: don't clear IPsec sa counters on HW clearing drm/virtio: fix bounds check in virtio_gpu_cmd_get_capset() iio: fix position relative kernel version apparmor: Fix network performance issue in aa_label_sk_perm ALSA: hda: fix unused variable warning apparmor: don't try to replace stale label in ptrace access check ARM: qcom_defconfig: Enable MAILBOX firmware: coreboot: Let OF core populate platform device PCI: iproc: Remove PAXC slot check to allow VF support bridge: br_arp_nd_proxy: set icmp6_router if neigh has NTF_ROUTER drm/hisilicon: hibmc: Don't overwrite fb helper surface depth signal/ia64: Use the generic force_sigsegv in setup_frame signal/ia64: Use the force_sig(SIGSEGV,...) in ia64_rt_sigreturn ASoC: wm9712: fix unused variable warning mailbox: mediatek: Add check for possible failure of kzalloc IB/rxe: replace kvfree with vfree IB/hfi1: Add mtu check for operational data VLs genirq/debugfs: Reinstate full OF path for domain name usb: dwc3: add EXTCON dependency for qcom usb: gadget: fsl_udc_core: check allocation return value and cleanup on failure cfg80211: regulatory: make initialization more robust mei: replace POLL* with EPOLL* for write queues. drm/msm: fix unsigned comparison with less than zero of: Fix property name in of_node_get_device_type ALSA: usb-audio: update quirk for B&W PX to remove microphone iwlwifi: nvm: get num of hw addresses from firmware staging: comedi: ni_mio_common: protect register write overflow netfilter: nft_osf: usage from output path is not valid pwm: lpss: Release runtime-pm reference from the driver's remove callback powerpc/pseries/memory-hotplug: Fix return value type of find_aa_index rtlwifi: rtl8821ae: replace _rtl8821ae_mrate_idx_to_arfr_id with generic version RDMA/bnxt_re: Add missing spin lock initialization netfilter: nf_flow_table: do not remove offload when other netns's interface is down powerpc/kgdb: add kgdb_arch_set/remove_breakpoint() tipc: eliminate message disordering during binding table update net: socionext: Add dummy PHY register read in phy_write() drm/sun4i: hdmi: Fix double flag assignation net: hns3: add error handler for hns3_nic_init_vector_data() mlxsw: reg: QEEC: Add minimum shaper fields mlxsw: spectrum: Set minimum shaper on MC TCs NTB: ntb_hw_idt: replace IS_ERR_OR_NULL with regular NULL checks ASoC: wm97xx: fix uninitialized regmap pointer problem ARM: dts: bcm283x: Correct mailbox register sizes pcrypt: use format specifier in kobject_add ASoC: sun8i-codec: add missing route for ADC pinctrl: meson-gxl: remove invalid GPIOX tsin_a pins bus: ti-sysc: Add mcasp optional clocks flag exportfs: fix 'passing zero to ERR_PTR()' warning drm: rcar-du: Fix the return value in case of error in 'rcar_du_crtc_set_crc_source()' drm: rcar-du: Fix vblank initialization net: always initialize pagedlen drm/dp_mst: Skip validating ports during destruction, just ref arm64: dts: meson-gx: Add hdmi_5v regulator as hdmi tx supply arm64: dts: renesas: r8a7795-es1: Add missing power domains to IPMMU nodes net: phy: Fix not to call phy_resume() if PHY is not attached IB/hfi1: Correctly process FECN and BECN in packets OPP: Fix missing debugfs supply directory for OPPs IB/rxe: Fix incorrect cache cleanup in error flow mailbox: ti-msgmgr: Off by one in ti_msgmgr_of_xlate() staging: bcm2835-camera: Abort probe if there is no camera staging: bcm2835-camera: fix module autoloading switchtec: Remove immediate status check after submitting MRPC command ipv6: add missing tx timestamping on IPPROTO_RAW pinctrl: sh-pfc: r8a7740: Add missing REF125CK pin to gether_gmii group pinctrl: sh-pfc: r8a7740: Add missing LCD0 marks to lcd0_data24_1 group pinctrl: sh-pfc: r8a7791: Remove bogus ctrl marks from qspi_data4_b group pinctrl: sh-pfc: r8a7791: Remove bogus marks from vin1_b_data18 group pinctrl: sh-pfc: sh73a0: Add missing TO pin to tpu4_to3 group pinctrl: sh-pfc: r8a7794: Remove bogus IPSR9 field pinctrl: sh-pfc: r8a77970: Add missing MOD_SEL0 field pinctrl: sh-pfc: r8a77980: Add missing MOD_SEL0 field pinctrl: sh-pfc: sh7734: Add missing IPSR11 field pinctrl: sh-pfc: r8a77995: Remove bogus SEL_PWM[0-3]_3 configurations pinctrl: sh-pfc: sh7269: Add missing PCIOR0 field pinctrl: sh-pfc: sh7734: Remove bogus IPSR10 value net: hns3: fix error handling int the hns3_get_vector_ring_chain vxlan: changelink: Fix handling of default remotes Input: nomadik-ske-keypad - fix a loop timeout test fork,memcg: fix crash in free_thread_stack on memcg charge fail clk: highbank: fix refcount leak in hb_clk_init() clk: qoriq: fix refcount leak in clockgen_init() clk: ti: fix refcount leak in ti_dt_clocks_register() clk: socfpga: fix refcount leak clk: samsung: exynos4: fix refcount leak in exynos4_get_xom() clk: imx6q: fix refcount leak in imx6q_clocks_init() clk: imx6sx: fix refcount leak in imx6sx_clocks_init() clk: imx7d: fix refcount leak in imx7d_clocks_init() clk: vf610: fix refcount leak in vf610_clocks_init() clk: armada-370: fix refcount leak in a370_clk_init() clk: kirkwood: fix refcount leak in kirkwood_clk_init() clk: armada-xp: fix refcount leak in axp_clk_init() clk: mv98dx3236: fix refcount leak in mv98dx3236_clk_init() clk: dove: fix refcount leak in dove_clk_init() MIPS: BCM63XX: drop unused and broken DSP platform device arm64: defconfig: Re-enable bcm2835-thermal driver remoteproc: qcom: q6v5-mss: Add missing clocks for MSM8996 remoteproc: qcom: q6v5-mss: Add missing regulator for MSM8996 drm: Fix error handling in drm_legacy_addctx ARM: dts: r8a7743: Remove generic compatible string from iic3 drm/etnaviv: fix some off by one bugs drm/fb-helper: generic: Fix setup error path fork, memcg: fix cached_stacks case IB/usnic: Fix out of bounds index check in query pkey RDMA/ocrdma: Fix out of bounds index check in query pkey RDMA/qedr: Fix out of bounds index check in query pkey drm/shmob: Fix return value check in shmob_drm_probe arm64: dts: apq8016-sbc: Increase load on l11 for SDCARD spi: cadence: Correct initialisation of runtime PM RDMA/iw_cxgb4: Fix the unchecked ep dereference net: phy: micrel: set soft_reset callback to genphy_soft_reset for KSZ9031 memory: tegra: Don't invoke Tegra30+ specific memory timing setup on Tegra20 drm/etnaviv: NULL vs IS_ERR() buf in etnaviv_core_dump() media: s5p-jpeg: Correct step and max values for V4L2_CID_JPEG_RESTART_INTERVAL kbuild: mark prepare0 as PHONY to fix external module build crypto: brcm - Fix some set-but-not-used warning crypto: tgr192 - fix unaligned memory access ASoC: imx-sgtl5000: put of nodes if finding codec fails IB/iser: Pass the correct number of entries for dma mapped SGL net: hns3: fix wrong combined count returned by ethtool -l media: tw9910: Unregister subdevice with v4l2-async IB/mlx5: Don't override existing ip_protocol rtc: cmos: ignore bogus century byte spi/topcliff_pch: Fix potential NULL dereference on allocation error net: hns3: fix bug of ethtool_ops.get_channels for VF ARM: dts: sun8i-a23-a33: Move NAND controller device node to sort by address clk: sunxi-ng: sun8i-a23: Enable PLL-MIPI LDOs when ungating it iwlwifi: mvm: avoid possible access out of array. net/mlx5: Take lock with IRQs disabled to avoid deadlock ip_tunnel: Fix route fl4 init in ip_md_tunnel_xmit arm64: dts: allwinner: h6: Move GIC device node fix base address ordering iwlwifi: mvm: fix A-MPDU reference assignment bus: ti-sysc: Fix timer handling with drop pm_runtime_irq_safe() tty: ipwireless: Fix potential NULL pointer dereference driver: uio: fix possible memory leak in __uio_register_device driver: uio: fix possible use-after-free in __uio_register_device crypto: crypto4xx - Fix wrong ppc4xx_trng_probe()/ppc4xx_trng_remove() arguments driver core: Fix DL_FLAG_AUTOREMOVE_SUPPLIER device link flag handling driver core: Avoid careless re-use of existing device links driver core: Do not resume suppliers under device_links_write_lock() driver core: Fix handling of runtime PM flags in device_link_add() driver core: Do not call rpm_put_suppliers() in pm_runtime_drop_link() ARM: dts: lpc32xx: add required clocks property to keypad device node ARM: dts: lpc32xx: reparent keypad controller to SIC1 ARM: dts: lpc32xx: fix ARM PrimeCell LCD controller variant ARM: dts: lpc32xx: fix ARM PrimeCell LCD controller clocks property ARM: dts: lpc32xx: phy3250: fix SD card regulator voltage drm/xen-front: Fix mmap attributes for display buffers iwlwifi: mvm: fix RSS config command staging: most: cdev: add missing check for cdev_add failure clk: ingenic: jz4740: Fix gating of UDC clock rtc: ds1672: fix unintended sign extension thermal: mediatek: fix register index error arm64: dts: msm8916: remove bogus argument to the cpu clock ath10k: fix dma unmap direction for management frames net: phy: fixed_phy: Fix fixed_phy not checking GPIO rtc: ds1307: rx8130: Fix alarm handling net/smc: original socket family in inet_sock_diag rtc: 88pm860x: fix unintended sign extension rtc: 88pm80x: fix unintended sign extension rtc: pm8xxx: fix unintended sign extension fbdev: chipsfb: remove set but not used variable 'size' iw_cxgb4: use tos when importing the endpoint iw_cxgb4: use tos when finding ipv6 routes ipmi: kcs_bmc: handle devm_kasprintf() failure case xsk: add missing smp_rmb() in xsk_mmap drm/etnaviv: potential NULL dereference ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers ntb_hw_switchtec: NT req id mapping table register entry number should be 512 pinctrl: sh-pfc: emev2: Add missing pinmux functions pinctrl: sh-pfc: r8a7791: Fix scifb2_data_c pin group pinctrl: sh-pfc: r8a7792: Fix vin1_data18_b pin group pinctrl: sh-pfc: sh73a0: Fix fsic_spdif pin groups RDMA/mlx5: Fix memory leak in case we fail to add an IB device driver core: Fix possible supplier PM-usage counter imbalance PCI: endpoint: functions: Use memcpy_fromio()/memcpy_toio() usb: phy: twl6030-usb: fix possible use-after-free on remove block: don't use bio->bi_vcnt to figure out segment number keys: Timestamp new keys net: dsa: b53: Fix default VLAN ID net: dsa: b53: Properly account for VLAN filtering net: dsa: b53: Do not program CPU port's PVID mt76: usb: fix possible memory leak in mt76u_buf_free media: sh: migor: Include missing dma-mapping header vfio_pci: Enable memory accesses before calling pci_map_rom hwmon: (pmbus/tps53679) Fix driver info initialization in probe routine mdio_bus: Fix PTR_ERR() usage after initialization to constant KVM: PPC: Release all hardware TCE tables attached to a group staging: r8822be: check kzalloc return or bail dmaengine: mv_xor: Use correct device for DMA API cdc-wdm: pass return value of recover_from_urb_loss brcmfmac: create debugfs files for bus-specific layer regulator: pv88060: Fix array out-of-bounds access regulator: pv88080: Fix array out-of-bounds access regulator: pv88090: Fix array out-of-bounds access net: dsa: qca8k: Enable delay for RGMII_ID mode net/mlx5: Delete unused FPGA QPN variable drm/nouveau/bios/ramcfg: fix missing parentheses when calculating RON drm/nouveau/pmu: don't print reply values if exec is false drm/nouveau: fix missing break in switch statement driver core: Fix PM-runtime for links added during consumer probe ASoC: qcom: Fix of-node refcount unbalance in apq8016_sbc_parse_of() net: dsa: fix unintended change of bridge interface STP state fs/nfs: Fix nfs_parse_devname to not modify it's argument staging: rtlwifi: Use proper enum for return in halmac_parse_psd_data_88xx powerpc/64s: Fix logic when handling unknown CPU features NFS: Fix a soft lockup in the delegation recovery code perf: Copy parent's address filter offsets on clone perf, pt, coresight: Fix address filters for vmas with non-zero offset clocksource/drivers/sun5i: Fail gracefully when clock rate is unavailable clocksource/drivers/exynos_mct: Fix error path in timer resources initialization platform/x86: wmi: fix potential null pointer dereference NFS/pnfs: Bulk destroy of layouts needs to be safe w.r.t. umount mmc: sdhci-brcmstb: handle mmc_of_parse() errors during probe iommu: Fix IOMMU debugfs fallout ARM: 8847/1: pm: fix HYP/SVC mode mismatch when MCPM is used ARM: 8848/1: virt: Align GIC version check with arm64 counterpart ARM: 8849/1: NOMMU: Fix encodings for PMSAv8's PRBAR4/PRLAR4 regulator: wm831x-dcdc: Fix list of wm831x_dcdc_ilim from mA to uA ath10k: Fix length of wmi tlv command for protected mgmt frames netfilter: nft_set_hash: fix lookups with fixed size hash on big endian netfilter: nft_set_hash: bogus element self comparison from deactivation path net: sched: act_csum: Fix csum calc for tagged packets hwrng: bcm2835 - fix probe as platform device iommu/vt-d: Fix NULL pointer reference in intel_svm_bind_mm() NFS: Add missing encode / decode sequence_maxsz to v4.2 operations NFSv4/flexfiles: Fix invalid deref in FF_LAYOUT_DEVID_NODE() net: aquantia: fixed instack structure overflow powerpc/mm: Check secondary hash page table media: dvb/earth-pt1: fix wrong initialization for demod blocks rbd: clear ->xferred on error from rbd_obj_issue_copyup() PCI: Fix "try" semantics of bus and slot reset nios2: ksyms: Add missing symbol exports x86/mm: Remove unused variable 'cpu' scsi: megaraid_sas: reduce module load time nfp: fix simple vNIC mailbox length drivers/rapidio/rio_cm.c: fix potential oops in riocm_ch_listen() xen, cpu_hotplug: Prevent an out of bounds access net/mlx5: Fix multiple updates of steering rules in parallel net/mlx5e: IPoIB, Fix RX checksum statistics update net: sh_eth: fix a missing check of of_get_phy_mode regulator: lp87565: Fix missing register for LP87565_BUCK_0 soc: amlogic: gx-socinfo: Add mask for each SoC packages media: ivtv: update *pos correctly in ivtv_read_pos() media: cx18: update *pos correctly in cx18_read_pos() media: wl128x: Fix an error code in fm_download_firmware() media: cx23885: check allocation return regulator: tps65086: Fix tps65086_ldoa1_ranges for selector 0xB crypto: ccree - reduce kernel stack usage with clang jfs: fix bogus variable self-initialization tipc: tipc clang warning m68k: mac: Fix VIA timer counter accesses ARM: dts: sun8i: a33: Reintroduce default pinctrl muxing arm64: dts: allwinner: a64: Add missing PIO clocks ARM: dts: sun9i: optimus: Fix fixed-regulators net: phy: don't clear BMCR in genphy_soft_reset ARM: OMAP2+: Fix potentially uninitialized return value for _setup_reset() net: dsa: Avoid null pointer when failing to connect to PHY soc: qcom: cmd-db: Fix an error code in cmd_db_dev_probe() media: davinci-isif: avoid uninitialized variable use media: tw5864: Fix possible NULL pointer dereference in tw5864_handle_frame spi: tegra114: clear packed bit for unpacked mode spi: tegra114: fix for unpacked mode transfers spi: tegra114: terminate dma and reset on transfer timeout spi: tegra114: flush fifos spi: tegra114: configure dma burst size to fifo trig level bus: ti-sysc: Fix sysc_unprepare() when no clocks have been allocated soc/fsl/qe: Fix an error code in qe_pin_request() spi: bcm2835aux: fix driver to not allow 65535 (=-1) cs-gpios drm/fb-helper: generic: Call drm_client_add() after setup is done arm64/vdso: don't leak kernel addresses rtc: Fix timestamp value for RTC_TIMESTAMP_BEGIN_1900 rtc: mt6397: Don't call irq_dispose_mapping. ehea: Fix a copy-paste err in ehea_init_port_res bpf: Add missed newline in verifier verbose log drm/vmwgfx: Remove set but not used variable 'restart' scsi: qla2xxx: Unregister chrdev if module initialization fails of: use correct function prototype for of_overlay_fdt_apply() net/sched: cbs: fix port_rate miscalculation clk: qcom: Skip halt checks on gcc_pcie_0_pipe_clk for 8998 ACPI: button: reinitialize button state upon resume firmware: arm_scmi: fix of_node leak in scmi_mailbox_check rxrpc: Fix detection of out of order acks scsi: target/core: Fix a race condition in the LUN lookup code brcmfmac: fix leak of mypkt on error return path ARM: pxa: ssp: Fix "WARNING: invalid free of devm_ allocated data" PCI: rockchip: Fix rockchip_pcie_ep_assert_intx() bitwise operations net: hns3: fix for vport->bw_limit overflow problem hwmon: (w83627hf) Use request_muxed_region for Super-IO accesses perf/core: Fix the address filtering fix staging: android: vsoc: fix copy_from_user overrun PCI: dwc: Fix dw_pcie_ep_find_capability() to return correct capability offset soc: amlogic: meson-gx-pwrc-vpu: Fix power on/off register bitmask platform/x86: alienware-wmi: fix kfree on potentially uninitialized pointer tipc: set sysctl_tipc_rmem and named_timeout right range usb: typec: tcpm: Notify the tcpc to start connection-detection for SRPs selftests/ipc: Fix msgque compiler warnings net: hns3: fix loop condition of hns3_get_tx_timeo_queue_info() powerpc: vdso: Make vdso32 installation conditional in vdso_install ARM: dts: ls1021: Fix SGMII PCS link remaining down after PHY disconnect media: ov2659: fix unbalanced mutex_lock/unlock 6lowpan: Off by one handling ->nexthdr dmaengine: axi-dmac: Don't check the number of frames for alignment ALSA: usb-audio: Handle the error from snd_usb_mixer_apply_create_quirk() afs: Fix AFS file locking to allow fine grained locks afs: Further fix file locking NFS: Don't interrupt file writeout due to fatal errors coresight: catu: fix clang build warning s390/kexec_file: Fix potential segment overlap in ELF loader irqchip/gic-v3-its: fix some definitions of inner cacheability attributes scsi: qla2xxx: Fix a format specifier scsi: qla2xxx: Fix error handling in qlt_alloc_qfull_cmd() scsi: qla2xxx: Avoid that qlt_send_resp_ctio() corrupts memory KVM: PPC: Book3S HV: Fix lockdep warning when entering the guest netfilter: nft_flow_offload: add entry to flowtable after confirmation PCI: iproc: Enable iProc config read for PAXBv2 ARM: dts: logicpd-som-lv: Fix MMC1 card detect packet: in recvmsg msg_name return at least sizeof sockaddr_ll ASoC: fix valid stream condition usb: gadget: fsl: fix link error against usb-gadget module dwc2: gadget: Fix completed transfer size calculation in DDMA IB/mlx5: Add missing XRC options to QP optional params mask RDMA/rxe: Consider skb reserve space based on netdev of GID iommu/vt-d: Make kernel parameter igfx_off work with vIOMMU net: ena: fix swapped parameters when calling ena_com_indirect_table_fill_entry net: ena: fix: Free napi resources when ena_up() fails net: ena: fix incorrect test of supported hash function net: ena: fix ena_com_fill_hash_function() implementation dmaengine: tegra210-adma: restore channel status watchdog: rtd119x_wdt: Fix remove function mmc: core: fix possible use after free of host lightnvm: pblk: fix lock order in pblk_rb_tear_down_check ath10k: Fix encoding for protected management frames afs: Fix the afs.cell and afs.volume xattr handlers vfio/mdev: Avoid release parent reference during error path vfio/mdev: Follow correct remove sequence vfio/mdev: Fix aborting mdev child device removal if one fails l2tp: Fix possible NULL pointer dereference ALSA: aica: Fix a long-time build breakage media: omap_vout: potential buffer overflow in vidioc_dqbuf() media: davinci/vpbe: array underflow in vpbe_enum_outputs() platform/x86: alienware-wmi: printing the wrong error code crypto: caam - fix caam_dump_sg that iterates through scatterlist netfilter: ebtables: CONFIG_COMPAT: reject trailing data after last rule pwm: meson: Consider 128 a valid pre-divider pwm: meson: Don't disable PWM when setting duty repeatedly ARM: riscpc: fix lack of keyboard interrupts after irq conversion nfp: bpf: fix static check error through tightening shift amount adjustment kdb: do a sanity check on the cpu in kdb_per_cpu() netfilter: nf_tables: correct NFT_LOGLEVEL_MAX value backlight: lm3630a: Return 0 on success in update_status functions thermal: rcar_gen3_thermal: fix interrupt type thermal: cpu_cooling: Actually trace CPU load in thermal_power_cpu_get_power EDAC/mc: Fix edac_mc_find() in case no device is found afs: Fix key leak in afs_release() and afs_evict_inode() afs: Don't invalidate callback if AFS_VNODE_DIR_VALID not set afs: Fix lock-wait/callback-break double locking afs: Fix double inc of vnode->cb_break ARM: dts: sun8i-h3: Fix wifi in Beelink X2 DT clk: meson: gxbb: no spread spectrum on mpll0 clk: meson: axg: spread spectrum is on mpll2 dmaengine: tegra210-adma: Fix crash during probe arm64: dts: meson: libretech-cc: set eMMC as removable RDMA/qedr: Fix incorrect device rate. spi: spi-fsl-spi: call spi_finalize_current_message() at the end crypto: ccp - fix AES CFB error exposed by new test vectors crypto: ccp - Fix 3DES complaint from ccp-crypto module serial: stm32: fix word length configuration serial: stm32: fix rx error handling serial: stm32: fix rx data length when parity enabled serial: stm32: fix transmit_chars when tx is stopped serial: stm32: Add support of TC bit status check serial: stm32: fix wakeup source initialization misc: sgi-xp: Properly initialize buf in xpc_get_rsvd_page_pa iommu: Add missing new line for dma type iommu: Use right function to get group for device signal/bpfilter: Fix bpfilter_kernl to use send_sig not force_sig signal/cifs: Fix cifs_put_tcp_session to call send_sig instead of force_sig inet: frags: call inet_frags_fini() after unregister_pernet_subsys() net: hns3: fix a memory leak issue for hclge_map_unmap_ring_to_vf_vector crypto: talitos - fix AEAD processing. netvsc: unshare skb in VF rx handler net: core: support XDP generic on stacked devices. RDMA/uverbs: check for allocation failure in uapi_add_elm() net: don't clear sock->sk early to avoid trouble in strparser phy: qcom-qusb2: fix missing assignment of ret when calling clk_prepare_enable cpufreq: brcmstb-avs-cpufreq: Fix initial command check cpufreq: brcmstb-avs-cpufreq: Fix types for voltage/frequency clk: sunxi-ng: sun50i-h6-r: Fix incorrect W1 clock gate register media: vivid: fix incorrect assignment operation when setting video mode crypto: inside-secure - fix zeroing of the request in ahash_exit_inv crypto: inside-secure - fix queued len computation arm64: dts: renesas: ebisu: Remove renesas, no-ether-link property mpls: fix warning with multi-label encap serial: stm32: fix a recursive locking in stm32_config_rs485 arm64: dts: meson-gxm-khadas-vim2: fix gpio-keys-polled node arm64: dts: meson-gxm-khadas-vim2: fix Bluetooth support iommu/vt-d: Duplicate iommu_resv_region objects per device list phy: usb: phy-brcm-usb: Remove sysfs attributes upon driver removal firmware: arm_scmi: fix bitfield definitions for SENSOR_DESC attributes firmware: arm_scmi: update rate_discrete in clock_describe_rates_get ntb_hw_switchtec: potential shift wrapping bug in switchtec_ntb_init_sndev() ASoC: meson: axg-tdmin: right_j is not supported ASoC: meson: axg-tdmout: right_j is not supported qed: iWARP - Use READ_ONCE and smp_store_release to access ep->state qed: iWARP - fix uninitialized callback powerpc/cacheinfo: add cacheinfo_teardown, cacheinfo_rebuild powerpc/pseries/mobility: rebuild cacheinfo hierarchy post-migration bpf: fix the check that forwarding is enabled in bpf_ipv6_fib_lookup IB/hfi1: Handle port down properly in pio drm/msm/mdp5: Fix mdp5_cfg_init error return net: netem: fix backlog accounting for corrupted GSO frames net/udp_gso: Allow TX timestamp with UDP GSO net/af_iucv: build proper skbs for HiperTransport net/af_iucv: always register net_device notifier ASoC: ti: davinci-mcasp: Fix slot mask settings when using multiple AXRs rtc: pcf8563: Fix interrupt trigger method rtc: pcf8563: Clear event flags and disable interrupts before requesting irq ARM: dts: iwg20d-q7-common: Fix SDHI1 VccQ regularor net/sched: cbs: Fix error path of cbs_module_init arm64: dts: allwinner: h6: Pine H64: Add interrupt line for RTC drm/msm/a3xx: remove TPL1 regs from snapshot ip6_fib: Don't discard nodes with valid routing information in fib6_locate_1() perf/ioctl: Add check for the sample_period value dmaengine: hsu: Revert "set HSU_CH_MTSR to memory width" clk: qcom: Fix -Wunused-const-variable nvmem: imx-ocotp: Ensure WAIT bits are preserved when setting timing nvmem: imx-ocotp: Change TIMING calculation to u-boot algorithm tools: bpftool: use correct argument in cgroup errors backlight: pwm_bl: Fix heuristic to determine number of brightness levels fork,memcg: alloc_thread_stack_node needs to set tsk->stack bnxt_en: Fix ethtool selftest crash under error conditions. bnxt_en: Suppress error messages when querying DSCP DCB capabilities. iommu/amd: Make iommu_disable safer mfd: intel-lpss: Release IDA resources rxrpc: Fix uninitialized error code in rxrpc_send_data_packet() xprtrdma: Fix use-after-free in rpcrdma_post_recvs um: Fix IRQ controller regression on console read PM: ACPI/PCI: Resume all devices during hibernation ACPI: PM: Simplify and fix PM domain hibernation callbacks ACPI: PM: Introduce "poweroff" callbacks for ACPI PM domain and LPSS fsi/core: Fix error paths on CFAM init devres: allow const resource arguments fsi: sbefifo: Don't fail operations when in SBE IPL state RDMA/hns: Fixs hw access invalid dma memory error PCI: mobiveil: Remove the flag MSI_FLAG_MULTI_PCI_MSI PCI: mobiveil: Fix devfn check in mobiveil_pcie_valid_device() PCI: mobiveil: Fix the valid check for inbound and outbound windows ceph: fix "ceph.dir.rctime" vxattr value net: pasemi: fix an use-after-free in pasemi_mac_phy_init() net/tls: fix socket wmem accounting on fallback with netem x86/pgtable/32: Fix LOWMEM_PAGES constant xdp: fix possible cq entry leak ARM: stm32: use "depends on" instead of "if" after prompt scsi: libfc: fix null pointer dereference on a null lport xfrm interface: ifname may be wrong in logs drm/panel: make drm_panel.h self-contained clk: sunxi-ng: v3s: add the missing PLL_DDR1 PM: sleep: Fix possible overflow in pm_system_cancel_wakeup() libertas_tf: Use correct channel range in lbtf_geo_init qed: reduce maximum stack frame size usb: host: xhci-hub: fix extra endianness conversion media: rcar-vin: Clean up correct notifier in error path mic: avoid statically declaring a 'struct device'. x86/kgbd: Use NMI_VECTOR not APIC_DM_NMI crypto: ccp - Reduce maximum stack usage ALSA: aoa: onyx: always initialize register read value arm64: dts: renesas: r8a77995: Fix register range of display node tipc: reduce risk of wakeup queue starvation ARM: dts: stm32: add missing vdda-supply to adc on stm32h743i-eval net/mlx5: Fix mlx5_ifc_query_lag_out_bits cifs: fix rmmod regression in cifs.ko caused by force_sig changes iio: tsl2772: Use devm_add_action_or_reset for tsl2772_chip_off net: fix bpf_xdp_adjust_head regression for generic-XDP spi: bcm-qspi: Fix BSPI QUAD and DUAL mode support when using flex mode cxgb4: smt: Add lock for atomic_dec_and_test crypto: caam - free resources in case caam_rng registration failed ext4: set error return correctly when ext4_htree_store_dirent fails RDMA/hns: Bugfix for slab-out-of-bounds when unloading hip08 driver RDMA/hns: bugfix for slab-out-of-bounds when loading hip08 driver ASoC: es8328: Fix copy-paste error in es8328_right_line_controls ASoC: cs4349: Use PM ops 'cs4349_runtime_pm' ASoC: wm8737: Fix copy-paste error in wm8737_snd_controls net/rds: Add a few missing rds_stat_names entries tools: bpftool: fix arguments for p_err() in do_event_pipe() tools: bpftool: fix format strings and arguments for jsonw_printf() drm: rcar-du: lvds: Fix bridge_to_rcar_lvds bnxt_en: Fix handling FRAG_ERR when NVM_INSTALL_UPDATE cmd fails signal: Allow cifs and drbd to receive their terminating signals powerpc/64s/radix: Fix memory hot-unplug page table split ASoC: sun4i-i2s: RX and TX counter registers are swapped dmaengine: dw: platform: Switch to acpi_dma_controller_register() rtc: rv3029: revert error handling patch to rv3029_eeprom_write() mac80211: minstrel_ht: fix per-group max throughput rate initialization i40e: reduce stack usage in i40e_set_fc media: atmel: atmel-isi: fix timeout value for stop streaming ARM: 8896/1: VDSO: Don't leak kernel addresses rtc: pcf2127: bugfix: read rtc disables watchdog mips: avoid explicit UB in assignment of mips_io_port_base media: em28xx: Fix exception handling in em28xx_alloc_urbs() iommu/mediatek: Fix iova_to_phys PA start for 4GB mode ahci: Do not export local variable ahci_em_messages rxrpc: Fix lack of conn cleanup when local endpoint is cleaned up [ver #2] Partially revert "kfifo: fix kfifo_alloc() and kfifo_init()" hwmon: (lm75) Fix write operations for negative temperatures net/sched: cbs: Set default link speed to 10 Mbps in cbs_set_port_rate power: supply: Init device wakeup after device_add() x86, perf: Fix the dependency of the x86 insn decoder selftest staging: greybus: light: fix a couple double frees irqdomain: Add the missing assignment of domain->fwnode for named fwnode bcma: fix incorrect update of BCMA_CORE_PCI_MDIO_DATA usb: typec: tps6598x: Fix build error without CONFIG_REGMAP_I2C bcache: Fix an error code in bch_dump_read() iio: dac: ad5380: fix incorrect assignment to val netfilter: ctnetlink: honor IPS_OFFLOAD flag ath9k: dynack: fix possible deadlock in ath_dynack_node_{de}init wcn36xx: use dynamic allocation for large variables tty: serial: fsl_lpuart: Use appropriate lpuart32_* I/O funcs ARM: dts: aspeed-g5: Fixe gpio-ranges upper limit xsk: avoid store-tearing when assigning queues xsk: avoid store-tearing when assigning umem led: triggers: Fix dereferencing of null pointer net: sonic: return NETDEV_TX_OK if failed to map buffer net: hns3: fix error VF index when setting VLAN offload rtlwifi: Fix file release memory leak ARM: dts: logicpd-som-lv: Fix i2c2 and i2c3 Pin mux f2fs: fix wrong error injection path in inc_valid_block_count() f2fs: fix error path of f2fs_convert_inline_page() scsi: fnic: fix msix interrupt allocation Btrfs: fix hang when loading existing inode cache off disk Btrfs: fix inode cache waiters hanging on failure to start caching thread Btrfs: fix inode cache waiters hanging on path allocation failure btrfs: use correct count in btrfs_file_write_iter() ixgbe: sync the first fragment unconditionally hwmon: (shtc1) fix shtc1 and shtw1 id mask net: sonic: replace dev_kfree_skb in sonic_send_packet pinctrl: iproc-gpio: Fix incorrect pinconf configurations gpio/aspeed: Fix incorrect number of banks ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet RDMA/cma: Fix false error message net/rds: Fix 'ib_evt_handler_call' element in 'rds_ib_stat_names' um: Fix off by one error in IRQ enumeration bnxt_en: Increase timeout for HWRM_DBG_COREDUMP_XX commands f2fs: fix to avoid accessing uninitialized field of inode page in is_alive() mailbox: qcom-apcs: fix max_register value clk: actions: Fix factor clk struct member access powerpc/mm/mce: Keep irqs disabled during lockless page table walk bpf: fix BTF limits crypto: hisilicon - Matching the dma address for dma_pool_free() iommu/amd: Wait for completion of IOTLB flush in attach_device net: aquantia: Fix aq_vec_isr_legacy() return value cxgb4: Signedness bug in init_one() net: hisilicon: Fix signedness bug in hix5hd2_dev_probe() net: broadcom/bcmsysport: Fix signedness in bcm_sysport_probe() net: netsec: Fix signedness bug in netsec_probe() net: socionext: Fix a signedness bug in ave_probe() net: stmmac: dwmac-meson8b: Fix signedness bug in probe net: axienet: fix a signedness bug in probe of: mdio: Fix a signedness bug in of_phy_get_and_connect() net: nixge: Fix a signedness bug in nixge_probe() net: ethernet: stmmac: Fix signedness bug in ipq806x_gmac_of_parse() net: sched: cbs: Avoid division by zero when calculating the port rate nvme: retain split access workaround for capability reads net: stmmac: gmac4+: Not all Unicast addresses may be available rxrpc: Fix trace-after-put looking at the put connection record mac80211: accept deauth frames in IBSS mode llc: fix another potential sk_buff leak in llc_ui_sendmsg() llc: fix sk_buff refcounting in llc_conn_state_process() ip6erspan: remove the incorrect mtu limit for ip6erspan net: stmmac: fix length of PTP clock's name string net: stmmac: fix disabling flexible PPS output sctp: add chunks to sk_backlog when the newsk sk_socket is not set s390/qeth: Fix error handling during VNICC initialization s390/qeth: Fix initialization of vnicc cmd masks during set online act_mirred: Fix mirred_init_module error handling net: avoid possible false sharing in sk_leave_memory_pressure() net: add {READ|WRITE}_ONCE() annotations on ->rskq_accept_head tcp: annotate lockless access to tcp_memory_pressure net/smc: receive returns without data net/smc: receive pending data after RCV_SHUTDOWN drm/msm/dsi: Implement reset correctly vhost/test: stop device before reset dmaengine: imx-sdma: fix size check for sdma script_number firmware: dmi: Fix unlikely out-of-bounds read in save_mem_devices arm64: hibernate: check pgd table allocation net: netem: fix error path for corrupted GSO frames net: netem: correct the parent's backlog when corrupted packet was dropped xsk: Fix registration of Rx-only sockets bpf, offload: Unlock on error in bpf_offload_dev_create() afs: Fix missing timeout reset net: qca_spi: Move reset_count to struct qcaspi hv_netvsc: Fix offset usage in netvsc_send_table() hv_netvsc: Fix send_table offset in case of a host bug afs: Fix large file support drm: panel-lvds: Potential Oops in probe error handling hwrng: omap3-rom - Fix missing clock by probing with device tree dpaa_eth: perform DMA unmapping before read dpaa_eth: avoid timestamp read on error paths MIPS: Loongson: Fix return value of loongson_hwmon_init hv_netvsc: flag software created hash value net: neigh: use long type to store jiffies delta packet: fix data-race in fanout_flow_is_huge() i2c: stm32f7: report dma error during probe mmc: sdio: fix wl1251 vendor id mmc: core: fix wl1251 sdio quirks affs: fix a memory leak in affs_remount afs: Remove set but not used variables 'before', 'after' dmaengine: ti: edma: fix missed failure handling drm/radeon: fix bad DMA from INTERRUPT_CNTL2 arm64: dts: juno: Fix UART frequency samples/bpf: Fix broken xdp_rxq_info due to map order assumptions usb: dwc3: Allow building USB_DWC3_QCOM without EXTCON IB/iser: Fix dma_nents type definition serial: stm32: fix clearing interrupt error flags arm64: dts: meson-gxm-khadas-vim2: fix uart_A bluetooth node m68k: Call timer_interrupt() with interrupts disabled Linux 4.19.99 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ieabeab79ea5c8cb4b6b1552702fa5d6100cea5db
2939 lines
70 KiB
C
2939 lines
70 KiB
C
/*
|
|
* Kernel Debugger Architecture Independent Main Code
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
|
|
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
|
|
* Xscale (R) modifications copyright (C) 2003 Intel Corporation.
|
|
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
|
|
*/
|
|
|
|
#include <linux/ctype.h>
|
|
#include <linux/types.h>
|
|
#include <linux/string.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kmsg_dump.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched/loadavg.h>
|
|
#include <linux/sched/stat.h>
|
|
#include <linux/sched/debug.h>
|
|
#include <linux/sysrq.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/utsname.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/atomic.h>
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kallsyms.h>
|
|
#include <linux/kgdb.h>
|
|
#include <linux/kdb.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/nmi.h>
|
|
#include <linux/time.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/sysctl.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/kdebug.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/slab.h>
|
|
#include "kdb_private.h"
|
|
|
|
#undef MODULE_PARAM_PREFIX
|
|
#define MODULE_PARAM_PREFIX "kdb."
|
|
|
|
static int kdb_cmd_enabled = CONFIG_KDB_DEFAULT_ENABLE;
|
|
module_param_named(cmd_enable, kdb_cmd_enabled, int, 0600);
|
|
|
|
char kdb_grep_string[KDB_GREP_STRLEN];
|
|
int kdb_grepping_flag;
|
|
EXPORT_SYMBOL(kdb_grepping_flag);
|
|
int kdb_grep_leading;
|
|
int kdb_grep_trailing;
|
|
|
|
/*
|
|
* Kernel debugger state flags
|
|
*/
|
|
int kdb_flags;
|
|
|
|
/*
|
|
* kdb_lock protects updates to kdb_initial_cpu. Used to
|
|
* single thread processors through the kernel debugger.
|
|
*/
|
|
int kdb_initial_cpu = -1; /* cpu number that owns kdb */
|
|
int kdb_nextline = 1;
|
|
int kdb_state; /* General KDB state */
|
|
|
|
struct task_struct *kdb_current_task;
|
|
EXPORT_SYMBOL(kdb_current_task);
|
|
struct pt_regs *kdb_current_regs;
|
|
|
|
const char *kdb_diemsg;
|
|
static int kdb_go_count;
|
|
#ifdef CONFIG_KDB_CONTINUE_CATASTROPHIC
|
|
static unsigned int kdb_continue_catastrophic =
|
|
CONFIG_KDB_CONTINUE_CATASTROPHIC;
|
|
#else
|
|
static unsigned int kdb_continue_catastrophic;
|
|
#endif
|
|
|
|
/* kdb_commands describes the available commands. */
|
|
static kdbtab_t *kdb_commands;
|
|
#define KDB_BASE_CMD_MAX 50
|
|
static int kdb_max_commands = KDB_BASE_CMD_MAX;
|
|
static kdbtab_t kdb_base_commands[KDB_BASE_CMD_MAX];
|
|
#define for_each_kdbcmd(cmd, num) \
|
|
for ((cmd) = kdb_base_commands, (num) = 0; \
|
|
num < kdb_max_commands; \
|
|
num++, num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++)
|
|
|
|
typedef struct _kdbmsg {
|
|
int km_diag; /* kdb diagnostic */
|
|
char *km_msg; /* Corresponding message text */
|
|
} kdbmsg_t;
|
|
|
|
#define KDBMSG(msgnum, text) \
|
|
{ KDB_##msgnum, text }
|
|
|
|
static kdbmsg_t kdbmsgs[] = {
|
|
KDBMSG(NOTFOUND, "Command Not Found"),
|
|
KDBMSG(ARGCOUNT, "Improper argument count, see usage."),
|
|
KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, "
|
|
"8 is only allowed on 64 bit systems"),
|
|
KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"),
|
|
KDBMSG(NOTENV, "Cannot find environment variable"),
|
|
KDBMSG(NOENVVALUE, "Environment variable should have value"),
|
|
KDBMSG(NOTIMP, "Command not implemented"),
|
|
KDBMSG(ENVFULL, "Environment full"),
|
|
KDBMSG(ENVBUFFULL, "Environment buffer full"),
|
|
KDBMSG(TOOMANYBPT, "Too many breakpoints defined"),
|
|
#ifdef CONFIG_CPU_XSCALE
|
|
KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"),
|
|
#else
|
|
KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"),
|
|
#endif
|
|
KDBMSG(DUPBPT, "Duplicate breakpoint address"),
|
|
KDBMSG(BPTNOTFOUND, "Breakpoint not found"),
|
|
KDBMSG(BADMODE, "Invalid IDMODE"),
|
|
KDBMSG(BADINT, "Illegal numeric value"),
|
|
KDBMSG(INVADDRFMT, "Invalid symbolic address format"),
|
|
KDBMSG(BADREG, "Invalid register name"),
|
|
KDBMSG(BADCPUNUM, "Invalid cpu number"),
|
|
KDBMSG(BADLENGTH, "Invalid length field"),
|
|
KDBMSG(NOBP, "No Breakpoint exists"),
|
|
KDBMSG(BADADDR, "Invalid address"),
|
|
KDBMSG(NOPERM, "Permission denied"),
|
|
};
|
|
#undef KDBMSG
|
|
|
|
static const int __nkdb_err = ARRAY_SIZE(kdbmsgs);
|
|
|
|
|
|
/*
|
|
* Initial environment. This is all kept static and local to
|
|
* this file. We don't want to rely on the memory allocation
|
|
* mechanisms in the kernel, so we use a very limited allocate-only
|
|
* heap for new and altered environment variables. The entire
|
|
* environment is limited to a fixed number of entries (add more
|
|
* to __env[] if required) and a fixed amount of heap (add more to
|
|
* KDB_ENVBUFSIZE if required).
|
|
*/
|
|
|
|
static char *__env[] = {
|
|
#if defined(CONFIG_SMP)
|
|
"PROMPT=[%d]kdb> ",
|
|
#else
|
|
"PROMPT=kdb> ",
|
|
#endif
|
|
"MOREPROMPT=more> ",
|
|
"RADIX=16",
|
|
"MDCOUNT=8", /* lines of md output */
|
|
KDB_PLATFORM_ENV,
|
|
"DTABCOUNT=30",
|
|
"NOSECT=1",
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
};
|
|
|
|
static const int __nenv = ARRAY_SIZE(__env);
|
|
|
|
struct task_struct *kdb_curr_task(int cpu)
|
|
{
|
|
struct task_struct *p = curr_task(cpu);
|
|
#ifdef _TIF_MCA_INIT
|
|
if ((task_thread_info(p)->flags & _TIF_MCA_INIT) && KDB_TSK(cpu))
|
|
p = krp->p;
|
|
#endif
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
* Check whether the flags of the current command and the permissions
|
|
* of the kdb console has allow a command to be run.
|
|
*/
|
|
static inline bool kdb_check_flags(kdb_cmdflags_t flags, int permissions,
|
|
bool no_args)
|
|
{
|
|
/* permissions comes from userspace so needs massaging slightly */
|
|
permissions &= KDB_ENABLE_MASK;
|
|
permissions |= KDB_ENABLE_ALWAYS_SAFE;
|
|
|
|
/* some commands change group when launched with no arguments */
|
|
if (no_args)
|
|
permissions |= permissions << KDB_ENABLE_NO_ARGS_SHIFT;
|
|
|
|
flags |= KDB_ENABLE_ALL;
|
|
|
|
return permissions & flags;
|
|
}
|
|
|
|
/*
|
|
* kdbgetenv - This function will return the character string value of
|
|
* an environment variable.
|
|
* Parameters:
|
|
* match A character string representing an environment variable.
|
|
* Returns:
|
|
* NULL No environment variable matches 'match'
|
|
* char* Pointer to string value of environment variable.
|
|
*/
|
|
char *kdbgetenv(const char *match)
|
|
{
|
|
char **ep = __env;
|
|
int matchlen = strlen(match);
|
|
int i;
|
|
|
|
for (i = 0; i < __nenv; i++) {
|
|
char *e = *ep++;
|
|
|
|
if (!e)
|
|
continue;
|
|
|
|
if ((strncmp(match, e, matchlen) == 0)
|
|
&& ((e[matchlen] == '\0')
|
|
|| (e[matchlen] == '='))) {
|
|
char *cp = strchr(e, '=');
|
|
return cp ? ++cp : "";
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* kdballocenv - This function is used to allocate bytes for
|
|
* environment entries.
|
|
* Parameters:
|
|
* match A character string representing a numeric value
|
|
* Outputs:
|
|
* *value the unsigned long representation of the env variable 'match'
|
|
* Returns:
|
|
* Zero on success, a kdb diagnostic on failure.
|
|
* Remarks:
|
|
* We use a static environment buffer (envbuffer) to hold the values
|
|
* of dynamically generated environment variables (see kdb_set). Buffer
|
|
* space once allocated is never free'd, so over time, the amount of space
|
|
* (currently 512 bytes) will be exhausted if env variables are changed
|
|
* frequently.
|
|
*/
|
|
static char *kdballocenv(size_t bytes)
|
|
{
|
|
#define KDB_ENVBUFSIZE 512
|
|
static char envbuffer[KDB_ENVBUFSIZE];
|
|
static int envbufsize;
|
|
char *ep = NULL;
|
|
|
|
if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) {
|
|
ep = &envbuffer[envbufsize];
|
|
envbufsize += bytes;
|
|
}
|
|
return ep;
|
|
}
|
|
|
|
/*
|
|
* kdbgetulenv - This function will return the value of an unsigned
|
|
* long-valued environment variable.
|
|
* Parameters:
|
|
* match A character string representing a numeric value
|
|
* Outputs:
|
|
* *value the unsigned long represntation of the env variable 'match'
|
|
* Returns:
|
|
* Zero on success, a kdb diagnostic on failure.
|
|
*/
|
|
static int kdbgetulenv(const char *match, unsigned long *value)
|
|
{
|
|
char *ep;
|
|
|
|
ep = kdbgetenv(match);
|
|
if (!ep)
|
|
return KDB_NOTENV;
|
|
if (strlen(ep) == 0)
|
|
return KDB_NOENVVALUE;
|
|
|
|
*value = simple_strtoul(ep, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdbgetintenv - This function will return the value of an
|
|
* integer-valued environment variable.
|
|
* Parameters:
|
|
* match A character string representing an integer-valued env variable
|
|
* Outputs:
|
|
* *value the integer representation of the environment variable 'match'
|
|
* Returns:
|
|
* Zero on success, a kdb diagnostic on failure.
|
|
*/
|
|
int kdbgetintenv(const char *match, int *value)
|
|
{
|
|
unsigned long val;
|
|
int diag;
|
|
|
|
diag = kdbgetulenv(match, &val);
|
|
if (!diag)
|
|
*value = (int) val;
|
|
return diag;
|
|
}
|
|
|
|
/*
|
|
* kdbgetularg - This function will convert a numeric string into an
|
|
* unsigned long value.
|
|
* Parameters:
|
|
* arg A character string representing a numeric value
|
|
* Outputs:
|
|
* *value the unsigned long represntation of arg.
|
|
* Returns:
|
|
* Zero on success, a kdb diagnostic on failure.
|
|
*/
|
|
int kdbgetularg(const char *arg, unsigned long *value)
|
|
{
|
|
char *endp;
|
|
unsigned long val;
|
|
|
|
val = simple_strtoul(arg, &endp, 0);
|
|
|
|
if (endp == arg) {
|
|
/*
|
|
* Also try base 16, for us folks too lazy to type the
|
|
* leading 0x...
|
|
*/
|
|
val = simple_strtoul(arg, &endp, 16);
|
|
if (endp == arg)
|
|
return KDB_BADINT;
|
|
}
|
|
|
|
*value = val;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int kdbgetu64arg(const char *arg, u64 *value)
|
|
{
|
|
char *endp;
|
|
u64 val;
|
|
|
|
val = simple_strtoull(arg, &endp, 0);
|
|
|
|
if (endp == arg) {
|
|
|
|
val = simple_strtoull(arg, &endp, 16);
|
|
if (endp == arg)
|
|
return KDB_BADINT;
|
|
}
|
|
|
|
*value = val;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_set - This function implements the 'set' command. Alter an
|
|
* existing environment variable or create a new one.
|
|
*/
|
|
int kdb_set(int argc, const char **argv)
|
|
{
|
|
int i;
|
|
char *ep;
|
|
size_t varlen, vallen;
|
|
|
|
/*
|
|
* we can be invoked two ways:
|
|
* set var=value argv[1]="var", argv[2]="value"
|
|
* set var = value argv[1]="var", argv[2]="=", argv[3]="value"
|
|
* - if the latter, shift 'em down.
|
|
*/
|
|
if (argc == 3) {
|
|
argv[2] = argv[3];
|
|
argc--;
|
|
}
|
|
|
|
if (argc != 2)
|
|
return KDB_ARGCOUNT;
|
|
|
|
/*
|
|
* Check for internal variables
|
|
*/
|
|
if (strcmp(argv[1], "KDBDEBUG") == 0) {
|
|
unsigned int debugflags;
|
|
char *cp;
|
|
|
|
debugflags = simple_strtoul(argv[2], &cp, 0);
|
|
if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) {
|
|
kdb_printf("kdb: illegal debug flags '%s'\n",
|
|
argv[2]);
|
|
return 0;
|
|
}
|
|
kdb_flags = (kdb_flags &
|
|
~(KDB_DEBUG_FLAG_MASK << KDB_DEBUG_FLAG_SHIFT))
|
|
| (debugflags << KDB_DEBUG_FLAG_SHIFT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Tokenizer squashed the '=' sign. argv[1] is variable
|
|
* name, argv[2] = value.
|
|
*/
|
|
varlen = strlen(argv[1]);
|
|
vallen = strlen(argv[2]);
|
|
ep = kdballocenv(varlen + vallen + 2);
|
|
if (ep == (char *)0)
|
|
return KDB_ENVBUFFULL;
|
|
|
|
sprintf(ep, "%s=%s", argv[1], argv[2]);
|
|
|
|
ep[varlen+vallen+1] = '\0';
|
|
|
|
for (i = 0; i < __nenv; i++) {
|
|
if (__env[i]
|
|
&& ((strncmp(__env[i], argv[1], varlen) == 0)
|
|
&& ((__env[i][varlen] == '\0')
|
|
|| (__env[i][varlen] == '=')))) {
|
|
__env[i] = ep;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Wasn't existing variable. Fit into slot.
|
|
*/
|
|
for (i = 0; i < __nenv-1; i++) {
|
|
if (__env[i] == (char *)0) {
|
|
__env[i] = ep;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return KDB_ENVFULL;
|
|
}
|
|
|
|
static int kdb_check_regs(void)
|
|
{
|
|
if (!kdb_current_regs) {
|
|
kdb_printf("No current kdb registers."
|
|
" You may need to select another task\n");
|
|
return KDB_BADREG;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdbgetaddrarg - This function is responsible for parsing an
|
|
* address-expression and returning the value of the expression,
|
|
* symbol name, and offset to the caller.
|
|
*
|
|
* The argument may consist of a numeric value (decimal or
|
|
* hexidecimal), a symbol name, a register name (preceded by the
|
|
* percent sign), an environment variable with a numeric value
|
|
* (preceded by a dollar sign) or a simple arithmetic expression
|
|
* consisting of a symbol name, +/-, and a numeric constant value
|
|
* (offset).
|
|
* Parameters:
|
|
* argc - count of arguments in argv
|
|
* argv - argument vector
|
|
* *nextarg - index to next unparsed argument in argv[]
|
|
* regs - Register state at time of KDB entry
|
|
* Outputs:
|
|
* *value - receives the value of the address-expression
|
|
* *offset - receives the offset specified, if any
|
|
* *name - receives the symbol name, if any
|
|
* *nextarg - index to next unparsed argument in argv[]
|
|
* Returns:
|
|
* zero is returned on success, a kdb diagnostic code is
|
|
* returned on error.
|
|
*/
|
|
int kdbgetaddrarg(int argc, const char **argv, int *nextarg,
|
|
unsigned long *value, long *offset,
|
|
char **name)
|
|
{
|
|
unsigned long addr;
|
|
unsigned long off = 0;
|
|
int positive;
|
|
int diag;
|
|
int found = 0;
|
|
char *symname;
|
|
char symbol = '\0';
|
|
char *cp;
|
|
kdb_symtab_t symtab;
|
|
|
|
/*
|
|
* If the enable flags prohibit both arbitrary memory access
|
|
* and flow control then there are no reasonable grounds to
|
|
* provide symbol lookup.
|
|
*/
|
|
if (!kdb_check_flags(KDB_ENABLE_MEM_READ | KDB_ENABLE_FLOW_CTRL,
|
|
kdb_cmd_enabled, false))
|
|
return KDB_NOPERM;
|
|
|
|
/*
|
|
* Process arguments which follow the following syntax:
|
|
*
|
|
* symbol | numeric-address [+/- numeric-offset]
|
|
* %register
|
|
* $environment-variable
|
|
*/
|
|
|
|
if (*nextarg > argc)
|
|
return KDB_ARGCOUNT;
|
|
|
|
symname = (char *)argv[*nextarg];
|
|
|
|
/*
|
|
* If there is no whitespace between the symbol
|
|
* or address and the '+' or '-' symbols, we
|
|
* remember the character and replace it with a
|
|
* null so the symbol/value can be properly parsed
|
|
*/
|
|
cp = strpbrk(symname, "+-");
|
|
if (cp != NULL) {
|
|
symbol = *cp;
|
|
*cp++ = '\0';
|
|
}
|
|
|
|
if (symname[0] == '$') {
|
|
diag = kdbgetulenv(&symname[1], &addr);
|
|
if (diag)
|
|
return diag;
|
|
} else if (symname[0] == '%') {
|
|
diag = kdb_check_regs();
|
|
if (diag)
|
|
return diag;
|
|
/* Implement register values with % at a later time as it is
|
|
* arch optional.
|
|
*/
|
|
return KDB_NOTIMP;
|
|
} else {
|
|
found = kdbgetsymval(symname, &symtab);
|
|
if (found) {
|
|
addr = symtab.sym_start;
|
|
} else {
|
|
diag = kdbgetularg(argv[*nextarg], &addr);
|
|
if (diag)
|
|
return diag;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
found = kdbnearsym(addr, &symtab);
|
|
|
|
(*nextarg)++;
|
|
|
|
if (name)
|
|
*name = symname;
|
|
if (value)
|
|
*value = addr;
|
|
if (offset && name && *name)
|
|
*offset = addr - symtab.sym_start;
|
|
|
|
if ((*nextarg > argc)
|
|
&& (symbol == '\0'))
|
|
return 0;
|
|
|
|
/*
|
|
* check for +/- and offset
|
|
*/
|
|
|
|
if (symbol == '\0') {
|
|
if ((argv[*nextarg][0] != '+')
|
|
&& (argv[*nextarg][0] != '-')) {
|
|
/*
|
|
* Not our argument. Return.
|
|
*/
|
|
return 0;
|
|
} else {
|
|
positive = (argv[*nextarg][0] == '+');
|
|
(*nextarg)++;
|
|
}
|
|
} else
|
|
positive = (symbol == '+');
|
|
|
|
/*
|
|
* Now there must be an offset!
|
|
*/
|
|
if ((*nextarg > argc)
|
|
&& (symbol == '\0')) {
|
|
return KDB_INVADDRFMT;
|
|
}
|
|
|
|
if (!symbol) {
|
|
cp = (char *)argv[*nextarg];
|
|
(*nextarg)++;
|
|
}
|
|
|
|
diag = kdbgetularg(cp, &off);
|
|
if (diag)
|
|
return diag;
|
|
|
|
if (!positive)
|
|
off = -off;
|
|
|
|
if (offset)
|
|
*offset += off;
|
|
|
|
if (value)
|
|
*value += off;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void kdb_cmderror(int diag)
|
|
{
|
|
int i;
|
|
|
|
if (diag >= 0) {
|
|
kdb_printf("no error detected (diagnostic is %d)\n", diag);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < __nkdb_err; i++) {
|
|
if (kdbmsgs[i].km_diag == diag) {
|
|
kdb_printf("diag: %d: %s\n", diag, kdbmsgs[i].km_msg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
kdb_printf("Unknown diag %d\n", -diag);
|
|
}
|
|
|
|
/*
|
|
* kdb_defcmd, kdb_defcmd2 - This function implements the 'defcmd'
|
|
* command which defines one command as a set of other commands,
|
|
* terminated by endefcmd. kdb_defcmd processes the initial
|
|
* 'defcmd' command, kdb_defcmd2 is invoked from kdb_parse for
|
|
* the following commands until 'endefcmd'.
|
|
* Inputs:
|
|
* argc argument count
|
|
* argv argument vector
|
|
* Returns:
|
|
* zero for success, a kdb diagnostic if error
|
|
*/
|
|
struct defcmd_set {
|
|
int count;
|
|
int usable;
|
|
char *name;
|
|
char *usage;
|
|
char *help;
|
|
char **command;
|
|
};
|
|
static struct defcmd_set *defcmd_set;
|
|
static int defcmd_set_count;
|
|
static int defcmd_in_progress;
|
|
|
|
/* Forward references */
|
|
static int kdb_exec_defcmd(int argc, const char **argv);
|
|
|
|
static int kdb_defcmd2(const char *cmdstr, const char *argv0)
|
|
{
|
|
struct defcmd_set *s = defcmd_set + defcmd_set_count - 1;
|
|
char **save_command = s->command;
|
|
if (strcmp(argv0, "endefcmd") == 0) {
|
|
defcmd_in_progress = 0;
|
|
if (!s->count)
|
|
s->usable = 0;
|
|
if (s->usable)
|
|
/* macros are always safe because when executed each
|
|
* internal command re-enters kdb_parse() and is
|
|
* safety checked individually.
|
|
*/
|
|
kdb_register_flags(s->name, kdb_exec_defcmd, s->usage,
|
|
s->help, 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
return 0;
|
|
}
|
|
if (!s->usable)
|
|
return KDB_NOTIMP;
|
|
s->command = kcalloc(s->count + 1, sizeof(*(s->command)), GFP_KDB);
|
|
if (!s->command) {
|
|
kdb_printf("Could not allocate new kdb_defcmd table for %s\n",
|
|
cmdstr);
|
|
s->usable = 0;
|
|
return KDB_NOTIMP;
|
|
}
|
|
memcpy(s->command, save_command, s->count * sizeof(*(s->command)));
|
|
s->command[s->count++] = kdb_strdup(cmdstr, GFP_KDB);
|
|
kfree(save_command);
|
|
return 0;
|
|
}
|
|
|
|
static int kdb_defcmd(int argc, const char **argv)
|
|
{
|
|
struct defcmd_set *save_defcmd_set = defcmd_set, *s;
|
|
if (defcmd_in_progress) {
|
|
kdb_printf("kdb: nested defcmd detected, assuming missing "
|
|
"endefcmd\n");
|
|
kdb_defcmd2("endefcmd", "endefcmd");
|
|
}
|
|
if (argc == 0) {
|
|
int i;
|
|
for (s = defcmd_set; s < defcmd_set + defcmd_set_count; ++s) {
|
|
kdb_printf("defcmd %s \"%s\" \"%s\"\n", s->name,
|
|
s->usage, s->help);
|
|
for (i = 0; i < s->count; ++i)
|
|
kdb_printf("%s", s->command[i]);
|
|
kdb_printf("endefcmd\n");
|
|
}
|
|
return 0;
|
|
}
|
|
if (argc != 3)
|
|
return KDB_ARGCOUNT;
|
|
if (in_dbg_master()) {
|
|
kdb_printf("Command only available during kdb_init()\n");
|
|
return KDB_NOTIMP;
|
|
}
|
|
defcmd_set = kmalloc_array(defcmd_set_count + 1, sizeof(*defcmd_set),
|
|
GFP_KDB);
|
|
if (!defcmd_set)
|
|
goto fail_defcmd;
|
|
memcpy(defcmd_set, save_defcmd_set,
|
|
defcmd_set_count * sizeof(*defcmd_set));
|
|
s = defcmd_set + defcmd_set_count;
|
|
memset(s, 0, sizeof(*s));
|
|
s->usable = 1;
|
|
s->name = kdb_strdup(argv[1], GFP_KDB);
|
|
if (!s->name)
|
|
goto fail_name;
|
|
s->usage = kdb_strdup(argv[2], GFP_KDB);
|
|
if (!s->usage)
|
|
goto fail_usage;
|
|
s->help = kdb_strdup(argv[3], GFP_KDB);
|
|
if (!s->help)
|
|
goto fail_help;
|
|
if (s->usage[0] == '"') {
|
|
strcpy(s->usage, argv[2]+1);
|
|
s->usage[strlen(s->usage)-1] = '\0';
|
|
}
|
|
if (s->help[0] == '"') {
|
|
strcpy(s->help, argv[3]+1);
|
|
s->help[strlen(s->help)-1] = '\0';
|
|
}
|
|
++defcmd_set_count;
|
|
defcmd_in_progress = 1;
|
|
kfree(save_defcmd_set);
|
|
return 0;
|
|
fail_help:
|
|
kfree(s->usage);
|
|
fail_usage:
|
|
kfree(s->name);
|
|
fail_name:
|
|
kfree(defcmd_set);
|
|
fail_defcmd:
|
|
kdb_printf("Could not allocate new defcmd_set entry for %s\n", argv[1]);
|
|
defcmd_set = save_defcmd_set;
|
|
return KDB_NOTIMP;
|
|
}
|
|
|
|
/*
|
|
* kdb_exec_defcmd - Execute the set of commands associated with this
|
|
* defcmd name.
|
|
* Inputs:
|
|
* argc argument count
|
|
* argv argument vector
|
|
* Returns:
|
|
* zero for success, a kdb diagnostic if error
|
|
*/
|
|
static int kdb_exec_defcmd(int argc, const char **argv)
|
|
{
|
|
int i, ret;
|
|
struct defcmd_set *s;
|
|
if (argc != 0)
|
|
return KDB_ARGCOUNT;
|
|
for (s = defcmd_set, i = 0; i < defcmd_set_count; ++i, ++s) {
|
|
if (strcmp(s->name, argv[0]) == 0)
|
|
break;
|
|
}
|
|
if (i == defcmd_set_count) {
|
|
kdb_printf("kdb_exec_defcmd: could not find commands for %s\n",
|
|
argv[0]);
|
|
return KDB_NOTIMP;
|
|
}
|
|
for (i = 0; i < s->count; ++i) {
|
|
/* Recursive use of kdb_parse, do not use argv after
|
|
* this point */
|
|
argv = NULL;
|
|
kdb_printf("[%s]kdb> %s\n", s->name, s->command[i]);
|
|
ret = kdb_parse(s->command[i]);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Command history */
|
|
#define KDB_CMD_HISTORY_COUNT 32
|
|
#define CMD_BUFLEN 200 /* kdb_printf: max printline
|
|
* size == 256 */
|
|
static unsigned int cmd_head, cmd_tail;
|
|
static unsigned int cmdptr;
|
|
static char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN];
|
|
static char cmd_cur[CMD_BUFLEN];
|
|
|
|
/*
|
|
* The "str" argument may point to something like | grep xyz
|
|
*/
|
|
static void parse_grep(const char *str)
|
|
{
|
|
int len;
|
|
char *cp = (char *)str, *cp2;
|
|
|
|
/* sanity check: we should have been called with the \ first */
|
|
if (*cp != '|')
|
|
return;
|
|
cp++;
|
|
while (isspace(*cp))
|
|
cp++;
|
|
if (strncmp(cp, "grep ", 5)) {
|
|
kdb_printf("invalid 'pipe', see grephelp\n");
|
|
return;
|
|
}
|
|
cp += 5;
|
|
while (isspace(*cp))
|
|
cp++;
|
|
cp2 = strchr(cp, '\n');
|
|
if (cp2)
|
|
*cp2 = '\0'; /* remove the trailing newline */
|
|
len = strlen(cp);
|
|
if (len == 0) {
|
|
kdb_printf("invalid 'pipe', see grephelp\n");
|
|
return;
|
|
}
|
|
/* now cp points to a nonzero length search string */
|
|
if (*cp == '"') {
|
|
/* allow it be "x y z" by removing the "'s - there must
|
|
be two of them */
|
|
cp++;
|
|
cp2 = strchr(cp, '"');
|
|
if (!cp2) {
|
|
kdb_printf("invalid quoted string, see grephelp\n");
|
|
return;
|
|
}
|
|
*cp2 = '\0'; /* end the string where the 2nd " was */
|
|
}
|
|
kdb_grep_leading = 0;
|
|
if (*cp == '^') {
|
|
kdb_grep_leading = 1;
|
|
cp++;
|
|
}
|
|
len = strlen(cp);
|
|
kdb_grep_trailing = 0;
|
|
if (*(cp+len-1) == '$') {
|
|
kdb_grep_trailing = 1;
|
|
*(cp+len-1) = '\0';
|
|
}
|
|
len = strlen(cp);
|
|
if (!len)
|
|
return;
|
|
if (len >= KDB_GREP_STRLEN) {
|
|
kdb_printf("search string too long\n");
|
|
return;
|
|
}
|
|
strcpy(kdb_grep_string, cp);
|
|
kdb_grepping_flag++;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* kdb_parse - Parse the command line, search the command table for a
|
|
* matching command and invoke the command function. This
|
|
* function may be called recursively, if it is, the second call
|
|
* will overwrite argv and cbuf. It is the caller's
|
|
* responsibility to save their argv if they recursively call
|
|
* kdb_parse().
|
|
* Parameters:
|
|
* cmdstr The input command line to be parsed.
|
|
* regs The registers at the time kdb was entered.
|
|
* Returns:
|
|
* Zero for success, a kdb diagnostic if failure.
|
|
* Remarks:
|
|
* Limited to 20 tokens.
|
|
*
|
|
* Real rudimentary tokenization. Basically only whitespace
|
|
* is considered a token delimeter (but special consideration
|
|
* is taken of the '=' sign as used by the 'set' command).
|
|
*
|
|
* The algorithm used to tokenize the input string relies on
|
|
* there being at least one whitespace (or otherwise useless)
|
|
* character between tokens as the character immediately following
|
|
* the token is altered in-place to a null-byte to terminate the
|
|
* token string.
|
|
*/
|
|
|
|
#define MAXARGC 20
|
|
|
|
int kdb_parse(const char *cmdstr)
|
|
{
|
|
static char *argv[MAXARGC];
|
|
static int argc;
|
|
static char cbuf[CMD_BUFLEN+2];
|
|
char *cp;
|
|
char *cpp, quoted;
|
|
kdbtab_t *tp;
|
|
int i, escaped, ignore_errors = 0, check_grep = 0;
|
|
|
|
/*
|
|
* First tokenize the command string.
|
|
*/
|
|
cp = (char *)cmdstr;
|
|
|
|
if (KDB_FLAG(CMD_INTERRUPT)) {
|
|
/* Previous command was interrupted, newline must not
|
|
* repeat the command */
|
|
KDB_FLAG_CLEAR(CMD_INTERRUPT);
|
|
KDB_STATE_SET(PAGER);
|
|
argc = 0; /* no repeat */
|
|
}
|
|
|
|
if (*cp != '\n' && *cp != '\0') {
|
|
argc = 0;
|
|
cpp = cbuf;
|
|
while (*cp) {
|
|
/* skip whitespace */
|
|
while (isspace(*cp))
|
|
cp++;
|
|
if ((*cp == '\0') || (*cp == '\n') ||
|
|
(*cp == '#' && !defcmd_in_progress))
|
|
break;
|
|
/* special case: check for | grep pattern */
|
|
if (*cp == '|') {
|
|
check_grep++;
|
|
break;
|
|
}
|
|
if (cpp >= cbuf + CMD_BUFLEN) {
|
|
kdb_printf("kdb_parse: command buffer "
|
|
"overflow, command ignored\n%s\n",
|
|
cmdstr);
|
|
return KDB_NOTFOUND;
|
|
}
|
|
if (argc >= MAXARGC - 1) {
|
|
kdb_printf("kdb_parse: too many arguments, "
|
|
"command ignored\n%s\n", cmdstr);
|
|
return KDB_NOTFOUND;
|
|
}
|
|
argv[argc++] = cpp;
|
|
escaped = 0;
|
|
quoted = '\0';
|
|
/* Copy to next unquoted and unescaped
|
|
* whitespace or '=' */
|
|
while (*cp && *cp != '\n' &&
|
|
(escaped || quoted || !isspace(*cp))) {
|
|
if (cpp >= cbuf + CMD_BUFLEN)
|
|
break;
|
|
if (escaped) {
|
|
escaped = 0;
|
|
*cpp++ = *cp++;
|
|
continue;
|
|
}
|
|
if (*cp == '\\') {
|
|
escaped = 1;
|
|
++cp;
|
|
continue;
|
|
}
|
|
if (*cp == quoted)
|
|
quoted = '\0';
|
|
else if (*cp == '\'' || *cp == '"')
|
|
quoted = *cp;
|
|
*cpp = *cp++;
|
|
if (*cpp == '=' && !quoted)
|
|
break;
|
|
++cpp;
|
|
}
|
|
*cpp++ = '\0'; /* Squash a ws or '=' character */
|
|
}
|
|
}
|
|
if (!argc)
|
|
return 0;
|
|
if (check_grep)
|
|
parse_grep(cp);
|
|
if (defcmd_in_progress) {
|
|
int result = kdb_defcmd2(cmdstr, argv[0]);
|
|
if (!defcmd_in_progress) {
|
|
argc = 0; /* avoid repeat on endefcmd */
|
|
*(argv[0]) = '\0';
|
|
}
|
|
return result;
|
|
}
|
|
if (argv[0][0] == '-' && argv[0][1] &&
|
|
(argv[0][1] < '0' || argv[0][1] > '9')) {
|
|
ignore_errors = 1;
|
|
++argv[0];
|
|
}
|
|
|
|
for_each_kdbcmd(tp, i) {
|
|
if (tp->cmd_name) {
|
|
/*
|
|
* If this command is allowed to be abbreviated,
|
|
* check to see if this is it.
|
|
*/
|
|
|
|
if (tp->cmd_minlen
|
|
&& (strlen(argv[0]) <= tp->cmd_minlen)) {
|
|
if (strncmp(argv[0],
|
|
tp->cmd_name,
|
|
tp->cmd_minlen) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (strcmp(argv[0], tp->cmd_name) == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we don't find a command by this name, see if the first
|
|
* few characters of this match any of the known commands.
|
|
* e.g., md1c20 should match md.
|
|
*/
|
|
if (i == kdb_max_commands) {
|
|
for_each_kdbcmd(tp, i) {
|
|
if (tp->cmd_name) {
|
|
if (strncmp(argv[0],
|
|
tp->cmd_name,
|
|
strlen(tp->cmd_name)) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i < kdb_max_commands) {
|
|
int result;
|
|
|
|
if (!kdb_check_flags(tp->cmd_flags, kdb_cmd_enabled, argc <= 1))
|
|
return KDB_NOPERM;
|
|
|
|
KDB_STATE_SET(CMD);
|
|
result = (*tp->cmd_func)(argc-1, (const char **)argv);
|
|
if (result && ignore_errors && result > KDB_CMD_GO)
|
|
result = 0;
|
|
KDB_STATE_CLEAR(CMD);
|
|
|
|
if (tp->cmd_flags & KDB_REPEAT_WITH_ARGS)
|
|
return result;
|
|
|
|
argc = tp->cmd_flags & KDB_REPEAT_NO_ARGS ? 1 : 0;
|
|
if (argv[argc])
|
|
*(argv[argc]) = '\0';
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* If the input with which we were presented does not
|
|
* map to an existing command, attempt to parse it as an
|
|
* address argument and display the result. Useful for
|
|
* obtaining the address of a variable, or the nearest symbol
|
|
* to an address contained in a register.
|
|
*/
|
|
{
|
|
unsigned long value;
|
|
char *name = NULL;
|
|
long offset;
|
|
int nextarg = 0;
|
|
|
|
if (kdbgetaddrarg(0, (const char **)argv, &nextarg,
|
|
&value, &offset, &name)) {
|
|
return KDB_NOTFOUND;
|
|
}
|
|
|
|
kdb_printf("%s = ", argv[0]);
|
|
kdb_symbol_print(value, NULL, KDB_SP_DEFAULT);
|
|
kdb_printf("\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int handle_ctrl_cmd(char *cmd)
|
|
{
|
|
#define CTRL_P 16
|
|
#define CTRL_N 14
|
|
|
|
/* initial situation */
|
|
if (cmd_head == cmd_tail)
|
|
return 0;
|
|
switch (*cmd) {
|
|
case CTRL_P:
|
|
if (cmdptr != cmd_tail)
|
|
cmdptr = (cmdptr-1) % KDB_CMD_HISTORY_COUNT;
|
|
strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN);
|
|
return 1;
|
|
case CTRL_N:
|
|
if (cmdptr != cmd_head)
|
|
cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT;
|
|
strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_reboot - This function implements the 'reboot' command. Reboot
|
|
* the system immediately, or loop for ever on failure.
|
|
*/
|
|
static int kdb_reboot(int argc, const char **argv)
|
|
{
|
|
emergency_restart();
|
|
kdb_printf("Hmm, kdb_reboot did not reboot, spinning here\n");
|
|
while (1)
|
|
cpu_relax();
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
static void kdb_dumpregs(struct pt_regs *regs)
|
|
{
|
|
int old_lvl = console_loglevel;
|
|
console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
|
|
kdb_trap_printk++;
|
|
show_regs(regs);
|
|
kdb_trap_printk--;
|
|
kdb_printf("\n");
|
|
console_loglevel = old_lvl;
|
|
}
|
|
|
|
void kdb_set_current_task(struct task_struct *p)
|
|
{
|
|
kdb_current_task = p;
|
|
|
|
if (kdb_task_has_cpu(p)) {
|
|
kdb_current_regs = KDB_TSKREGS(kdb_process_cpu(p));
|
|
return;
|
|
}
|
|
kdb_current_regs = NULL;
|
|
}
|
|
|
|
static void drop_newline(char *buf)
|
|
{
|
|
size_t len = strlen(buf);
|
|
|
|
if (len == 0)
|
|
return;
|
|
if (*(buf + len - 1) == '\n')
|
|
*(buf + len - 1) = '\0';
|
|
}
|
|
|
|
/*
|
|
* kdb_local - The main code for kdb. This routine is invoked on a
|
|
* specific processor, it is not global. The main kdb() routine
|
|
* ensures that only one processor at a time is in this routine.
|
|
* This code is called with the real reason code on the first
|
|
* entry to a kdb session, thereafter it is called with reason
|
|
* SWITCH, even if the user goes back to the original cpu.
|
|
* Inputs:
|
|
* reason The reason KDB was invoked
|
|
* error The hardware-defined error code
|
|
* regs The exception frame at time of fault/breakpoint.
|
|
* db_result Result code from the break or debug point.
|
|
* Returns:
|
|
* 0 KDB was invoked for an event which it wasn't responsible
|
|
* 1 KDB handled the event for which it was invoked.
|
|
* KDB_CMD_GO User typed 'go'.
|
|
* KDB_CMD_CPU User switched to another cpu.
|
|
* KDB_CMD_SS Single step.
|
|
*/
|
|
static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
|
|
kdb_dbtrap_t db_result)
|
|
{
|
|
char *cmdbuf;
|
|
int diag;
|
|
struct task_struct *kdb_current =
|
|
kdb_curr_task(raw_smp_processor_id());
|
|
|
|
KDB_DEBUG_STATE("kdb_local 1", reason);
|
|
kdb_go_count = 0;
|
|
if (reason == KDB_REASON_DEBUG) {
|
|
/* special case below */
|
|
} else {
|
|
kdb_printf("\nEntering kdb (current=0x%px, pid %d) ",
|
|
kdb_current, kdb_current ? kdb_current->pid : 0);
|
|
#if defined(CONFIG_SMP)
|
|
kdb_printf("on processor %d ", raw_smp_processor_id());
|
|
#endif
|
|
}
|
|
|
|
switch (reason) {
|
|
case KDB_REASON_DEBUG:
|
|
{
|
|
/*
|
|
* If re-entering kdb after a single step
|
|
* command, don't print the message.
|
|
*/
|
|
switch (db_result) {
|
|
case KDB_DB_BPT:
|
|
kdb_printf("\nEntering kdb (0x%px, pid %d) ",
|
|
kdb_current, kdb_current->pid);
|
|
#if defined(CONFIG_SMP)
|
|
kdb_printf("on processor %d ", raw_smp_processor_id());
|
|
#endif
|
|
kdb_printf("due to Debug @ " kdb_machreg_fmt "\n",
|
|
instruction_pointer(regs));
|
|
break;
|
|
case KDB_DB_SS:
|
|
break;
|
|
case KDB_DB_SSBPT:
|
|
KDB_DEBUG_STATE("kdb_local 4", reason);
|
|
return 1; /* kdba_db_trap did the work */
|
|
default:
|
|
kdb_printf("kdb: Bad result from kdba_db_trap: %d\n",
|
|
db_result);
|
|
break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case KDB_REASON_ENTER:
|
|
if (KDB_STATE(KEYBOARD))
|
|
kdb_printf("due to Keyboard Entry\n");
|
|
else
|
|
kdb_printf("due to KDB_ENTER()\n");
|
|
break;
|
|
case KDB_REASON_KEYBOARD:
|
|
KDB_STATE_SET(KEYBOARD);
|
|
kdb_printf("due to Keyboard Entry\n");
|
|
break;
|
|
case KDB_REASON_ENTER_SLAVE:
|
|
/* drop through, slaves only get released via cpu switch */
|
|
case KDB_REASON_SWITCH:
|
|
kdb_printf("due to cpu switch\n");
|
|
break;
|
|
case KDB_REASON_OOPS:
|
|
kdb_printf("Oops: %s\n", kdb_diemsg);
|
|
kdb_printf("due to oops @ " kdb_machreg_fmt "\n",
|
|
instruction_pointer(regs));
|
|
kdb_dumpregs(regs);
|
|
break;
|
|
case KDB_REASON_SYSTEM_NMI:
|
|
kdb_printf("due to System NonMaskable Interrupt\n");
|
|
break;
|
|
case KDB_REASON_NMI:
|
|
kdb_printf("due to NonMaskable Interrupt @ "
|
|
kdb_machreg_fmt "\n",
|
|
instruction_pointer(regs));
|
|
break;
|
|
case KDB_REASON_SSTEP:
|
|
case KDB_REASON_BREAK:
|
|
kdb_printf("due to %s @ " kdb_machreg_fmt "\n",
|
|
reason == KDB_REASON_BREAK ?
|
|
"Breakpoint" : "SS trap", instruction_pointer(regs));
|
|
/*
|
|
* Determine if this breakpoint is one that we
|
|
* are interested in.
|
|
*/
|
|
if (db_result != KDB_DB_BPT) {
|
|
kdb_printf("kdb: error return from kdba_bp_trap: %d\n",
|
|
db_result);
|
|
KDB_DEBUG_STATE("kdb_local 6", reason);
|
|
return 0; /* Not for us, dismiss it */
|
|
}
|
|
break;
|
|
case KDB_REASON_RECURSE:
|
|
kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n",
|
|
instruction_pointer(regs));
|
|
break;
|
|
default:
|
|
kdb_printf("kdb: unexpected reason code: %d\n", reason);
|
|
KDB_DEBUG_STATE("kdb_local 8", reason);
|
|
return 0; /* Not for us, dismiss it */
|
|
}
|
|
|
|
while (1) {
|
|
/*
|
|
* Initialize pager context.
|
|
*/
|
|
kdb_nextline = 1;
|
|
KDB_STATE_CLEAR(SUPPRESS);
|
|
kdb_grepping_flag = 0;
|
|
/* ensure the old search does not leak into '/' commands */
|
|
kdb_grep_string[0] = '\0';
|
|
|
|
cmdbuf = cmd_cur;
|
|
*cmdbuf = '\0';
|
|
*(cmd_hist[cmd_head]) = '\0';
|
|
|
|
do_full_getstr:
|
|
#if defined(CONFIG_SMP)
|
|
snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
|
|
raw_smp_processor_id());
|
|
#else
|
|
snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"));
|
|
#endif
|
|
if (defcmd_in_progress)
|
|
strncat(kdb_prompt_str, "[defcmd]", CMD_BUFLEN);
|
|
|
|
/*
|
|
* Fetch command from keyboard
|
|
*/
|
|
cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, kdb_prompt_str);
|
|
if (*cmdbuf != '\n') {
|
|
if (*cmdbuf < 32) {
|
|
if (cmdptr == cmd_head) {
|
|
strncpy(cmd_hist[cmd_head], cmd_cur,
|
|
CMD_BUFLEN);
|
|
*(cmd_hist[cmd_head] +
|
|
strlen(cmd_hist[cmd_head])-1) = '\0';
|
|
}
|
|
if (!handle_ctrl_cmd(cmdbuf))
|
|
*(cmd_cur+strlen(cmd_cur)-1) = '\0';
|
|
cmdbuf = cmd_cur;
|
|
goto do_full_getstr;
|
|
} else {
|
|
strncpy(cmd_hist[cmd_head], cmd_cur,
|
|
CMD_BUFLEN);
|
|
}
|
|
|
|
cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT;
|
|
if (cmd_head == cmd_tail)
|
|
cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT;
|
|
}
|
|
|
|
cmdptr = cmd_head;
|
|
diag = kdb_parse(cmdbuf);
|
|
if (diag == KDB_NOTFOUND) {
|
|
drop_newline(cmdbuf);
|
|
kdb_printf("Unknown kdb command: '%s'\n", cmdbuf);
|
|
diag = 0;
|
|
}
|
|
if (diag == KDB_CMD_GO
|
|
|| diag == KDB_CMD_CPU
|
|
|| diag == KDB_CMD_SS
|
|
|| diag == KDB_CMD_KGDB)
|
|
break;
|
|
|
|
if (diag)
|
|
kdb_cmderror(diag);
|
|
}
|
|
KDB_DEBUG_STATE("kdb_local 9", diag);
|
|
return diag;
|
|
}
|
|
|
|
|
|
/*
|
|
* kdb_print_state - Print the state data for the current processor
|
|
* for debugging.
|
|
* Inputs:
|
|
* text Identifies the debug point
|
|
* value Any integer value to be printed, e.g. reason code.
|
|
*/
|
|
void kdb_print_state(const char *text, int value)
|
|
{
|
|
kdb_printf("state: %s cpu %d value %d initial %d state %x\n",
|
|
text, raw_smp_processor_id(), value, kdb_initial_cpu,
|
|
kdb_state);
|
|
}
|
|
|
|
/*
|
|
* kdb_main_loop - After initial setup and assignment of the
|
|
* controlling cpu, all cpus are in this loop. One cpu is in
|
|
* control and will issue the kdb prompt, the others will spin
|
|
* until 'go' or cpu switch.
|
|
*
|
|
* To get a consistent view of the kernel stacks for all
|
|
* processes, this routine is invoked from the main kdb code via
|
|
* an architecture specific routine. kdba_main_loop is
|
|
* responsible for making the kernel stacks consistent for all
|
|
* processes, there should be no difference between a blocked
|
|
* process and a running process as far as kdb is concerned.
|
|
* Inputs:
|
|
* reason The reason KDB was invoked
|
|
* error The hardware-defined error code
|
|
* reason2 kdb's current reason code.
|
|
* Initially error but can change
|
|
* according to kdb state.
|
|
* db_result Result code from break or debug point.
|
|
* regs The exception frame at time of fault/breakpoint.
|
|
* should always be valid.
|
|
* Returns:
|
|
* 0 KDB was invoked for an event which it wasn't responsible
|
|
* 1 KDB handled the event for which it was invoked.
|
|
*/
|
|
int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
|
|
kdb_dbtrap_t db_result, struct pt_regs *regs)
|
|
{
|
|
int result = 1;
|
|
/* Stay in kdb() until 'go', 'ss[b]' or an error */
|
|
while (1) {
|
|
/*
|
|
* All processors except the one that is in control
|
|
* will spin here.
|
|
*/
|
|
KDB_DEBUG_STATE("kdb_main_loop 1", reason);
|
|
while (KDB_STATE(HOLD_CPU)) {
|
|
/* state KDB is turned off by kdb_cpu to see if the
|
|
* other cpus are still live, each cpu in this loop
|
|
* turns it back on.
|
|
*/
|
|
if (!KDB_STATE(KDB))
|
|
KDB_STATE_SET(KDB);
|
|
}
|
|
|
|
KDB_STATE_CLEAR(SUPPRESS);
|
|
KDB_DEBUG_STATE("kdb_main_loop 2", reason);
|
|
if (KDB_STATE(LEAVING))
|
|
break; /* Another cpu said 'go' */
|
|
/* Still using kdb, this processor is in control */
|
|
result = kdb_local(reason2, error, regs, db_result);
|
|
KDB_DEBUG_STATE("kdb_main_loop 3", result);
|
|
|
|
if (result == KDB_CMD_CPU)
|
|
break;
|
|
|
|
if (result == KDB_CMD_SS) {
|
|
KDB_STATE_SET(DOING_SS);
|
|
break;
|
|
}
|
|
|
|
if (result == KDB_CMD_KGDB) {
|
|
if (!KDB_STATE(DOING_KGDB))
|
|
kdb_printf("Entering please attach debugger "
|
|
"or use $D#44+ or $3#33\n");
|
|
break;
|
|
}
|
|
if (result && result != 1 && result != KDB_CMD_GO)
|
|
kdb_printf("\nUnexpected kdb_local return code %d\n",
|
|
result);
|
|
KDB_DEBUG_STATE("kdb_main_loop 4", reason);
|
|
break;
|
|
}
|
|
if (KDB_STATE(DOING_SS))
|
|
KDB_STATE_CLEAR(SSBPT);
|
|
|
|
/* Clean up any keyboard devices before leaving */
|
|
kdb_kbd_cleanup_state();
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* kdb_mdr - This function implements the guts of the 'mdr', memory
|
|
* read command.
|
|
* mdr <addr arg>,<byte count>
|
|
* Inputs:
|
|
* addr Start address
|
|
* count Number of bytes
|
|
* Returns:
|
|
* Always 0. Any errors are detected and printed by kdb_getarea.
|
|
*/
|
|
static int kdb_mdr(unsigned long addr, unsigned int count)
|
|
{
|
|
unsigned char c;
|
|
while (count--) {
|
|
if (kdb_getarea(c, addr))
|
|
return 0;
|
|
kdb_printf("%02x", c);
|
|
addr++;
|
|
}
|
|
kdb_printf("\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_md - This function implements the 'md', 'md1', 'md2', 'md4',
|
|
* 'md8' 'mdr' and 'mds' commands.
|
|
*
|
|
* md|mds [<addr arg> [<line count> [<radix>]]]
|
|
* mdWcN [<addr arg> [<line count> [<radix>]]]
|
|
* where W = is the width (1, 2, 4 or 8) and N is the count.
|
|
* for eg., md1c20 reads 20 bytes, 1 at a time.
|
|
* mdr <addr arg>,<byte count>
|
|
*/
|
|
static void kdb_md_line(const char *fmtstr, unsigned long addr,
|
|
int symbolic, int nosect, int bytesperword,
|
|
int num, int repeat, int phys)
|
|
{
|
|
/* print just one line of data */
|
|
kdb_symtab_t symtab;
|
|
char cbuf[32];
|
|
char *c = cbuf;
|
|
int i;
|
|
unsigned long word;
|
|
|
|
memset(cbuf, '\0', sizeof(cbuf));
|
|
if (phys)
|
|
kdb_printf("phys " kdb_machreg_fmt0 " ", addr);
|
|
else
|
|
kdb_printf(kdb_machreg_fmt0 " ", addr);
|
|
|
|
for (i = 0; i < num && repeat--; i++) {
|
|
if (phys) {
|
|
if (kdb_getphysword(&word, addr, bytesperword))
|
|
break;
|
|
} else if (kdb_getword(&word, addr, bytesperword))
|
|
break;
|
|
kdb_printf(fmtstr, word);
|
|
if (symbolic)
|
|
kdbnearsym(word, &symtab);
|
|
else
|
|
memset(&symtab, 0, sizeof(symtab));
|
|
if (symtab.sym_name) {
|
|
kdb_symbol_print(word, &symtab, 0);
|
|
if (!nosect) {
|
|
kdb_printf("\n");
|
|
kdb_printf(" %s %s "
|
|
kdb_machreg_fmt " "
|
|
kdb_machreg_fmt " "
|
|
kdb_machreg_fmt, symtab.mod_name,
|
|
symtab.sec_name, symtab.sec_start,
|
|
symtab.sym_start, symtab.sym_end);
|
|
}
|
|
addr += bytesperword;
|
|
} else {
|
|
union {
|
|
u64 word;
|
|
unsigned char c[8];
|
|
} wc;
|
|
unsigned char *cp;
|
|
#ifdef __BIG_ENDIAN
|
|
cp = wc.c + 8 - bytesperword;
|
|
#else
|
|
cp = wc.c;
|
|
#endif
|
|
wc.word = word;
|
|
#define printable_char(c) \
|
|
({unsigned char __c = c; isascii(__c) && isprint(__c) ? __c : '.'; })
|
|
switch (bytesperword) {
|
|
case 8:
|
|
*c++ = printable_char(*cp++);
|
|
*c++ = printable_char(*cp++);
|
|
*c++ = printable_char(*cp++);
|
|
*c++ = printable_char(*cp++);
|
|
addr += 4;
|
|
case 4:
|
|
*c++ = printable_char(*cp++);
|
|
*c++ = printable_char(*cp++);
|
|
addr += 2;
|
|
case 2:
|
|
*c++ = printable_char(*cp++);
|
|
addr++;
|
|
case 1:
|
|
*c++ = printable_char(*cp++);
|
|
addr++;
|
|
break;
|
|
}
|
|
#undef printable_char
|
|
}
|
|
}
|
|
kdb_printf("%*s %s\n", (int)((num-i)*(2*bytesperword + 1)+1),
|
|
" ", cbuf);
|
|
}
|
|
|
|
static int kdb_md(int argc, const char **argv)
|
|
{
|
|
static unsigned long last_addr;
|
|
static int last_radix, last_bytesperword, last_repeat;
|
|
int radix = 16, mdcount = 8, bytesperword = KDB_WORD_SIZE, repeat;
|
|
int nosect = 0;
|
|
char fmtchar, fmtstr[64];
|
|
unsigned long addr;
|
|
unsigned long word;
|
|
long offset = 0;
|
|
int symbolic = 0;
|
|
int valid = 0;
|
|
int phys = 0;
|
|
int raw = 0;
|
|
|
|
kdbgetintenv("MDCOUNT", &mdcount);
|
|
kdbgetintenv("RADIX", &radix);
|
|
kdbgetintenv("BYTESPERWORD", &bytesperword);
|
|
|
|
/* Assume 'md <addr>' and start with environment values */
|
|
repeat = mdcount * 16 / bytesperword;
|
|
|
|
if (strcmp(argv[0], "mdr") == 0) {
|
|
if (argc == 2 || (argc == 0 && last_addr != 0))
|
|
valid = raw = 1;
|
|
else
|
|
return KDB_ARGCOUNT;
|
|
} else if (isdigit(argv[0][2])) {
|
|
bytesperword = (int)(argv[0][2] - '0');
|
|
if (bytesperword == 0) {
|
|
bytesperword = last_bytesperword;
|
|
if (bytesperword == 0)
|
|
bytesperword = 4;
|
|
}
|
|
last_bytesperword = bytesperword;
|
|
repeat = mdcount * 16 / bytesperword;
|
|
if (!argv[0][3])
|
|
valid = 1;
|
|
else if (argv[0][3] == 'c' && argv[0][4]) {
|
|
char *p;
|
|
repeat = simple_strtoul(argv[0] + 4, &p, 10);
|
|
mdcount = ((repeat * bytesperword) + 15) / 16;
|
|
valid = !*p;
|
|
}
|
|
last_repeat = repeat;
|
|
} else if (strcmp(argv[0], "md") == 0)
|
|
valid = 1;
|
|
else if (strcmp(argv[0], "mds") == 0)
|
|
valid = 1;
|
|
else if (strcmp(argv[0], "mdp") == 0) {
|
|
phys = valid = 1;
|
|
}
|
|
if (!valid)
|
|
return KDB_NOTFOUND;
|
|
|
|
if (argc == 0) {
|
|
if (last_addr == 0)
|
|
return KDB_ARGCOUNT;
|
|
addr = last_addr;
|
|
radix = last_radix;
|
|
bytesperword = last_bytesperword;
|
|
repeat = last_repeat;
|
|
if (raw)
|
|
mdcount = repeat;
|
|
else
|
|
mdcount = ((repeat * bytesperword) + 15) / 16;
|
|
}
|
|
|
|
if (argc) {
|
|
unsigned long val;
|
|
int diag, nextarg = 1;
|
|
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr,
|
|
&offset, NULL);
|
|
if (diag)
|
|
return diag;
|
|
if (argc > nextarg+2)
|
|
return KDB_ARGCOUNT;
|
|
|
|
if (argc >= nextarg) {
|
|
diag = kdbgetularg(argv[nextarg], &val);
|
|
if (!diag) {
|
|
mdcount = (int) val;
|
|
if (raw)
|
|
repeat = mdcount;
|
|
else
|
|
repeat = mdcount * 16 / bytesperword;
|
|
}
|
|
}
|
|
if (argc >= nextarg+1) {
|
|
diag = kdbgetularg(argv[nextarg+1], &val);
|
|
if (!diag)
|
|
radix = (int) val;
|
|
}
|
|
}
|
|
|
|
if (strcmp(argv[0], "mdr") == 0) {
|
|
int ret;
|
|
last_addr = addr;
|
|
ret = kdb_mdr(addr, mdcount);
|
|
last_addr += mdcount;
|
|
last_repeat = mdcount;
|
|
last_bytesperword = bytesperword; // to make REPEAT happy
|
|
return ret;
|
|
}
|
|
|
|
switch (radix) {
|
|
case 10:
|
|
fmtchar = 'd';
|
|
break;
|
|
case 16:
|
|
fmtchar = 'x';
|
|
break;
|
|
case 8:
|
|
fmtchar = 'o';
|
|
break;
|
|
default:
|
|
return KDB_BADRADIX;
|
|
}
|
|
|
|
last_radix = radix;
|
|
|
|
if (bytesperword > KDB_WORD_SIZE)
|
|
return KDB_BADWIDTH;
|
|
|
|
switch (bytesperword) {
|
|
case 8:
|
|
sprintf(fmtstr, "%%16.16l%c ", fmtchar);
|
|
break;
|
|
case 4:
|
|
sprintf(fmtstr, "%%8.8l%c ", fmtchar);
|
|
break;
|
|
case 2:
|
|
sprintf(fmtstr, "%%4.4l%c ", fmtchar);
|
|
break;
|
|
case 1:
|
|
sprintf(fmtstr, "%%2.2l%c ", fmtchar);
|
|
break;
|
|
default:
|
|
return KDB_BADWIDTH;
|
|
}
|
|
|
|
last_repeat = repeat;
|
|
last_bytesperword = bytesperword;
|
|
|
|
if (strcmp(argv[0], "mds") == 0) {
|
|
symbolic = 1;
|
|
/* Do not save these changes as last_*, they are temporary mds
|
|
* overrides.
|
|
*/
|
|
bytesperword = KDB_WORD_SIZE;
|
|
repeat = mdcount;
|
|
kdbgetintenv("NOSECT", &nosect);
|
|
}
|
|
|
|
/* Round address down modulo BYTESPERWORD */
|
|
|
|
addr &= ~(bytesperword-1);
|
|
|
|
while (repeat > 0) {
|
|
unsigned long a;
|
|
int n, z, num = (symbolic ? 1 : (16 / bytesperword));
|
|
|
|
if (KDB_FLAG(CMD_INTERRUPT))
|
|
return 0;
|
|
for (a = addr, z = 0; z < repeat; a += bytesperword, ++z) {
|
|
if (phys) {
|
|
if (kdb_getphysword(&word, a, bytesperword)
|
|
|| word)
|
|
break;
|
|
} else if (kdb_getword(&word, a, bytesperword) || word)
|
|
break;
|
|
}
|
|
n = min(num, repeat);
|
|
kdb_md_line(fmtstr, addr, symbolic, nosect, bytesperword,
|
|
num, repeat, phys);
|
|
addr += bytesperword * n;
|
|
repeat -= n;
|
|
z = (z + num - 1) / num;
|
|
if (z > 2) {
|
|
int s = num * (z-2);
|
|
kdb_printf(kdb_machreg_fmt0 "-" kdb_machreg_fmt0
|
|
" zero suppressed\n",
|
|
addr, addr + bytesperword * s - 1);
|
|
addr += bytesperword * s;
|
|
repeat -= s;
|
|
}
|
|
}
|
|
last_addr = addr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_mm - This function implements the 'mm' command.
|
|
* mm address-expression new-value
|
|
* Remarks:
|
|
* mm works on machine words, mmW works on bytes.
|
|
*/
|
|
static int kdb_mm(int argc, const char **argv)
|
|
{
|
|
int diag;
|
|
unsigned long addr;
|
|
long offset = 0;
|
|
unsigned long contents;
|
|
int nextarg;
|
|
int width;
|
|
|
|
if (argv[0][2] && !isdigit(argv[0][2]))
|
|
return KDB_NOTFOUND;
|
|
|
|
if (argc < 2)
|
|
return KDB_ARGCOUNT;
|
|
|
|
nextarg = 1;
|
|
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL);
|
|
if (diag)
|
|
return diag;
|
|
|
|
if (nextarg > argc)
|
|
return KDB_ARGCOUNT;
|
|
diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL);
|
|
if (diag)
|
|
return diag;
|
|
|
|
if (nextarg != argc + 1)
|
|
return KDB_ARGCOUNT;
|
|
|
|
width = argv[0][2] ? (argv[0][2] - '0') : (KDB_WORD_SIZE);
|
|
diag = kdb_putword(addr, contents, width);
|
|
if (diag)
|
|
return diag;
|
|
|
|
kdb_printf(kdb_machreg_fmt " = " kdb_machreg_fmt "\n", addr, contents);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_go - This function implements the 'go' command.
|
|
* go [address-expression]
|
|
*/
|
|
static int kdb_go(int argc, const char **argv)
|
|
{
|
|
unsigned long addr;
|
|
int diag;
|
|
int nextarg;
|
|
long offset;
|
|
|
|
if (raw_smp_processor_id() != kdb_initial_cpu) {
|
|
kdb_printf("go must execute on the entry cpu, "
|
|
"please use \"cpu %d\" and then execute go\n",
|
|
kdb_initial_cpu);
|
|
return KDB_BADCPUNUM;
|
|
}
|
|
if (argc == 1) {
|
|
nextarg = 1;
|
|
diag = kdbgetaddrarg(argc, argv, &nextarg,
|
|
&addr, &offset, NULL);
|
|
if (diag)
|
|
return diag;
|
|
} else if (argc) {
|
|
return KDB_ARGCOUNT;
|
|
}
|
|
|
|
diag = KDB_CMD_GO;
|
|
if (KDB_FLAG(CATASTROPHIC)) {
|
|
kdb_printf("Catastrophic error detected\n");
|
|
kdb_printf("kdb_continue_catastrophic=%d, ",
|
|
kdb_continue_catastrophic);
|
|
if (kdb_continue_catastrophic == 0 && kdb_go_count++ == 0) {
|
|
kdb_printf("type go a second time if you really want "
|
|
"to continue\n");
|
|
return 0;
|
|
}
|
|
if (kdb_continue_catastrophic == 2) {
|
|
kdb_printf("forcing reboot\n");
|
|
kdb_reboot(0, NULL);
|
|
}
|
|
kdb_printf("attempting to continue\n");
|
|
}
|
|
return diag;
|
|
}
|
|
|
|
/*
|
|
* kdb_rd - This function implements the 'rd' command.
|
|
*/
|
|
static int kdb_rd(int argc, const char **argv)
|
|
{
|
|
int len = kdb_check_regs();
|
|
#if DBG_MAX_REG_NUM > 0
|
|
int i;
|
|
char *rname;
|
|
int rsize;
|
|
u64 reg64;
|
|
u32 reg32;
|
|
u16 reg16;
|
|
u8 reg8;
|
|
|
|
if (len)
|
|
return len;
|
|
|
|
for (i = 0; i < DBG_MAX_REG_NUM; i++) {
|
|
rsize = dbg_reg_def[i].size * 2;
|
|
if (rsize > 16)
|
|
rsize = 2;
|
|
if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) {
|
|
len = 0;
|
|
kdb_printf("\n");
|
|
}
|
|
if (len)
|
|
len += kdb_printf(" ");
|
|
switch(dbg_reg_def[i].size * 8) {
|
|
case 8:
|
|
rname = dbg_get_reg(i, ®8, kdb_current_regs);
|
|
if (!rname)
|
|
break;
|
|
len += kdb_printf("%s: %02x", rname, reg8);
|
|
break;
|
|
case 16:
|
|
rname = dbg_get_reg(i, ®16, kdb_current_regs);
|
|
if (!rname)
|
|
break;
|
|
len += kdb_printf("%s: %04x", rname, reg16);
|
|
break;
|
|
case 32:
|
|
rname = dbg_get_reg(i, ®32, kdb_current_regs);
|
|
if (!rname)
|
|
break;
|
|
len += kdb_printf("%s: %08x", rname, reg32);
|
|
break;
|
|
case 64:
|
|
rname = dbg_get_reg(i, ®64, kdb_current_regs);
|
|
if (!rname)
|
|
break;
|
|
len += kdb_printf("%s: %016llx", rname, reg64);
|
|
break;
|
|
default:
|
|
len += kdb_printf("%s: ??", dbg_reg_def[i].name);
|
|
}
|
|
}
|
|
kdb_printf("\n");
|
|
#else
|
|
if (len)
|
|
return len;
|
|
|
|
kdb_dumpregs(kdb_current_regs);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_rm - This function implements the 'rm' (register modify) command.
|
|
* rm register-name new-contents
|
|
* Remarks:
|
|
* Allows register modification with the same restrictions as gdb
|
|
*/
|
|
static int kdb_rm(int argc, const char **argv)
|
|
{
|
|
#if DBG_MAX_REG_NUM > 0
|
|
int diag;
|
|
const char *rname;
|
|
int i;
|
|
u64 reg64;
|
|
u32 reg32;
|
|
u16 reg16;
|
|
u8 reg8;
|
|
|
|
if (argc != 2)
|
|
return KDB_ARGCOUNT;
|
|
/*
|
|
* Allow presence or absence of leading '%' symbol.
|
|
*/
|
|
rname = argv[1];
|
|
if (*rname == '%')
|
|
rname++;
|
|
|
|
diag = kdbgetu64arg(argv[2], ®64);
|
|
if (diag)
|
|
return diag;
|
|
|
|
diag = kdb_check_regs();
|
|
if (diag)
|
|
return diag;
|
|
|
|
diag = KDB_BADREG;
|
|
for (i = 0; i < DBG_MAX_REG_NUM; i++) {
|
|
if (strcmp(rname, dbg_reg_def[i].name) == 0) {
|
|
diag = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (!diag) {
|
|
switch(dbg_reg_def[i].size * 8) {
|
|
case 8:
|
|
reg8 = reg64;
|
|
dbg_set_reg(i, ®8, kdb_current_regs);
|
|
break;
|
|
case 16:
|
|
reg16 = reg64;
|
|
dbg_set_reg(i, ®16, kdb_current_regs);
|
|
break;
|
|
case 32:
|
|
reg32 = reg64;
|
|
dbg_set_reg(i, ®32, kdb_current_regs);
|
|
break;
|
|
case 64:
|
|
dbg_set_reg(i, ®64, kdb_current_regs);
|
|
break;
|
|
}
|
|
}
|
|
return diag;
|
|
#else
|
|
kdb_printf("ERROR: Register set currently not implemented\n");
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#if defined(CONFIG_MAGIC_SYSRQ)
|
|
/*
|
|
* kdb_sr - This function implements the 'sr' (SYSRQ key) command
|
|
* which interfaces to the soi-disant MAGIC SYSRQ functionality.
|
|
* sr <magic-sysrq-code>
|
|
*/
|
|
static int kdb_sr(int argc, const char **argv)
|
|
{
|
|
bool check_mask =
|
|
!kdb_check_flags(KDB_ENABLE_ALL, kdb_cmd_enabled, false);
|
|
|
|
if (argc != 1)
|
|
return KDB_ARGCOUNT;
|
|
|
|
kdb_trap_printk++;
|
|
__handle_sysrq(*argv[1], check_mask);
|
|
kdb_trap_printk--;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_MAGIC_SYSRQ */
|
|
|
|
/*
|
|
* kdb_ef - This function implements the 'regs' (display exception
|
|
* frame) command. This command takes an address and expects to
|
|
* find an exception frame at that address, formats and prints
|
|
* it.
|
|
* regs address-expression
|
|
* Remarks:
|
|
* Not done yet.
|
|
*/
|
|
static int kdb_ef(int argc, const char **argv)
|
|
{
|
|
int diag;
|
|
unsigned long addr;
|
|
long offset;
|
|
int nextarg;
|
|
|
|
if (argc != 1)
|
|
return KDB_ARGCOUNT;
|
|
|
|
nextarg = 1;
|
|
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL);
|
|
if (diag)
|
|
return diag;
|
|
show_regs((struct pt_regs *)addr);
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_MODULES)
|
|
/*
|
|
* kdb_lsmod - This function implements the 'lsmod' command. Lists
|
|
* currently loaded kernel modules.
|
|
* Mostly taken from userland lsmod.
|
|
*/
|
|
static int kdb_lsmod(int argc, const char **argv)
|
|
{
|
|
struct module *mod;
|
|
|
|
if (argc != 0)
|
|
return KDB_ARGCOUNT;
|
|
|
|
kdb_printf("Module Size modstruct Used by\n");
|
|
list_for_each_entry(mod, kdb_modules, list) {
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
|
|
kdb_printf("%-20s%8u 0x%px ", mod->name,
|
|
mod->core_layout.size, (void *)mod);
|
|
#ifdef CONFIG_MODULE_UNLOAD
|
|
kdb_printf("%4d ", module_refcount(mod));
|
|
#endif
|
|
if (mod->state == MODULE_STATE_GOING)
|
|
kdb_printf(" (Unloading)");
|
|
else if (mod->state == MODULE_STATE_COMING)
|
|
kdb_printf(" (Loading)");
|
|
else
|
|
kdb_printf(" (Live)");
|
|
kdb_printf(" 0x%px", mod->core_layout.base);
|
|
|
|
#ifdef CONFIG_MODULE_UNLOAD
|
|
{
|
|
struct module_use *use;
|
|
kdb_printf(" [ ");
|
|
list_for_each_entry(use, &mod->source_list,
|
|
source_list)
|
|
kdb_printf("%s ", use->target->name);
|
|
kdb_printf("]\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_MODULES */
|
|
|
|
/*
|
|
* kdb_env - This function implements the 'env' command. Display the
|
|
* current environment variables.
|
|
*/
|
|
|
|
static int kdb_env(int argc, const char **argv)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < __nenv; i++) {
|
|
if (__env[i])
|
|
kdb_printf("%s\n", __env[i]);
|
|
}
|
|
|
|
if (KDB_DEBUG(MASK))
|
|
kdb_printf("KDBFLAGS=0x%x\n", kdb_flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_PRINTK
|
|
/*
|
|
* kdb_dmesg - This function implements the 'dmesg' command to display
|
|
* the contents of the syslog buffer.
|
|
* dmesg [lines] [adjust]
|
|
*/
|
|
static int kdb_dmesg(int argc, const char **argv)
|
|
{
|
|
int diag;
|
|
int logging;
|
|
int lines = 0;
|
|
int adjust = 0;
|
|
int n = 0;
|
|
int skip = 0;
|
|
struct kmsg_dumper dumper = { .active = 1 };
|
|
size_t len;
|
|
char buf[201];
|
|
|
|
if (argc > 2)
|
|
return KDB_ARGCOUNT;
|
|
if (argc) {
|
|
char *cp;
|
|
lines = simple_strtol(argv[1], &cp, 0);
|
|
if (*cp)
|
|
lines = 0;
|
|
if (argc > 1) {
|
|
adjust = simple_strtoul(argv[2], &cp, 0);
|
|
if (*cp || adjust < 0)
|
|
adjust = 0;
|
|
}
|
|
}
|
|
|
|
/* disable LOGGING if set */
|
|
diag = kdbgetintenv("LOGGING", &logging);
|
|
if (!diag && logging) {
|
|
const char *setargs[] = { "set", "LOGGING", "0" };
|
|
kdb_set(2, setargs);
|
|
}
|
|
|
|
kmsg_dump_rewind_nolock(&dumper);
|
|
while (kmsg_dump_get_line_nolock(&dumper, 1, NULL, 0, NULL))
|
|
n++;
|
|
|
|
if (lines < 0) {
|
|
if (adjust >= n)
|
|
kdb_printf("buffer only contains %d lines, nothing "
|
|
"printed\n", n);
|
|
else if (adjust - lines >= n)
|
|
kdb_printf("buffer only contains %d lines, last %d "
|
|
"lines printed\n", n, n - adjust);
|
|
skip = adjust;
|
|
lines = abs(lines);
|
|
} else if (lines > 0) {
|
|
skip = n - lines - adjust;
|
|
lines = abs(lines);
|
|
if (adjust >= n) {
|
|
kdb_printf("buffer only contains %d lines, "
|
|
"nothing printed\n", n);
|
|
skip = n;
|
|
} else if (skip < 0) {
|
|
lines += skip;
|
|
skip = 0;
|
|
kdb_printf("buffer only contains %d lines, first "
|
|
"%d lines printed\n", n, lines);
|
|
}
|
|
} else {
|
|
lines = n;
|
|
}
|
|
|
|
if (skip >= n || skip < 0)
|
|
return 0;
|
|
|
|
kmsg_dump_rewind_nolock(&dumper);
|
|
while (kmsg_dump_get_line_nolock(&dumper, 1, buf, sizeof(buf), &len)) {
|
|
if (skip) {
|
|
skip--;
|
|
continue;
|
|
}
|
|
if (!lines--)
|
|
break;
|
|
if (KDB_FLAG(CMD_INTERRUPT))
|
|
return 0;
|
|
|
|
kdb_printf("%.*s\n", (int)len - 1, buf);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_PRINTK */
|
|
|
|
/* Make sure we balance enable/disable calls, must disable first. */
|
|
static atomic_t kdb_nmi_disabled;
|
|
|
|
static int kdb_disable_nmi(int argc, const char *argv[])
|
|
{
|
|
if (atomic_read(&kdb_nmi_disabled))
|
|
return 0;
|
|
atomic_set(&kdb_nmi_disabled, 1);
|
|
arch_kgdb_ops.enable_nmi(0);
|
|
return 0;
|
|
}
|
|
|
|
static int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
|
|
{
|
|
if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
|
|
return -EINVAL;
|
|
arch_kgdb_ops.enable_nmi(1);
|
|
return 0;
|
|
}
|
|
|
|
static const struct kernel_param_ops kdb_param_ops_enable_nmi = {
|
|
.set = kdb_param_enable_nmi,
|
|
};
|
|
module_param_cb(enable_nmi, &kdb_param_ops_enable_nmi, NULL, 0600);
|
|
|
|
/*
|
|
* kdb_cpu - This function implements the 'cpu' command.
|
|
* cpu [<cpunum>]
|
|
* Returns:
|
|
* KDB_CMD_CPU for success, a kdb diagnostic if error
|
|
*/
|
|
static void kdb_cpu_status(void)
|
|
{
|
|
int i, start_cpu, first_print = 1;
|
|
char state, prev_state = '?';
|
|
|
|
kdb_printf("Currently on cpu %d\n", raw_smp_processor_id());
|
|
kdb_printf("Available cpus: ");
|
|
for (start_cpu = -1, i = 0; i < NR_CPUS; i++) {
|
|
if (!cpu_online(i)) {
|
|
state = 'F'; /* cpu is offline */
|
|
} else if (!kgdb_info[i].enter_kgdb) {
|
|
state = 'D'; /* cpu is online but unresponsive */
|
|
} else {
|
|
state = ' '; /* cpu is responding to kdb */
|
|
if (kdb_task_state_char(KDB_TSK(i)) == 'I')
|
|
state = 'I'; /* idle task */
|
|
}
|
|
if (state != prev_state) {
|
|
if (prev_state != '?') {
|
|
if (!first_print)
|
|
kdb_printf(", ");
|
|
first_print = 0;
|
|
kdb_printf("%d", start_cpu);
|
|
if (start_cpu < i-1)
|
|
kdb_printf("-%d", i-1);
|
|
if (prev_state != ' ')
|
|
kdb_printf("(%c)", prev_state);
|
|
}
|
|
prev_state = state;
|
|
start_cpu = i;
|
|
}
|
|
}
|
|
/* print the trailing cpus, ignoring them if they are all offline */
|
|
if (prev_state != 'F') {
|
|
if (!first_print)
|
|
kdb_printf(", ");
|
|
kdb_printf("%d", start_cpu);
|
|
if (start_cpu < i-1)
|
|
kdb_printf("-%d", i-1);
|
|
if (prev_state != ' ')
|
|
kdb_printf("(%c)", prev_state);
|
|
}
|
|
kdb_printf("\n");
|
|
}
|
|
|
|
static int kdb_cpu(int argc, const char **argv)
|
|
{
|
|
unsigned long cpunum;
|
|
int diag;
|
|
|
|
if (argc == 0) {
|
|
kdb_cpu_status();
|
|
return 0;
|
|
}
|
|
|
|
if (argc != 1)
|
|
return KDB_ARGCOUNT;
|
|
|
|
diag = kdbgetularg(argv[1], &cpunum);
|
|
if (diag)
|
|
return diag;
|
|
|
|
/*
|
|
* Validate cpunum
|
|
*/
|
|
if ((cpunum >= CONFIG_NR_CPUS) || !kgdb_info[cpunum].enter_kgdb)
|
|
return KDB_BADCPUNUM;
|
|
|
|
dbg_switch_cpu = cpunum;
|
|
|
|
/*
|
|
* Switch to other cpu
|
|
*/
|
|
return KDB_CMD_CPU;
|
|
}
|
|
|
|
/* The user may not realize that ps/bta with no parameters does not print idle
|
|
* or sleeping system daemon processes, so tell them how many were suppressed.
|
|
*/
|
|
void kdb_ps_suppressed(void)
|
|
{
|
|
int idle = 0, daemon = 0;
|
|
unsigned long mask_I = kdb_task_state_string("I"),
|
|
mask_M = kdb_task_state_string("M");
|
|
unsigned long cpu;
|
|
const struct task_struct *p, *g;
|
|
for_each_online_cpu(cpu) {
|
|
p = kdb_curr_task(cpu);
|
|
if (kdb_task_state(p, mask_I))
|
|
++idle;
|
|
}
|
|
kdb_do_each_thread(g, p) {
|
|
if (kdb_task_state(p, mask_M))
|
|
++daemon;
|
|
} kdb_while_each_thread(g, p);
|
|
if (idle || daemon) {
|
|
if (idle)
|
|
kdb_printf("%d idle process%s (state I)%s\n",
|
|
idle, idle == 1 ? "" : "es",
|
|
daemon ? " and " : "");
|
|
if (daemon)
|
|
kdb_printf("%d sleeping system daemon (state M) "
|
|
"process%s", daemon,
|
|
daemon == 1 ? "" : "es");
|
|
kdb_printf(" suppressed,\nuse 'ps A' to see all.\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* kdb_ps - This function implements the 'ps' command which shows a
|
|
* list of the active processes.
|
|
* ps [DRSTCZEUIMA] All processes, optionally filtered by state
|
|
*/
|
|
void kdb_ps1(const struct task_struct *p)
|
|
{
|
|
int cpu;
|
|
unsigned long tmp;
|
|
|
|
if (!p || probe_kernel_read(&tmp, (char *)p, sizeof(unsigned long)))
|
|
return;
|
|
|
|
cpu = kdb_process_cpu(p);
|
|
kdb_printf("0x%px %8d %8d %d %4d %c 0x%px %c%s\n",
|
|
(void *)p, p->pid, p->parent->pid,
|
|
kdb_task_has_cpu(p), kdb_process_cpu(p),
|
|
kdb_task_state_char(p),
|
|
(void *)(&p->thread),
|
|
p == kdb_curr_task(raw_smp_processor_id()) ? '*' : ' ',
|
|
p->comm);
|
|
if (kdb_task_has_cpu(p)) {
|
|
if (!KDB_TSK(cpu)) {
|
|
kdb_printf(" Error: no saved data for this cpu\n");
|
|
} else {
|
|
if (KDB_TSK(cpu) != p)
|
|
kdb_printf(" Error: does not match running "
|
|
"process table (0x%px)\n", KDB_TSK(cpu));
|
|
}
|
|
}
|
|
}
|
|
|
|
static int kdb_ps(int argc, const char **argv)
|
|
{
|
|
struct task_struct *g, *p;
|
|
unsigned long mask, cpu;
|
|
|
|
if (argc == 0)
|
|
kdb_ps_suppressed();
|
|
kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n",
|
|
(int)(2*sizeof(void *))+2, "Task Addr",
|
|
(int)(2*sizeof(void *))+2, "Thread");
|
|
mask = kdb_task_state_string(argc ? argv[1] : NULL);
|
|
/* Run the active tasks first */
|
|
for_each_online_cpu(cpu) {
|
|
if (KDB_FLAG(CMD_INTERRUPT))
|
|
return 0;
|
|
p = kdb_curr_task(cpu);
|
|
if (kdb_task_state(p, mask))
|
|
kdb_ps1(p);
|
|
}
|
|
kdb_printf("\n");
|
|
/* Now the real tasks */
|
|
kdb_do_each_thread(g, p) {
|
|
if (KDB_FLAG(CMD_INTERRUPT))
|
|
return 0;
|
|
if (kdb_task_state(p, mask))
|
|
kdb_ps1(p);
|
|
} kdb_while_each_thread(g, p);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_pid - This function implements the 'pid' command which switches
|
|
* the currently active process.
|
|
* pid [<pid> | R]
|
|
*/
|
|
static int kdb_pid(int argc, const char **argv)
|
|
{
|
|
struct task_struct *p;
|
|
unsigned long val;
|
|
int diag;
|
|
|
|
if (argc > 1)
|
|
return KDB_ARGCOUNT;
|
|
|
|
if (argc) {
|
|
if (strcmp(argv[1], "R") == 0) {
|
|
p = KDB_TSK(kdb_initial_cpu);
|
|
} else {
|
|
diag = kdbgetularg(argv[1], &val);
|
|
if (diag)
|
|
return KDB_BADINT;
|
|
|
|
p = find_task_by_pid_ns((pid_t)val, &init_pid_ns);
|
|
if (!p) {
|
|
kdb_printf("No task with pid=%d\n", (pid_t)val);
|
|
return 0;
|
|
}
|
|
}
|
|
kdb_set_current_task(p);
|
|
}
|
|
kdb_printf("KDB current process is %s(pid=%d)\n",
|
|
kdb_current_task->comm,
|
|
kdb_current_task->pid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int kdb_kgdb(int argc, const char **argv)
|
|
{
|
|
return KDB_CMD_KGDB;
|
|
}
|
|
|
|
/*
|
|
* kdb_help - This function implements the 'help' and '?' commands.
|
|
*/
|
|
static int kdb_help(int argc, const char **argv)
|
|
{
|
|
kdbtab_t *kt;
|
|
int i;
|
|
|
|
kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description");
|
|
kdb_printf("-----------------------------"
|
|
"-----------------------------\n");
|
|
for_each_kdbcmd(kt, i) {
|
|
char *space = "";
|
|
if (KDB_FLAG(CMD_INTERRUPT))
|
|
return 0;
|
|
if (!kt->cmd_name)
|
|
continue;
|
|
if (!kdb_check_flags(kt->cmd_flags, kdb_cmd_enabled, true))
|
|
continue;
|
|
if (strlen(kt->cmd_usage) > 20)
|
|
space = "\n ";
|
|
kdb_printf("%-15.15s %-20s%s%s\n", kt->cmd_name,
|
|
kt->cmd_usage, space, kt->cmd_help);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_kill - This function implements the 'kill' commands.
|
|
*/
|
|
static int kdb_kill(int argc, const char **argv)
|
|
{
|
|
long sig, pid;
|
|
char *endp;
|
|
struct task_struct *p;
|
|
|
|
if (argc != 2)
|
|
return KDB_ARGCOUNT;
|
|
|
|
sig = simple_strtol(argv[1], &endp, 0);
|
|
if (*endp)
|
|
return KDB_BADINT;
|
|
if ((sig >= 0) || !valid_signal(-sig)) {
|
|
kdb_printf("Invalid signal parameter.<-signal>\n");
|
|
return 0;
|
|
}
|
|
sig = -sig;
|
|
|
|
pid = simple_strtol(argv[2], &endp, 0);
|
|
if (*endp)
|
|
return KDB_BADINT;
|
|
if (pid <= 0) {
|
|
kdb_printf("Process ID must be large than 0.\n");
|
|
return 0;
|
|
}
|
|
|
|
/* Find the process. */
|
|
p = find_task_by_pid_ns(pid, &init_pid_ns);
|
|
if (!p) {
|
|
kdb_printf("The specified process isn't found.\n");
|
|
return 0;
|
|
}
|
|
p = p->group_leader;
|
|
kdb_send_sig(p, sig);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Most of this code has been lifted from kernel/timer.c::sys_sysinfo().
|
|
* I cannot call that code directly from kdb, it has an unconditional
|
|
* cli()/sti() and calls routines that take locks which can stop the debugger.
|
|
*/
|
|
static void kdb_sysinfo(struct sysinfo *val)
|
|
{
|
|
u64 uptime = ktime_get_mono_fast_ns();
|
|
|
|
memset(val, 0, sizeof(*val));
|
|
val->uptime = div_u64(uptime, NSEC_PER_SEC);
|
|
val->loads[0] = avenrun[0];
|
|
val->loads[1] = avenrun[1];
|
|
val->loads[2] = avenrun[2];
|
|
val->procs = nr_threads-1;
|
|
si_meminfo(val);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* kdb_summary - This function implements the 'summary' command.
|
|
*/
|
|
static int kdb_summary(int argc, const char **argv)
|
|
{
|
|
time64_t now;
|
|
struct tm tm;
|
|
struct sysinfo val;
|
|
|
|
if (argc)
|
|
return KDB_ARGCOUNT;
|
|
|
|
kdb_printf("sysname %s\n", init_uts_ns.name.sysname);
|
|
kdb_printf("release %s\n", init_uts_ns.name.release);
|
|
kdb_printf("version %s\n", init_uts_ns.name.version);
|
|
kdb_printf("machine %s\n", init_uts_ns.name.machine);
|
|
kdb_printf("nodename %s\n", init_uts_ns.name.nodename);
|
|
kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
|
|
kdb_printf("ccversion %s\n", __stringify(CCVERSION));
|
|
|
|
now = __ktime_get_real_seconds();
|
|
time64_to_tm(now, 0, &tm);
|
|
kdb_printf("date %04ld-%02d-%02d %02d:%02d:%02d "
|
|
"tz_minuteswest %d\n",
|
|
1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
|
sys_tz.tz_minuteswest);
|
|
|
|
kdb_sysinfo(&val);
|
|
kdb_printf("uptime ");
|
|
if (val.uptime > (24*60*60)) {
|
|
int days = val.uptime / (24*60*60);
|
|
val.uptime %= (24*60*60);
|
|
kdb_printf("%d day%s ", days, days == 1 ? "" : "s");
|
|
}
|
|
kdb_printf("%02ld:%02ld\n", val.uptime/(60*60), (val.uptime/60)%60);
|
|
|
|
kdb_printf("load avg %ld.%02ld %ld.%02ld %ld.%02ld\n",
|
|
LOAD_INT(val.loads[0]), LOAD_FRAC(val.loads[0]),
|
|
LOAD_INT(val.loads[1]), LOAD_FRAC(val.loads[1]),
|
|
LOAD_INT(val.loads[2]), LOAD_FRAC(val.loads[2]));
|
|
|
|
/* Display in kilobytes */
|
|
#define K(x) ((x) << (PAGE_SHIFT - 10))
|
|
kdb_printf("\nMemTotal: %8lu kB\nMemFree: %8lu kB\n"
|
|
"Buffers: %8lu kB\n",
|
|
K(val.totalram), K(val.freeram), K(val.bufferram));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_per_cpu - This function implements the 'per_cpu' command.
|
|
*/
|
|
static int kdb_per_cpu(int argc, const char **argv)
|
|
{
|
|
char fmtstr[64];
|
|
int cpu, diag, nextarg = 1;
|
|
unsigned long addr, symaddr, val, bytesperword = 0, whichcpu = ~0UL;
|
|
|
|
if (argc < 1 || argc > 3)
|
|
return KDB_ARGCOUNT;
|
|
|
|
diag = kdbgetaddrarg(argc, argv, &nextarg, &symaddr, NULL, NULL);
|
|
if (diag)
|
|
return diag;
|
|
|
|
if (argc >= 2) {
|
|
diag = kdbgetularg(argv[2], &bytesperword);
|
|
if (diag)
|
|
return diag;
|
|
}
|
|
if (!bytesperword)
|
|
bytesperword = KDB_WORD_SIZE;
|
|
else if (bytesperword > KDB_WORD_SIZE)
|
|
return KDB_BADWIDTH;
|
|
sprintf(fmtstr, "%%0%dlx ", (int)(2*bytesperword));
|
|
if (argc >= 3) {
|
|
diag = kdbgetularg(argv[3], &whichcpu);
|
|
if (diag)
|
|
return diag;
|
|
if (whichcpu >= nr_cpu_ids || !cpu_online(whichcpu)) {
|
|
kdb_printf("cpu %ld is not online\n", whichcpu);
|
|
return KDB_BADCPUNUM;
|
|
}
|
|
}
|
|
|
|
/* Most architectures use __per_cpu_offset[cpu], some use
|
|
* __per_cpu_offset(cpu), smp has no __per_cpu_offset.
|
|
*/
|
|
#ifdef __per_cpu_offset
|
|
#define KDB_PCU(cpu) __per_cpu_offset(cpu)
|
|
#else
|
|
#ifdef CONFIG_SMP
|
|
#define KDB_PCU(cpu) __per_cpu_offset[cpu]
|
|
#else
|
|
#define KDB_PCU(cpu) 0
|
|
#endif
|
|
#endif
|
|
for_each_online_cpu(cpu) {
|
|
if (KDB_FLAG(CMD_INTERRUPT))
|
|
return 0;
|
|
|
|
if (whichcpu != ~0UL && whichcpu != cpu)
|
|
continue;
|
|
addr = symaddr + KDB_PCU(cpu);
|
|
diag = kdb_getword(&val, addr, bytesperword);
|
|
if (diag) {
|
|
kdb_printf("%5d " kdb_bfd_vma_fmt0 " - unable to "
|
|
"read, diag=%d\n", cpu, addr, diag);
|
|
continue;
|
|
}
|
|
kdb_printf("%5d ", cpu);
|
|
kdb_md_line(fmtstr, addr,
|
|
bytesperword == KDB_WORD_SIZE,
|
|
1, bytesperword, 1, 1, 0);
|
|
}
|
|
#undef KDB_PCU
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* display help for the use of cmd | grep pattern
|
|
*/
|
|
static int kdb_grep_help(int argc, const char **argv)
|
|
{
|
|
kdb_printf("Usage of cmd args | grep pattern:\n");
|
|
kdb_printf(" Any command's output may be filtered through an ");
|
|
kdb_printf("emulated 'pipe'.\n");
|
|
kdb_printf(" 'grep' is just a key word.\n");
|
|
kdb_printf(" The pattern may include a very limited set of "
|
|
"metacharacters:\n");
|
|
kdb_printf(" pattern or ^pattern or pattern$ or ^pattern$\n");
|
|
kdb_printf(" And if there are spaces in the pattern, you may "
|
|
"quote it:\n");
|
|
kdb_printf(" \"pat tern\" or \"^pat tern\" or \"pat tern$\""
|
|
" or \"^pat tern$\"\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* kdb_register_flags - This function is used to register a kernel
|
|
* debugger command.
|
|
* Inputs:
|
|
* cmd Command name
|
|
* func Function to execute the command
|
|
* usage A simple usage string showing arguments
|
|
* help A simple help string describing command
|
|
* repeat Does the command auto repeat on enter?
|
|
* Returns:
|
|
* zero for success, one if a duplicate command.
|
|
*/
|
|
#define kdb_command_extend 50 /* arbitrary */
|
|
int kdb_register_flags(char *cmd,
|
|
kdb_func_t func,
|
|
char *usage,
|
|
char *help,
|
|
short minlen,
|
|
kdb_cmdflags_t flags)
|
|
{
|
|
int i;
|
|
kdbtab_t *kp;
|
|
|
|
/*
|
|
* Brute force method to determine duplicates
|
|
*/
|
|
for_each_kdbcmd(kp, i) {
|
|
if (kp->cmd_name && (strcmp(kp->cmd_name, cmd) == 0)) {
|
|
kdb_printf("Duplicate kdb command registered: "
|
|
"%s, func %px help %s\n", cmd, func, help);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Insert command into first available location in table
|
|
*/
|
|
for_each_kdbcmd(kp, i) {
|
|
if (kp->cmd_name == NULL)
|
|
break;
|
|
}
|
|
|
|
if (i >= kdb_max_commands) {
|
|
kdbtab_t *new = kmalloc_array(kdb_max_commands -
|
|
KDB_BASE_CMD_MAX +
|
|
kdb_command_extend,
|
|
sizeof(*new),
|
|
GFP_KDB);
|
|
if (!new) {
|
|
kdb_printf("Could not allocate new kdb_command "
|
|
"table\n");
|
|
return 1;
|
|
}
|
|
if (kdb_commands) {
|
|
memcpy(new, kdb_commands,
|
|
(kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new));
|
|
kfree(kdb_commands);
|
|
}
|
|
memset(new + kdb_max_commands - KDB_BASE_CMD_MAX, 0,
|
|
kdb_command_extend * sizeof(*new));
|
|
kdb_commands = new;
|
|
kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX;
|
|
kdb_max_commands += kdb_command_extend;
|
|
}
|
|
|
|
kp->cmd_name = cmd;
|
|
kp->cmd_func = func;
|
|
kp->cmd_usage = usage;
|
|
kp->cmd_help = help;
|
|
kp->cmd_minlen = minlen;
|
|
kp->cmd_flags = flags;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(kdb_register_flags);
|
|
|
|
|
|
/*
|
|
* kdb_register - Compatibility register function for commands that do
|
|
* not need to specify a repeat state. Equivalent to
|
|
* kdb_register_flags with flags set to 0.
|
|
* Inputs:
|
|
* cmd Command name
|
|
* func Function to execute the command
|
|
* usage A simple usage string showing arguments
|
|
* help A simple help string describing command
|
|
* Returns:
|
|
* zero for success, one if a duplicate command.
|
|
*/
|
|
int kdb_register(char *cmd,
|
|
kdb_func_t func,
|
|
char *usage,
|
|
char *help,
|
|
short minlen)
|
|
{
|
|
return kdb_register_flags(cmd, func, usage, help, minlen, 0);
|
|
}
|
|
EXPORT_SYMBOL_GPL(kdb_register);
|
|
|
|
/*
|
|
* kdb_unregister - This function is used to unregister a kernel
|
|
* debugger command. It is generally called when a module which
|
|
* implements kdb commands is unloaded.
|
|
* Inputs:
|
|
* cmd Command name
|
|
* Returns:
|
|
* zero for success, one command not registered.
|
|
*/
|
|
int kdb_unregister(char *cmd)
|
|
{
|
|
int i;
|
|
kdbtab_t *kp;
|
|
|
|
/*
|
|
* find the command.
|
|
*/
|
|
for_each_kdbcmd(kp, i) {
|
|
if (kp->cmd_name && (strcmp(kp->cmd_name, cmd) == 0)) {
|
|
kp->cmd_name = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Couldn't find it. */
|
|
return 1;
|
|
}
|
|
EXPORT_SYMBOL_GPL(kdb_unregister);
|
|
|
|
/* Initialize the kdb command table. */
|
|
static void __init kdb_inittab(void)
|
|
{
|
|
int i;
|
|
kdbtab_t *kp;
|
|
|
|
for_each_kdbcmd(kp, i)
|
|
kp->cmd_name = NULL;
|
|
|
|
kdb_register_flags("md", kdb_md, "<vaddr>",
|
|
"Display Memory Contents, also mdWcN, e.g. md8c1", 1,
|
|
KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
|
|
kdb_register_flags("mdr", kdb_md, "<vaddr> <bytes>",
|
|
"Display Raw Memory", 0,
|
|
KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
|
|
kdb_register_flags("mdp", kdb_md, "<paddr> <bytes>",
|
|
"Display Physical Memory", 0,
|
|
KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
|
|
kdb_register_flags("mds", kdb_md, "<vaddr>",
|
|
"Display Memory Symbolically", 0,
|
|
KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
|
|
kdb_register_flags("mm", kdb_mm, "<vaddr> <contents>",
|
|
"Modify Memory Contents", 0,
|
|
KDB_ENABLE_MEM_WRITE | KDB_REPEAT_NO_ARGS);
|
|
kdb_register_flags("go", kdb_go, "[<vaddr>]",
|
|
"Continue Execution", 1,
|
|
KDB_ENABLE_REG_WRITE | KDB_ENABLE_ALWAYS_SAFE_NO_ARGS);
|
|
kdb_register_flags("rd", kdb_rd, "",
|
|
"Display Registers", 0,
|
|
KDB_ENABLE_REG_READ);
|
|
kdb_register_flags("rm", kdb_rm, "<reg> <contents>",
|
|
"Modify Registers", 0,
|
|
KDB_ENABLE_REG_WRITE);
|
|
kdb_register_flags("ef", kdb_ef, "<vaddr>",
|
|
"Display exception frame", 0,
|
|
KDB_ENABLE_MEM_READ);
|
|
kdb_register_flags("bt", kdb_bt, "[<vaddr>]",
|
|
"Stack traceback", 1,
|
|
KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS);
|
|
kdb_register_flags("btp", kdb_bt, "<pid>",
|
|
"Display stack for process <pid>", 0,
|
|
KDB_ENABLE_INSPECT);
|
|
kdb_register_flags("bta", kdb_bt, "[D|R|S|T|C|Z|E|U|I|M|A]",
|
|
"Backtrace all processes matching state flag", 0,
|
|
KDB_ENABLE_INSPECT);
|
|
kdb_register_flags("btc", kdb_bt, "",
|
|
"Backtrace current process on each cpu", 0,
|
|
KDB_ENABLE_INSPECT);
|
|
kdb_register_flags("btt", kdb_bt, "<vaddr>",
|
|
"Backtrace process given its struct task address", 0,
|
|
KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS);
|
|
kdb_register_flags("env", kdb_env, "",
|
|
"Show environment variables", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
kdb_register_flags("set", kdb_set, "",
|
|
"Set environment variables", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
kdb_register_flags("help", kdb_help, "",
|
|
"Display Help Message", 1,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
kdb_register_flags("?", kdb_help, "",
|
|
"Display Help Message", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
kdb_register_flags("cpu", kdb_cpu, "<cpunum>",
|
|
"Switch to new cpu", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE_NO_ARGS);
|
|
kdb_register_flags("kgdb", kdb_kgdb, "",
|
|
"Enter kgdb mode", 0, 0);
|
|
kdb_register_flags("ps", kdb_ps, "[<flags>|A]",
|
|
"Display active task list", 0,
|
|
KDB_ENABLE_INSPECT);
|
|
kdb_register_flags("pid", kdb_pid, "<pidnum>",
|
|
"Switch to another task", 0,
|
|
KDB_ENABLE_INSPECT);
|
|
kdb_register_flags("reboot", kdb_reboot, "",
|
|
"Reboot the machine immediately", 0,
|
|
KDB_ENABLE_REBOOT);
|
|
#if defined(CONFIG_MODULES)
|
|
kdb_register_flags("lsmod", kdb_lsmod, "",
|
|
"List loaded kernel modules", 0,
|
|
KDB_ENABLE_INSPECT);
|
|
#endif
|
|
#if defined(CONFIG_MAGIC_SYSRQ)
|
|
kdb_register_flags("sr", kdb_sr, "<key>",
|
|
"Magic SysRq key", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
#endif
|
|
#if defined(CONFIG_PRINTK)
|
|
kdb_register_flags("dmesg", kdb_dmesg, "[lines]",
|
|
"Display syslog buffer", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
#endif
|
|
if (arch_kgdb_ops.enable_nmi) {
|
|
kdb_register_flags("disable_nmi", kdb_disable_nmi, "",
|
|
"Disable NMI entry to KDB", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
}
|
|
kdb_register_flags("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
|
|
"Define a set of commands, down to endefcmd", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
kdb_register_flags("kill", kdb_kill, "<-signal> <pid>",
|
|
"Send a signal to a process", 0,
|
|
KDB_ENABLE_SIGNAL);
|
|
kdb_register_flags("summary", kdb_summary, "",
|
|
"Summarize the system", 4,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
kdb_register_flags("per_cpu", kdb_per_cpu, "<sym> [<bytes>] [<cpu>]",
|
|
"Display per_cpu variables", 3,
|
|
KDB_ENABLE_MEM_READ);
|
|
kdb_register_flags("grephelp", kdb_grep_help, "",
|
|
"Display help on | grep", 0,
|
|
KDB_ENABLE_ALWAYS_SAFE);
|
|
}
|
|
|
|
/* Execute any commands defined in kdb_cmds. */
|
|
static void __init kdb_cmd_init(void)
|
|
{
|
|
int i, diag;
|
|
for (i = 0; kdb_cmds[i]; ++i) {
|
|
diag = kdb_parse(kdb_cmds[i]);
|
|
if (diag)
|
|
kdb_printf("kdb command %s failed, kdb diag %d\n",
|
|
kdb_cmds[i], diag);
|
|
}
|
|
if (defcmd_in_progress) {
|
|
kdb_printf("Incomplete 'defcmd' set, forcing endefcmd\n");
|
|
kdb_parse("endefcmd");
|
|
}
|
|
}
|
|
|
|
/* Initialize kdb_printf, breakpoint tables and kdb state */
|
|
void __init kdb_init(int lvl)
|
|
{
|
|
static int kdb_init_lvl = KDB_NOT_INITIALIZED;
|
|
int i;
|
|
|
|
if (kdb_init_lvl == KDB_INIT_FULL || lvl <= kdb_init_lvl)
|
|
return;
|
|
for (i = kdb_init_lvl; i < lvl; i++) {
|
|
switch (i) {
|
|
case KDB_NOT_INITIALIZED:
|
|
kdb_inittab(); /* Initialize Command Table */
|
|
kdb_initbptab(); /* Initialize Breakpoints */
|
|
break;
|
|
case KDB_INIT_EARLY:
|
|
kdb_cmd_init(); /* Build kdb_cmds tables */
|
|
break;
|
|
}
|
|
}
|
|
kdb_init_lvl = lvl;
|
|
}
|